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

stefanberger / libtpms / #2046

02 Jan 2026 04:38PM UTC coverage: 77.225% (+0.01%) from 77.211%
#2046

push

travis-ci

web-flow
Merge d93cf7173 into ee31b0b23

1 of 1 new or added line in 1 file covered. (100.0%)

527 existing lines in 42 files now uncovered.

36112 of 46762 relevant lines covered (77.23%)

126004.05 hits per line

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

93.26
/src/tpm2/ExecCommand.c
1
/********************************************************************************/
2
/*                                                                                */
3
/*                             ExecCommand                                        */
4
/*                             Written by Ken Goldman                                */
5
/*                       IBM Thomas J. Watson Research Center                        */
6
/*                                                                                */
7
/*  Licenses and Notices                                                        */
8
/*                                                                                */
9
/*  1. Copyright Licenses:                                                        */
10
/*                                                                                */
11
/*  - Trusted Computing Group (TCG) grants to the user of the source code in        */
12
/*    this specification (the "Source Code") a worldwide, irrevocable,                 */
13
/*    nonexclusive, royalty free, copyright license to reproduce, create         */
14
/*    derivative works, distribute, display and perform the Source Code and        */
15
/*    derivative works thereof, and to grant others the rights granted herein.        */
16
/*                                                                                */
17
/*  - The TCG grants to the user of the other parts of the specification         */
18
/*    (other than the Source Code) the rights to reproduce, distribute,         */
19
/*    display, and perform the specification solely for the purpose of                 */
20
/*    developing products based on such documents.                                */
21
/*                                                                                */
22
/*  2. Source Code Distribution Conditions:                                        */
23
/*                                                                                */
24
/*  - Redistributions of Source Code must retain the above copyright licenses,         */
25
/*    this list of conditions and the following disclaimers.                        */
26
/*                                                                                */
27
/*  - Redistributions in binary form must reproduce the above copyright         */
28
/*    licenses, this list of conditions        and the following disclaimers in the         */
29
/*    documentation and/or other materials provided with the distribution.        */
30
/*                                                                                */
31
/*  3. Disclaimers:                                                                */
32
/*                                                                                */
33
/*  - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF        */
34
/*  LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH        */
35
/*  RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES)        */
36
/*  THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE.                */
37
/*  Contact TCG Administration (admin@trustedcomputinggroup.org) for                 */
38
/*  information on specification licensing rights available through TCG         */
39
/*  membership agreements.                                                        */
40
/*                                                                                */
41
/*  - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED         */
42
/*    WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR         */
43
/*    FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR                 */
44
/*    NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY                 */
45
/*    OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.                */
46
/*                                                                                */
47
/*  - Without limitation, TCG and its members and licensors disclaim all         */
48
/*    liability, including liability for infringement of any proprietary         */
49
/*    rights, relating to use of information in this specification and to the        */
50
/*    implementation of this specification, and TCG disclaims all liability for        */
51
/*    cost of procurement of substitute goods or services, lost profits, loss         */
52
/*    of use, loss of data or any incidental, consequential, direct, indirect,         */
53
/*    or special damages, whether under contract, tort, warranty or otherwise,         */
54
/*    arising in any way out of use or reliance upon this specification or any         */
55
/*    information herein.                                                        */
56
/*                                                                                */
57
/*  (c) Copyright IBM Corp. and others, 2016 - 2023                                */
58
/*                                                                                */
59
/********************************************************************************/
60

61
//** Introduction
62
//
63
// This file contains the entry function ExecuteCommand() which provides the main
64
// control flow for TPM command execution.
65

66
//** Includes
67

68
#include "Tpm.h"
69
#include "Marshal.h"
70
// TODO_RENAME_INC_FOLDER:platform_interface refers to the TPM_CoreLib platform interface
71
#include "ExecCommand_fp.h"        // libtpms changed
72

73
// Uncomment this next #include if doing static command/response buffer sizing
74
// #include "CommandResponseSizes_fp.h"
75

76
#define TPM_HAVE_TPM2_DECLARATIONS
77
#include "tpm_library_intern.h"  // libtpms added
78

79
//** ExecuteCommand()
80
//
81
// The function performs the following steps.
82
//
83
//  a)  Parses the command header from input buffer.
84
//  b)  Calls ParseHandleBuffer() to parse the handle area of the command.
85
//  c)  Validates that each of the handles references a loaded entity.
86
//  d)  Calls ParseSessionBuffer () to:
87
//      1)  unmarshal and parse the session area;
88
//      2)  check the authorizations; and
89
//      3)  when necessary, decrypt a parameter.
90
//  e)  Calls CommandDispatcher() to:
91
//      1)  unmarshal the command parameters from the command buffer;
92
//      2)  call the routine that performs the command actions; and
93
//      3)  marshal the responses into the response buffer.
94
//  f)  If any error occurs in any of the steps above create the error response
95
//      and return.
96
//  g)  Calls BuildResponseSession() to:
97
//      1)  when necessary, encrypt a parameter
98
//      2)  build the response authorization sessions
99
//      3)  update the audit sessions and nonces
100
//  h)  Calls BuildResponseHeader() to complete the construction of the response.
101
//
102
// 'responseSize' is set by the caller to the maximum number of bytes available in
103
// the output buffer. ExecuteCommand will adjust the value and return the number
104
// of bytes placed in the buffer.
105
//
106
// 'response' is also set by the caller to indicate the buffer into which
107
//  ExecuteCommand is to place the response.
108
//
109
//  'request' and 'response' may point to the same buffer
110
//
111
// Note: As of February, 2016, the failure processing has been moved to the
112
// platform-specific code. When the TPM code encounters an unrecoverable failure, it
113
// will SET g_inFailureMode and call _plat__Fail(). That function should not return
114
// but may call ExecuteCommand().
115
//
116
LIB_EXPORT void ExecuteCommand(
17,795✔
117
    uint32_t        requestSize,   // IN: command buffer size
118
    unsigned char*  request,       // IN: command buffer
119
    uint32_t*       responseSize,  // IN/OUT: response buffer size
120
    unsigned char** response       // IN/OUT: response buffer
121
)
122
{
123
    // Command local variables
124
    UINT32  commandSize;
17,795✔
125
    COMMAND command;
17,795✔
126

127
    // Response local variables
128
    UINT32 maxResponse = *responseSize;
17,795✔
129
    TPM_RC result;  // return code for the command
17,795✔
130

131
    /* check for an unreasonably large command size, since it's cast to a signed integer later */
132
    if (requestSize > INT32_MAX) {
17,795✔
UNCOV
133
        result = TPM_RC_SUCCESS;
×
UNCOV
134
        goto Cleanup;
×
135
    }
136
    // This next function call is used in development to size the command and response
137
    // buffers. The values printed are the sizes of the internal structures and
138
    // not the sizes of the canonical forms of the command response structures. Also,
139
    // the sizes do not include the tag, command.code, requestSize, or the authorization
140
    // fields.
141
    //CommandResponseSizes();
142
    // Set flags for NV access state. This should happen before any other
143
    // operation that may require a NV write. Note, that this needs to be done
144
    // even when in failure mode. Otherwise, g_updateNV would stay SET while in
145
    // Failure mode and the NV would be written on each call.
146
    g_updateNV     = UT_NONE;
17,795✔
147
    g_clearOrderly = FALSE;
17,795✔
148
    if(g_inFailureMode)
17,795✔
149
    {
150
        // Do failure mode processing
UNCOV
151
        TpmFailureMode(requestSize, request, responseSize, response);
×
UNCOV
152
        return;
×
153
    }
154
    // Query platform to get the NV state.  The result state is saved internally
155
    // and will be reported by NvIsAvailable(). The reference code requires that
156
    // accessibility of NV does not change during the execution of a command.
157
    // Specifically, if NV is available when the command execution starts and then
158
    // is not available later when it is necessary to write to NV, then the TPM
159
    // will go into failure mode.
160
    NvCheckState();
17,795✔
161

162
    // Due to the limitations of the simulation, TPM clock must be explicitly
163
    // synchronized with the system clock whenever a command is received.
164
    // This function call is not necessary in a hardware TPM. However, taking
165
    // a snapshot of the hardware timer at the beginning of the command allows
166
    // the time value to be consistent for the duration of the command execution.
167
    TimeUpdateToCurrent();
17,795✔
168

169
    // Any command through this function will unceremoniously end the
170
    // _TPM_Hash_Data/_TPM_Hash_End sequence.
171
    if(g_DRTMHandle != TPM_RH_UNASSIGNED)
17,795✔
UNCOV
172
        ObjectTerminateEvent();
×
173

174
    // Get command buffer size and command buffer.
175
    command.tag = 0;                                // libtpms added: Coverity
17,795✔
176
    command.parameterBuffer = request;
17,795✔
177
    command.parameterSize   = requestSize;
17,795✔
178

179
    // Parse command header: tag, commandSize and command.code.
180
    // First parse the tag. The unmarshaling routine will validate
181
    // that it is either TPM_ST_SESSIONS or TPM_ST_NO_SESSIONS.
182
    result = TPMI_ST_COMMAND_TAG_Unmarshal(
17,795✔
183
        &command.tag, &command.parameterBuffer, &command.parameterSize);
184
    if(result != TPM_RC_SUCCESS)
17,795✔
185
        goto Cleanup;
12✔
186
    // Unmarshal the commandSize indicator.
187
    result = UINT32_Unmarshal(
17,783✔
188
        &commandSize, &command.parameterBuffer, &command.parameterSize);
189
    if(result != TPM_RC_SUCCESS)
17,783✔
190
        goto Cleanup;
4✔
191
    // On a TPM that receives bytes on a port, the number of bytes that were
192
    // received on that port is requestSize it must be identical to commandSize.
193
    // In addition, commandSize must not be larger than MAX_COMMAND_SIZE allowed
194
    // by the implementation. The check against MAX_COMMAND_SIZE may be redundant
195
    // as the input processing (the function that receives the command bytes and
196
    // places them in the input buffer) would likely have the input truncated when
197
    // it reaches MAX_COMMAND_SIZE, and requestSize would not equal commandSize.
198
    if(commandSize != requestSize || commandSize > MAX_COMMAND_SIZE)
17,779✔
199
    {
200
        result = TPM_RC_COMMAND_SIZE;
4✔
201
        goto Cleanup;
4✔
202
    }
203
    // Unmarshal the command code.
204
    result = TPM_CC_Unmarshal(
17,775✔
205
        &command.code, &command.parameterBuffer, &command.parameterSize);
206
    if(result != TPM_RC_SUCCESS)
17,775✔
207
        goto Cleanup;
4✔
208
    // Check to see if the command is implemented.
209
    command.index = CommandCodeToCommandIndex(command.code);
17,771✔
210
    if(UNIMPLEMENTED_COMMAND_INDEX == command.index)
17,771✔
211
    {
212
        result = TPM_RC_COMMAND_CODE;
5✔
213
        goto Cleanup;
5✔
214
    }
215
#if FIELD_UPGRADE_IMPLEMENTED == YES
216
    // If the TPM is in FUM, then the only allowed command is
217
    // TPM_CC_FieldUpgradeData.
218
    if(IsFieldUgradeMode() && (command.code != TPM_CC_FieldUpgradeData))
219
    {
220
        result = TPM_RC_UPGRADE;
221
        goto Cleanup;
222
    }
223
    else
224
#endif
225
        // Excepting FUM, the TPM only accepts TPM2_Startup() after
226
        // _TPM_Init. After getting a TPM2_Startup(), TPM2_Startup()
227
        // is no longer allowed.
228
        if((!TPMIsStarted() && command.code != TPM_CC_Startup)
17,766✔
229
           || (TPMIsStarted() && command.code == TPM_CC_Startup))
17,741✔
230
        {
231
            result = TPM_RC_INITIALIZE;
36✔
232
            goto Cleanup;
36✔
233
        }
234
    // Start regular command process.
235
    NvIndexCacheInit();
17,730✔
236
    // Parse Handle buffer.
237
    result = ParseHandleBuffer(&command);
17,730✔
238
    if(result != TPM_RC_SUCCESS)
17,730✔
239
        goto Cleanup;
514✔
240
    // All handles in the handle area are required to reference TPM-resident
241
    // entities.
242
    result = EntityGetLoadStatus(&command);
17,216✔
243
    if(result != TPM_RC_SUCCESS)
17,216✔
244
        goto Cleanup;
370✔
245
    // Authorization session handling for the command.
246
    ClearCpRpHashes(&command);
16,846✔
247
    if(command.tag == TPM_ST_SESSIONS)
16,846✔
248
    {
249
        // Find out session buffer size.
250
        result = UINT32_Unmarshal((UINT32*)&command.authSize,
6,337✔
251
                                  &command.parameterBuffer,
252
                                  &command.parameterSize);
253
        if(result != TPM_RC_SUCCESS)
6,337✔
254
            goto Cleanup;
4✔
255
        // Perform sanity check on the unmarshaled value. If it is smaller than
256
        // the smallest possible session or larger than the remaining size of
257
        // the command, then it is an error. NOTE: This check could pass but the
258
        // session size could still be wrong. That will be determined after the
259
        // sessions are unmarshaled.
260
        if(command.authSize < 9 || command.authSize > command.parameterSize)
6,333✔
261
        {
262
            result = TPM_RC_SIZE;
24✔
263
            goto Cleanup;
24✔
264
        }
265
        command.parameterSize -= command.authSize;
6,309✔
266

267
        // The actions of ParseSessionBuffer() are described in the introduction.
268
        // As the sessions are parsed command.parameterBuffer is advanced so, on a
269
        // successful return, command.parameterBuffer should be pointing at the
270
        // first byte of the parameters.
271
        result = ParseSessionBuffer(&command);
6,309✔
272
        if(result != TPM_RC_SUCCESS)
6,309✔
273
            goto Cleanup;
273✔
274
    }
275
    else
276
    {
277
        command.authSize = 0;
10,509✔
278
        // The command has no authorization sessions.
279
        // If the command requires authorizations, then CheckAuthNoSession() will
280
        // return an error.
281
        result = CheckAuthNoSession(&command);
10,509✔
282
        if(result != TPM_RC_SUCCESS)
10,509✔
283
            goto Cleanup;
24✔
284
    }
285
    // Set up the response buffer pointers. CommandDispatch will marshal the
286
    // response parameters starting at the address in command.responseBuffer.
287
    //*response = MemoryGetResponseBuffer(command.index);
288
    // leave space for the command header
289
    command.responseBuffer = *response + STD_RESPONSE_HEADER;
16,521✔
290

291
    // leave space for the parameter size field if needed
292
    if(command.tag == TPM_ST_SESSIONS)
16,521✔
293
        command.responseBuffer += sizeof(UINT32);
6,036✔
294
    if(IsHandleInResponse(command.index))
16,521✔
295
        command.responseBuffer += sizeof(TPM_HANDLE);
2,633✔
296

297
    // CommandDispatcher returns a response handle buffer and a response parameter
298
    // buffer if it succeeds. It will also set the parameterSize field in the
299
    // buffer if the tag is TPM_RC_SESSIONS.
300
    result = CommandDispatcher(&command);
16,521✔
301
    if(result != TPM_RC_SUCCESS)
16,521✔
302
        goto Cleanup;
1,930✔
303

304
    // Build the session area at the end of the parameter area.
305
    result = BuildResponseSession(&command);
14,591✔
306
    if(result != TPM_RC_SUCCESS)
14,591✔
307
    {
308
        goto Cleanup;
309
    }
310

311
Cleanup:
14,591✔
312
    if(g_clearOrderly == TRUE && NV_IS_ORDERLY)
17,795✔
313
    {
314
#if USE_DA_USED
315
        gp.orderlyState = g_daUsed ? SU_DA_USED_VALUE : SU_NONE_VALUE;
2✔
316
#else
317
        gp.orderlyState = SU_NONE_VALUE;
318
#endif
319
        NV_SYNC_PERSISTENT(orderlyState);
2✔
320
    }
321
    // This implementation loads an "evict" object to a transient object slot in
322
    // RAM whenever an "evict" object handle is used in a command so that the
323
    // access to any object is the same. These temporary objects need to be
324
    // cleared from RAM whether the command succeeds or fails.
325
    ObjectCleanupEvict();
17,795✔
326

327
    // The parameters and sessions have been marshaled. Now tack on the header and
328
    // set the sizes
329
    BuildResponseHeader(&command, *response, result);
17,795✔
330

331
    // Try to commit all the writes to NV if any NV write happened during this
332
    // command execution. This check should be made for both succeeded and failed
333
    // commands, because a failed one may trigger a NV write in DA logic as well.
334
    // This is the only place in the command execution path that may call the NV
335
    // commit. If the NV commit fails, the TPM should be put in failure mode.
336
    if((g_updateNV != UT_NONE) && !g_inFailureMode)
17,795✔
337
    {
338
        if(g_updateNV == UT_ORDERLY)
6,794✔
339
            NvUpdateIndexOrderlyData();
15✔
340
        if(!NvCommit())
6,794✔
UNCOV
341
            FAIL(FATAL_ERROR_INTERNAL);
×
342
        g_updateNV = UT_NONE;
6,794✔
343
    }
344
    pAssert((UINT32)command.parameterSize <= maxResponse);
17,795✔
345

346
    // Clear unused bits in response buffer.
347
    MemorySet(*response + *responseSize, 0, maxResponse - *responseSize);
17,795✔
348

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

352
    return;
17,795✔
353
}
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