• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stefanberger / libtpms / #2033

04 Dec 2025 02:24PM UTC coverage: 77.218% (-0.003%) from 77.221%
#2033

push

travis-ci

web-flow
Merge 914712db4 into 4f71e9b45

50 of 63 new or added lines in 13 files covered. (79.37%)

897 existing lines in 26 files now uncovered.

36122 of 46779 relevant lines covered (77.22%)

125357.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.26
/src/tpm2/ExecCommand.c
1
// SPDX-License-Identifier: BSD-2-Clause
2

3
//** Introduction
4
//
5
// This file contains the entry function ExecuteCommand() which provides the main
6
// control flow for TPM command execution.
7

8
//** Includes
9

10
#include "Tpm.h"
11
#include "Marshal.h"
12
// TODO_RENAME_INC_FOLDER:platform_interface refers to the TPM_CoreLib platform interface
13
#include "ExecCommand_fp.h"        // libtpms changed
14

15
// Uncomment this next #include if doing static command/response buffer sizing
16
// #include "CommandResponseSizes_fp.h"
17

18
#define TPM_HAVE_TPM2_DECLARATIONS
19
#include "tpm_library_intern.h"  // libtpms added
20

21
//** ExecuteCommand()
22
//
23
// The function performs the following steps.
24
//
25
//  a)  Parses the command header from input buffer.
26
//  b)  Calls ParseHandleBuffer() to parse the handle area of the command.
27
//  c)  Validates that each of the handles references a loaded entity.
28
//  d)  Calls ParseSessionBuffer () to:
29
//      1)  unmarshal and parse the session area;
30
//      2)  check the authorizations; and
31
//      3)  when necessary, decrypt a parameter.
32
//  e)  Calls CommandDispatcher() to:
33
//      1)  unmarshal the command parameters from the command buffer;
34
//      2)  call the routine that performs the command actions; and
35
//      3)  marshal the responses into the response buffer.
36
//  f)  If any error occurs in any of the steps above create the error response
37
//      and return.
38
//  g)  Calls BuildResponseSession() to:
39
//      1)  when necessary, encrypt a parameter
40
//      2)  build the response authorization sessions
41
//      3)  update the audit sessions and nonces
42
//  h)  Calls BuildResponseHeader() to complete the construction of the response.
43
//
44
// 'responseSize' is set by the caller to the maximum number of bytes available in
45
// the output buffer. ExecuteCommand will adjust the value and return the number
46
// of bytes placed in the buffer.
47
//
48
// 'response' is also set by the caller to indicate the buffer into which
49
//  ExecuteCommand is to place the response.
50
//
51
//  'request' and 'response' may point to the same buffer
52
//
53
// Note: As of February, 2016, the failure processing has been moved to the
54
// platform-specific code. When the TPM code encounters an unrecoverable failure, it
55
// will SET g_inFailureMode and call _plat__Fail(). That function should not return
56
// but may call ExecuteCommand().
57
//
58
LIB_EXPORT void ExecuteCommand(
17,795✔
59
    uint32_t        requestSize,   // IN: command buffer size
60
    unsigned char*  request,       // IN: command buffer
61
    uint32_t*       responseSize,  // IN/OUT: response buffer size
62
    unsigned char** response       // IN/OUT: response buffer
63
)
64
{
65
    // Command local variables
66
    UINT32  commandSize;
17,795✔
67
    COMMAND command;
17,795✔
68

69
    // Response local variables
70
    UINT32 maxResponse = *responseSize;
17,795✔
71
    TPM_RC result;  // return code for the command
17,795✔
72

73
    /* check for an unreasonably large command size, since it's cast to a signed integer later */
74
    if (requestSize > INT32_MAX) {
17,795✔
UNCOV
75
        result = TPM_RC_SUCCESS;
×
UNCOV
76
        goto Cleanup;
×
77
    }
78
    // This next function call is used in development to size the command and response
79
    // buffers. The values printed are the sizes of the internal structures and
80
    // not the sizes of the canonical forms of the command response structures. Also,
81
    // the sizes do not include the tag, command.code, requestSize, or the authorization
82
    // fields.
83
    //CommandResponseSizes();
84
    // Set flags for NV access state. This should happen before any other
85
    // operation that may require a NV write. Note, that this needs to be done
86
    // even when in failure mode. Otherwise, g_updateNV would stay SET while in
87
    // Failure mode and the NV would be written on each call.
88
    g_updateNV     = UT_NONE;
17,795✔
89
    g_clearOrderly = FALSE;
17,795✔
90
    if(g_inFailureMode)
17,795✔
91
    {
92
        // Do failure mode processing
UNCOV
93
        TpmFailureMode(requestSize, request, responseSize, response);
×
UNCOV
94
        return;
×
95
    }
96
    // Query platform to get the NV state.  The result state is saved internally
97
    // and will be reported by NvIsAvailable(). The reference code requires that
98
    // accessibility of NV does not change during the execution of a command.
99
    // Specifically, if NV is available when the command execution starts and then
100
    // is not available later when it is necessary to write to NV, then the TPM
101
    // will go into failure mode.
102
    NvCheckState();
17,795✔
103

104
    // Due to the limitations of the simulation, TPM clock must be explicitly
105
    // synchronized with the system clock whenever a command is received.
106
    // This function call is not necessary in a hardware TPM. However, taking
107
    // a snapshot of the hardware timer at the beginning of the command allows
108
    // the time value to be consistent for the duration of the command execution.
109
    TimeUpdateToCurrent();
17,795✔
110

111
    // Any command through this function will unceremoniously end the
112
    // _TPM_Hash_Data/_TPM_Hash_End sequence.
113
    if(g_DRTMHandle != TPM_RH_UNASSIGNED)
17,795✔
UNCOV
114
        ObjectTerminateEvent();
×
115

116
    // Get command buffer size and command buffer.
117
    command.tag = 0;                                // libtpms added: Coverity
17,795✔
118
    command.parameterBuffer = request;
17,795✔
119
    command.parameterSize   = requestSize;
17,795✔
120

121
    // Parse command header: tag, commandSize and command.code.
122
    // First parse the tag. The unmarshaling routine will validate
123
    // that it is either TPM_ST_SESSIONS or TPM_ST_NO_SESSIONS.
124
    result = TPMI_ST_COMMAND_TAG_Unmarshal(
17,795✔
125
        &command.tag, &command.parameterBuffer, &command.parameterSize);
126
    if(result != TPM_RC_SUCCESS)
17,795✔
127
        goto Cleanup;
12✔
128
    // Unmarshal the commandSize indicator.
129
    result = UINT32_Unmarshal(
17,783✔
130
        &commandSize, &command.parameterBuffer, &command.parameterSize);
131
    if(result != TPM_RC_SUCCESS)
17,783✔
132
        goto Cleanup;
4✔
133
    // On a TPM that receives bytes on a port, the number of bytes that were
134
    // received on that port is requestSize it must be identical to commandSize.
135
    // In addition, commandSize must not be larger than MAX_COMMAND_SIZE allowed
136
    // by the implementation. The check against MAX_COMMAND_SIZE may be redundant
137
    // as the input processing (the function that receives the command bytes and
138
    // places them in the input buffer) would likely have the input truncated when
139
    // it reaches MAX_COMMAND_SIZE, and requestSize would not equal commandSize.
140
    if(commandSize != requestSize || commandSize > MAX_COMMAND_SIZE)
17,779✔
141
    {
142
        result = TPM_RC_COMMAND_SIZE;
4✔
143
        goto Cleanup;
4✔
144
    }
145
    // Unmarshal the command code.
146
    result = TPM_CC_Unmarshal(
17,775✔
147
        &command.code, &command.parameterBuffer, &command.parameterSize);
148
    if(result != TPM_RC_SUCCESS)
17,775✔
149
        goto Cleanup;
4✔
150
    // Check to see if the command is implemented.
151
    command.index = CommandCodeToCommandIndex(command.code);
17,771✔
152
    if(UNIMPLEMENTED_COMMAND_INDEX == command.index)
17,771✔
153
    {
154
        result = TPM_RC_COMMAND_CODE;
5✔
155
        goto Cleanup;
5✔
156
    }
157
#if CC_ReadOnlyControl
158
    // Check if the TPM is operating in Read-Only mode. If so, reject commands
159
    // that are disallowed in this mode before performing any further auth checks.
160
    // The execution of some commands may still be disallowed under certain conditions,
161
    // but those will be evaluated in the corresponding command implementation.
162
    if(gc.readOnly && IsDisallowedInReadOnlyMode(command.index))
163
    {
164
        result = TPM_RC_READ_ONLY;
165
        goto Cleanup;
166
    }
167
#endif
168
#if FIELD_UPGRADE_IMPLEMENTED == YES
169
    // If the TPM is in FUM, then the only allowed command is
170
    // TPM_CC_FieldUpgradeData.
171
    if(IsFieldUgradeMode() && (command.code != TPM_CC_FieldUpgradeData))
172
    {
173
        result = TPM_RC_UPGRADE;
174
        goto Cleanup;
175
    }
176
    else
177
#endif
178
        // Excepting FUM, the TPM only accepts TPM2_Startup() after
179
        // _TPM_Init. After getting a TPM2_Startup(), TPM2_Startup()
180
        // is no longer allowed.
181
        if((!TPMIsStarted() && command.code != TPM_CC_Startup)
17,766✔
182
           || (TPMIsStarted() && command.code == TPM_CC_Startup))
17,741✔
183
        {
184
            result = TPM_RC_INITIALIZE;
36✔
185
            goto Cleanup;
36✔
186
        }
187
    // Start regular command process.
188
    NvIndexCacheInit();
17,730✔
189
    // Parse Handle buffer.
190
    result = ParseHandleBuffer(&command);
17,730✔
191
    if(result != TPM_RC_SUCCESS)
17,730✔
192
        goto Cleanup;
514✔
193
    // All handles in the handle area are required to reference TPM-resident
194
    // entities.
195
    result = EntityGetLoadStatus(&command);
17,216✔
196
    if(result != TPM_RC_SUCCESS)
17,216✔
197
        goto Cleanup;
370✔
198
    // Authorization session handling for the command.
199
    ClearCpRpHashes(&command);
16,846✔
200
    if(command.tag == TPM_ST_SESSIONS)
16,846✔
201
    {
202
        // Find out session buffer size.
203
        result = UINT32_Unmarshal((UINT32*)&command.authSize,
6,336✔
204
                                  &command.parameterBuffer,
205
                                  &command.parameterSize);
206
        if(result != TPM_RC_SUCCESS)
6,336✔
207
            goto Cleanup;
4✔
208
        // Perform sanity check on the unmarshaled value. If it is smaller than
209
        // the smallest possible session or larger than the remaining size of
210
        // the command, then it is an error. NOTE: This check could pass but the
211
        // session size could still be wrong. That will be determined after the
212
        // sessions are unmarshaled.
213
        if(command.authSize < 9 || command.authSize > command.parameterSize)
6,332✔
214
        {
215
            result = TPM_RC_SIZE;
24✔
216
            goto Cleanup;
24✔
217
        }
218
        command.parameterSize -= command.authSize;
6,308✔
219

220
        // The actions of ParseSessionBuffer() are described in the introduction.
221
        // As the sessions are parsed command.parameterBuffer is advanced so, on a
222
        // successful return, command.parameterBuffer should be pointing at the
223
        // first byte of the parameters.
224
        result = ParseSessionBuffer(&command);
6,308✔
225
        if(result != TPM_RC_SUCCESS)
6,308✔
226
            goto Cleanup;
273✔
227
    }
228
    else
229
    {
230
        command.authSize = 0;
10,510✔
231
        // The command has no authorization sessions.
232
        // If the command requires authorizations, then CheckAuthNoSession() will
233
        // return an error.
234
        result = CheckAuthNoSession(&command);
10,510✔
235
        if(result != TPM_RC_SUCCESS)
10,510✔
236
            goto Cleanup;
24✔
237
    }
238
    // Set up the response buffer pointers. CommandDispatch will marshal the
239
    // response parameters starting at the address in command.responseBuffer.
240
    //*response = MemoryGetResponseBuffer(command.index);
241
    // leave space for the command header
242
    command.responseBuffer = *response + STD_RESPONSE_HEADER;
16,521✔
243

244
    // leave space for the parameter size field if needed
245
    if(command.tag == TPM_ST_SESSIONS)
16,521✔
246
        command.responseBuffer += sizeof(UINT32);
6,035✔
247
    if(IsHandleInResponse(command.index))
16,521✔
248
        command.responseBuffer += sizeof(TPM_HANDLE);
2,633✔
249

250
    // CommandDispatcher returns a response handle buffer and a response parameter
251
    // buffer if it succeeds. It will also set the parameterSize field in the
252
    // buffer if the tag is TPM_RC_SESSIONS.
253
    result = CommandDispatcher(&command);
16,521✔
254
    if(result != TPM_RC_SUCCESS)
16,521✔
255
        goto Cleanup;
1,930✔
256

257
    // Build the session area at the end of the parameter area.
258
    result = BuildResponseSession(&command);
14,591✔
259
    if(result != TPM_RC_SUCCESS)
14,591✔
260
    {
261
        goto Cleanup;
262
    }
263

264
Cleanup:
14,591✔
265
    if(g_clearOrderly == TRUE && NV_IS_ORDERLY)
17,795✔
266
    {
267
#if USE_DA_USED
268
        gp.orderlyState = g_daUsed ? SU_DA_USED_VALUE : SU_NONE_VALUE;
2✔
269
#else
270
        gp.orderlyState = SU_NONE_VALUE;
271
#endif
272
        NV_SYNC_PERSISTENT(orderlyState);
2✔
273
    }
274
    // This implementation loads an "evict" object to a transient object slot in
275
    // RAM whenever an "evict" object handle is used in a command so that the
276
    // access to any object is the same. These temporary objects need to be
277
    // cleared from RAM whether the command succeeds or fails.
278
    ObjectCleanupEvict();
17,795✔
279

280
    // The parameters and sessions have been marshaled. Now tack on the header and
281
    // set the sizes
282
    BuildResponseHeader(&command, *response, result);
17,795✔
283

284
    // Try to commit all the writes to NV if any NV write happened during this
285
    // command execution. This check should be made for both succeeded and failed
286
    // commands, because a failed one may trigger a NV write in DA logic as well.
287
    // This is the only place in the command execution path that may call the NV
288
    // commit. If the NV commit fails, the TPM should be put in failure mode.
289
    if((g_updateNV != UT_NONE) && !g_inFailureMode)
17,795✔
290
    {
291
        if(g_updateNV == UT_ORDERLY)
6,794✔
292
            NvUpdateIndexOrderlyData();
15✔
293
        if(!NvCommit())
6,794✔
UNCOV
294
            FAIL(FATAL_ERROR_INTERNAL);
×
295
        g_updateNV = UT_NONE;
6,794✔
296
    }
297
    pAssert((UINT32)command.parameterSize <= maxResponse);
17,795✔
298

299
    // Clear unused bits in response buffer.
300
    MemorySet(*response + *responseSize, 0, maxResponse - *responseSize);
17,795✔
301

302
    // as a final act, and not before, update the response size.
303
    *responseSize = (UINT32)command.parameterSize;
17,795✔
304

305
    return;
17,795✔
306
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc