rev148: Rework how the TPM internal clock works

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
This commit is contained in:
Stefan Berger 2018-07-12 12:08:22 -04:00 committed by Stefan Berger
parent 32ddd9845a
commit 6b444ad3ff
7 changed files with 192 additions and 82 deletions

View File

@ -176,6 +176,9 @@ AC_C_INLINE
AC_TYPE_SIZE_T
AC_CHECK_LIB(c, clock_gettime, LIBRT_LIBS="", LIBRT_LIBS="-lrt")
AC_SUBST([LIBRT_LIBS])
AC_ARG_ENABLE([hardening],
AS_HELP_STRING([--disable-hardening], [Disable hardening flags]))

View File

@ -169,7 +169,7 @@ noinst_LTLIBRARIES += libtpms_tpm2.la
libtpms_la_LIBADD += libtpms_tpm2.la
libtpms_tpm2_la_LIBADD =
libtpms_tpm2_la_LIBADD = $(LIBRT_LIBS)
libtpms_tpm2_la_CFLAGS = $(common_CFLAGS)

View File

@ -3,7 +3,7 @@
/* Used by the simulator to mimic a hardware clock */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* $Id: Clock.c 1047 2017-07-20 18:27:34Z kgoldman $ */
/* $Id: Clock.c 1259 2018-07-10 19:11:09Z kgoldman $ */
/* */
/* Licenses and Notices */
/* */
@ -55,7 +55,7 @@
/* arising in any way out of use or reliance upon this specification or any */
/* information herein. */
/* */
/* (c) Copyright IBM Corp. and others, 2016, 2017 */
/* (c) Copyright IBM Corp. and others, 2016 - 2018 */
/* */
/********************************************************************************/
@ -98,14 +98,22 @@ ClockGetTime(
/* ClockAdjustPostResume -- adjust time parameters post resume */
#include "Tpm.h"
void
ClockAdjustPostResume(UINT64 backthen)
ClockAdjustPostResume(UINT64 backthen, BOOL timesAreRealtime)
{
UINT64 now = ClockGetTime(CLOCK_REALTIME);
INT64 timediff = now - backthen;
g_time += timediff;
s_realTimePrevious += timediff;
s_tpmTime += timediff;
if (timesAreRealtime) {
/* g_time, s_realTimePrevious, s_tpmTime are all in real time */
s_suspendedElapsedTime = now;
s_hostMonotonicAdjustTime = -ClockGetTime(CLOCK_MONOTONIC);
/* s_lastSystemTime & s_lastReportTime need to be set as well */
s_lastSystemTime = now;
s_lastReportedTime = now;
} else if (timediff >= 0) {
s_suspendedElapsedTime += timediff;
}
}
/* C.3.3. Simulator Functions */
@ -121,11 +129,13 @@ _plat__TimerReset(
void
)
{
s_realTimePrevious = (clock_t) ClockGetTime(CLOCK_REALTIME); /* kgold, FIXME, something wrong here */
s_lastSystemTime = 0;
s_tpmTime = 0;
s_adjustRate = CLOCK_NOMINAL;
s_timerReset = TRUE;
s_timerStopped = TRUE;
s_hostMonotonicAdjustTime = 0; /* libtpms */
s_suspendedElapsedTime = 0; /* libtpms */
return;
}
/* C.3.3.3. _plat__TimerRestart() */
@ -139,11 +149,55 @@ _plat__TimerRestart(
s_timerStopped = TRUE;
return;
}
/* C.3.4. Functions Used by TPM */
/* C.3.4.1. Introduction */
/* These functions are called by the TPM code. They should be replaced by appropriated hardware
functions. */
/* C.3.4.2. _plat__TimerRead() */
clock_t debugTime;
/* C.3.4.2. _plat__Time() */
/* This is another, probably futile, attempt to define a portable function that will return a 64-bit
clock value that has mSec resolution. */
uint64_t
_plat__RealTime(
void
)
{
clock64_t time;
//#ifdef _MSC_VER kgold
#ifdef TPM_WINDOWS
#include <SYS/Timeb.h>
struct _timeb sysTime;
//
_ftime(&sysTime); /* kgold, mingw doesn't have _ftime_s */
time = (clock64_t)(sysTime.time) * 1000 + sysTime.millitm;
// set the time back by one hour if daylight savings
if(sysTime.dstflag)
time -= 1000 * 60 * 60; // mSec/sec * sec/min * min/hour = ms/hour
#else
// hopefully, this will work with most UNIX systems
struct timespec systime;
//
clock_gettime(CLOCK_MONOTONIC, &systime);
time = (clock64_t)systime.tv_sec * 1000 + (systime.tv_nsec / 1000000);
#endif
/* We have to make sure that this function returns monotonically increasing time
also when a vTPM has been suspended and the host has been rebooted.
Example:
- The vTPM is suspended at systime '5'
- The vTPM is resumed at systime '1' after a host reboot
-> we now need to add '4' to the time
Besides this we want to account for the time a vTPM was suspended.
If it was suspended for 10 time units, we need to add '10' here.
*/
time += s_hostMonotonicAdjustTime + s_suspendedElapsedTime;
return time;
}
/* C.3.4.3. _plat__TimerRead() */
/* This function provides access to the tick timer of the platform. The TPM code uses this value to
drive the TPM Clock. */
/* The tick timer is supposed to run when power is applied to the device. This timer should not be
@ -153,7 +207,6 @@ _plat__TimerRestart(
TPM as long as the time provided by the environment is not allowed to go backwards. If the time
provided by the system can go backwards during a power discontinuity, then the
_plat__Signal_PowerOn() should call _plat__TimerReset(). */
/* The code in this function should be replaced by a read of a hardware tick timer. */
LIB_EXPORT uint64_t
_plat__TimerRead(
void
@ -163,49 +216,50 @@ _plat__TimerRead(
#error "need a defintion for reading the hardware clock"
return HARDWARE_CLOCK
#else
#define BILLION 1000000000
#define MILLION 1000000
#define THOUSAND 1000
clock_t timeDiff;
uint64_t adjusted;
// Save the value previously read from the system clock
timeDiff = s_realTimePrevious;
// update with the current value of the system clock
s_realTimePrevious = ClockGetTime(CLOCK_REALTIME);
// In the place below when we "put back" the unused part of the timeDiff
// it is possible that we can put back more than we take out. That is, we could
// take out 1000 mSec, rate adjust it and put back 1001 mS. This means that
// on a subsequent call, time may not have caught up. Rather than trying
// to rate adjust this, just stop time. This only occurs in a simulation so
// time for more than one command being the same should not be an issue.
if(timeDiff >= s_realTimePrevious)
clock64_t timeDiff;
clock64_t adjustedTimeDiff;
clock64_t timeNow;
clock64_t readjustedTimeDiff;
// This produces a timeNow that is basically locked to the system clock.
timeNow = _plat__RealTime();
// if this hasn't been initialized, initialize it
if(s_lastSystemTime == 0)
{
s_realTimePrevious = timeDiff;
return s_tpmTime;
s_lastSystemTime = timeNow;
debugTime = clock();
s_lastReportedTime = 0;
s_realTimePrevious = 0;
}
// Compute the amount of time since the last call to the system clock
timeDiff = s_realTimePrevious - timeDiff;
// The system time can bounce around and that's OK as long as we don't allow
// time to go backwards. When the time does appear to go backwards, set
// lastSystemTime to be the new value and then update the reported time.
if(timeNow < s_lastReportedTime)
s_lastSystemTime = timeNow;
s_lastReportedTime = s_lastReportedTime + timeNow - s_lastSystemTime;
s_lastSystemTime = timeNow;
timeNow = s_lastReportedTime;
// The code above produces a timeNow that is similar to the value returned
// by Clock(). The difference is that timeNow does not max out, and it is
// at a ms. rate rather than at a CLOCKS_PER_SEC rate. The code below
// uses that value and does the rate adjustment on the time value.
// If there is no difference in time, then skip all the computations
if(s_realTimePrevious >= timeNow)
return s_tpmTime;
// Compute the amount of time since the last update of the system clock
timeDiff = timeNow - s_realTimePrevious;
// Do the time rate adjustment and conversion from CLOCKS_PER_SEC to mSec
#if 0
adjusted = (((uint64_t)timeDiff * (THOUSAND * CLOCK_NOMINAL))
/ ((uint64_t)s_adjustRate * CLOCKS_PER_SEC));
#endif
/* kgold */
adjusted = (timeDiff * (uint64_t)(s_adjustRate)) / (uint64_t)CLOCK_NOMINAL;
s_tpmTime += (clock_t)adjusted;
adjustedTimeDiff = (timeDiff * CLOCK_NOMINAL) / ((uint64_t)s_adjustRate);
// update the TPM time with the adjusted timeDiff
s_tpmTime += (clock64_t)adjustedTimeDiff;
// Might have some rounding error that would loose CLOCKS. See what is not
// being used. As mentioned above, this could result in putting back more than
// is taken out
#if 0
adjusted = (adjusted * ((uint64_t)s_adjustRate * CLOCKS_PER_SEC))
/ (THOUSAND * CLOCK_NOMINAL);
#endif
// If adjusted is not the same as timeDiff, then there is some rounding
// error that needs to be pushed back into the previous sample.
// NOTE: the following is so that the fact that everything is signed will not
// matter.
s_realTimePrevious = (clock_t)((int64_t)s_realTimePrevious - adjusted);
s_realTimePrevious += timeDiff;
// is taken out. Here, we are trying to recreate timeDiff.
readjustedTimeDiff = (adjustedTimeDiff * (uint64_t)s_adjustRate )
/ CLOCK_NOMINAL;
// adjusted is now converted back to being the amount we should advance the
// previous sampled time. It should always be less than or equal to timeDiff.
// That is, we could not have use more time than we started with.
s_realTimePrevious = s_realTimePrevious + readjustedTimeDiff;
#ifdef DEBUGGING_TIME
// Put this in so that TPM time will pass much faster than real time when
// doing debug.
@ -216,6 +270,8 @@ _plat__TimerRead(
return s_tpmTime;
#endif
}
/* C.3.4.3. _plat__TimerWasReset() */
/* This function is used to interrogate the flag indicating if the tick timer has been reset. */
/* If the resetFlag parameter is SET, then the flag will be CLEAR before the function returns. */

View File

@ -2627,7 +2627,7 @@ skip_future_versions:
return rc;
}
#define VOLATILE_STATE_VERSION 3
#define VOLATILE_STATE_VERSION 4
#define VOLATILE_STATE_MAGIC 0x45637889
UINT16
@ -2916,8 +2916,18 @@ VolatileState_Marshal(BYTE **buffer, INT32 *size)
written += TPM2B_Marshal(&pd.PPSeed.b, buffer, size);
written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size); /* v4 */
tmp_uint64 = ClockGetTime(CLOCK_MONOTONIC) + s_hostMonotonicAdjustTime;
written += UINT64_Marshal(&tmp_uint64, buffer, size);
written += UINT64_Marshal(&s_suspendedElapsedTime, buffer, size);
written += UINT64_Marshal(&s_lastSystemTime, buffer, size);
written += UINT64_Marshal(&s_lastReportedTime, buffer, size);
written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size); /* v5 */
/* future versions append below this line */
BLOCK_SKIP_WRITE_POP(size); /* v5 */
BLOCK_SKIP_WRITE_POP(size); /* v4 */
BLOCK_SKIP_WRITE_POP(size); /* v3 */
@ -2930,6 +2940,29 @@ VolatileState_Marshal(BYTE **buffer, INT32 *size)
return written;
}
TPM_RC
VolatileState_TailV4_Unmarshal(BYTE **buffer, INT32 *size)
{
TPM_RC rc = TPM_RC_SUCCESS;
UINT64 tmp_uint64;
if (rc == TPM_RC_SUCCESS) {
rc = UINT64_Unmarshal(&tmp_uint64, buffer, size);
s_hostMonotonicAdjustTime = tmp_uint64 - ClockGetTime(CLOCK_MONOTONIC);
}
if (rc == TPM_RC_SUCCESS) {
rc = UINT64_Unmarshal(&s_suspendedElapsedTime, buffer, size);
}
if (rc == TPM_RC_SUCCESS) {
rc = UINT64_Unmarshal(&s_lastSystemTime, buffer, size);
}
if (rc == TPM_RC_SUCCESS) {
rc = UINT64_Unmarshal(&s_lastReportedTime, buffer, size);
}
return rc;
}
TPM_RC
VolatileState_TailV3_Unmarshal(BYTE **buffer, INT32 *size)
{
@ -3374,9 +3407,15 @@ skip_hardware_clock:
"Volatile State", "version 3 or later");
rc = VolatileState_TailV3_Unmarshal(buffer, size);
BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
BLOCK_SKIP_READ(skip_future_versions, hdr.version >= 4, buffer, size,
"Volatile State", "version 4 or later");
/* future versions nest-append here */
if (rc == TPM_RC_SUCCESS) {
rc = VolatileState_TailV4_Unmarshal(buffer, size);
}
BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
"Volatile State", "version 5 or later");
/* future versions append here */
}
skip_future_versions:
@ -3395,7 +3434,10 @@ skip_future_versions:
}
if (rc == TPM_RC_SUCCESS) {
ClockAdjustPostResume(backthen);
BOOL timesAreRealtime = hdr.version <= 3;
/* Before Rev148 (header version <= 3), times were reported in
realtime; we need to account for this now */
ClockAdjustPostResume(backthen, timesAreRealtime);
}
return rc;
}

View File

@ -1,9 +1,9 @@
/********************************************************************************/
/* */
/* */
/* TPM variables that are not stack allocated */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* $Id: PlatformData.c 809 2016-11-16 18:31:54Z kgoldman $ */
/* $Id: PlatformData.c 1259 2018-07-10 19:11:09Z kgoldman $ */
/* */
/* Licenses and Notices */
/* */
@ -55,15 +55,15 @@
/* arising in any way out of use or reliance upon this specification or any */
/* information herein. */
/* */
/* (c) Copyright IBM Corp. and others, 2016 */
/* (c) Copyright IBM Corp. and others, 2016 - 2018 */
/* */
/********************************************************************************/
/* C.9 PlatformData.c */
/* C.9.1. Description */
/* C.10 PlatformData.c */
/* C.10.1. Description */
/* This file will instance the TPM variables that are not stack allocated. The descriptions for
these variables are in Global.h for this project. */
/* C.9.2. Includes */
/* C.10.2. Includes */
#include "Implementation.h"
#include "PlatformData.h"
/* From Cancel.c */
@ -73,9 +73,14 @@ unsigned int s_adjustRate;
BOOL s_timerReset;
BOOL s_timerStopped;
#ifndef HARDWARE_CLOCK
#include <time.h>
clock_t s_realTimePrevious;
clock_t s_tpmTime;
clock64_t s_realTimePrevious;
clock64_t s_tpmTime;
clock64_t s_lastSystemTime;
clock64_t s_lastReportedTime;
/* libtpms added: */
int64_t s_hostMonotonicAdjustTime; /* can be negative */
uint64_t s_suspendedElapsedTime;
#endif
/* From LocalityPlat.c */
unsigned char s_locality;

View File

@ -3,7 +3,7 @@
/* Instance data for the Platform module. */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* $Id: PlatformData.h 1047 2017-07-20 18:27:34Z kgoldman $ */
/* $Id: PlatformData.h 1259 2018-07-10 19:11:09Z kgoldman $ */
/* */
/* Licenses and Notices */
/* */
@ -55,13 +55,10 @@
/* arising in any way out of use or reliance upon this specification or any */
/* information herein. */
/* */
/* (c) Copyright IBM Corp. and others, 2016, 2017. */
/* (c) Copyright IBM Corp. and others, 2016 - 2018. */
/* */
/********************************************************************************/
#ifndef PLATFORMDATA_H
#define PLATFORMDATA_H
/* A.1 PlatformData.h */
/* This file contains the instance data for the Platform module. It is collected in this file so
that the state of the module is easier to manage. */
@ -71,21 +68,31 @@
/* From Cancel.c Cancel flag. It is initialized as FALSE, which indicate the command is not being
canceled */
extern int s_isCanceled;
#include <time.h>
#ifndef __CYGWIN__
typedef struct {
time_t tv_sec; // Seconds - >= 0
long tv_nsec; // Nanoseconds - [0, 999999999]
} timespec_t;
#ifdef _MSC_VER
#include <sys/types.h>
#include <sys/timeb.h>
#else
#include <sys/time.h>
#include <time.h>
#endif
#ifndef HARDWARE_CLOCK
/* This is the value returned the last time that the system clock was read. This is only relevant
for a simulator or virtual TPM. */
extern clock_t s_realTimePrevious;
/* This is the rate adjusted value that is the equivalent of what would be read from a hardware
register that produced rate adjusted time. */
extern clock_t s_tpmTime;
typedef uint64_t clock64_t;
// This is the value returned the last time that the system clock was read. This is only relevant
// for a simulator or virtual TPM.
extern clock64_t s_realTimePrevious;
// These values are uses to try to synthesize a long lived version of clock().
extern clock64_t s_lastSystemTime;
extern clock64_t s_lastReportedTime;
// This is the rate adjusted value that is the equivalent of what would be read from a hardware
// register that produced rate adjusted time.
extern clock64_t s_tpmTime;
/* libtpms added: */
extern int64_t s_hostMonotonicAdjustTime;
extern uint64_t s_suspendedElapsedTime;
#endif // HARDWARE_CLOCK
/* This value indicates that the timer was reset */
extern BOOL s_timerReset;
/* This value indicates that the timer was stopped. It causes a clock discontinuity. */
@ -133,6 +140,3 @@ extern BOOL s_powerLost;
/* From Entropy.c */
extern uint32_t lastEntropy;
#endif // _PLATFORM_DATA_H_
#endif

View File

@ -379,7 +379,7 @@ _plat__GetUnique(
/* libtpms: */
#include <time.h>
void ClockAdjustPostResume(UINT64 backthen);
void ClockAdjustPostResume(UINT64 backthen, BOOL timesAreRealtime);
uint64_t ClockGetTime(clockid_t clk_id);
#endif // _PLATFORM_FP_H_