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

stefanberger / libtpms / #2001

10 Jun 2025 05:34PM UTC coverage: 76.734% (-0.5%) from 77.211%
#2001

push

travis-ci

web-flow
Merge 953b57ed4 into 9d6d76cc6

26 of 29 new or added lines in 2 files covered. (89.66%)

2807 existing lines in 74 files now uncovered.

33291 of 43385 relevant lines covered (76.73%)

61752.99 hits per line

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

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

62
/* 6.2 ExecCommand.c */
63
/* This file contains the entry function ExecuteCommand() which provides the main control flow for
64
   TPM command execution. */
65
#include "Tpm.h"
66
#include "ExecCommand_fp.h"
67

68
#define TPM_HAVE_TPM2_DECLARATIONS
69
#include "tpm_library_intern.h"  // libtpms added
70

71
/* Uncomment this next #include if doing static command/response buffer sizing */
72
// #include "CommandResponseSizes_fp.h"
73
// The function performs the following steps.
74
// a)        Parses the command header from input buffer.
75
// b)        Calls ParseHandleBuffer() to parse the handle area of the command.
76
//     c)        Validates that each of the handles references a loaded entity.
77
//     d)        Calls ParseSessionBuffer() () to:
78
// 1)        unmarshal and parse the session area;
79
// 2)        check the authorizations; and
80
// 3)        when necessary, decrypt a parameter.
81
//       e)        Calls CommandDispatcher() to:
82
// 1)        unmarshal the command parameters from the command buffer;
83
// 2)        call the routine that performs the command actions; and
84
// 3)        marshal the responses into the response buffer.
85
// f)        If any error occurs in any of the steps above create the error response and return.
86
// g)        Calls BuildResponseSessions() to:
87
// 1)        when necessary, encrypt a parameter
88
//       2)        build the response authorization sessions
89
//       3)        update the audit sessions and nonces
90
//       h)        Calls BuildResponseHeader() to complete the construction of the response.
91

92
//           responseSize is set by the caller to the maximum number of bytes available in the output
93
//           buffer. ExecuteCommand() will adjust the value and return the number of bytes placed in
94
//           the buffer.
95
//           response is also set by the caller to indicate the buffer into which ExecuteCommand() is
96
//           to place the response.
97
//           request and response may point to the same buffer
98
//           NOTE: As of February, 2016, the failure processing has been moved to the platform-specific
99
//           code. When the TPM code encounters an unrecoverable failure, it will SET g_inFailureMode
100
//           and call _plat__Fail(). That function should not return but may call ExecuteCommand().
101
LIB_EXPORT void
102
ExecuteCommand(
16,292✔
103
               uint32_t         requestSize,   // IN: command buffer size
104
               unsigned char   *request,       // IN: command buffer
105
               uint32_t        *responseSize,  // IN/OUT: response buffer size
106
               unsigned char   **response      // IN/OUT: response buffer
107
               )
108
{
109
    // Command local variables
110
    UINT32               commandSize;
16,292✔
111
    COMMAND              command;
16,292✔
112
    // Response local variables
113
    UINT32               maxResponse = *responseSize;
16,292✔
114
    TPM_RC               result;            // return code for the command
16,292✔
115
    // This next function call is used in development to size the command and response
116
    // buffers. The values printed are the sizes of the internal structures and
117
    // not the sizes of the canonical forms of he command response structures. Also,
118
    // the sizes do not include the tag, command.code, requestSize, or the authorization
119
    // fields.
120
    //CommandResponseSizes();
121
    // Set flags for NV access state. This should happen before any other
122
    // operation that may require a NV write. Note, that this needs to be done
123
    // even when in failure mode. Otherwise, g_updateNV would stay SET while in
124
    // Failure mode and the NV would be written on each call.
125
    g_updateNV = UT_NONE;
16,292✔
126
    g_clearOrderly = FALSE;
16,292✔
127
    if(g_inFailureMode)
16,292✔
128
        {
129
            // Do failure mode processing
UNCOV
130
            TpmFailureMode(requestSize, request, responseSize, response);
×
UNCOV
131
            return;
×
132
        }
133
    // Query platform to get the NV state.  The result state is saved internally
134
    // and will be reported by NvIsAvailable(). The reference code requires that
135
    // accessibility of NV does not change during the execution of a command.
136
    // Specifically, if NV is available when the command execution starts and then
137
    // is not available later when it is necessary to write to NV, then the TPM
138
    // will go into failure mode.
139
    NvCheckState();
16,292✔
140
    // Due to the limitations of the simulation, TPM clock must be explicitly
141
    // synchronized with the system clock whenever a command is received.
142
    // This function call is not necessary in a hardware TPM. However, taking
143
    // a snapshot of the hardware timer at the beginning of the command allows
144
    // the time value to be consistent for the duration of the command execution.
145
    TimeUpdateToCurrent();
16,292✔
146
    // Any command through this function will unceremoniously end the
147
    // _TPM_Hash_Data/_TPM_Hash_End sequence.
148
    if(g_DRTMHandle != TPM_RH_UNASSIGNED)
16,292✔
UNCOV
149
        ObjectTerminateEvent();
×
150
    // Get command buffer size and command buffer.
151
    command.parameterBuffer = request;
16,292✔
152
    command.parameterSize = requestSize;
16,292✔
153
    // Parse command header: tag, commandSize and command.code.
154
    // First parse the tag. The unmarshaling routine will validate
155
    // that it is either TPM_ST_SESSIONS or TPM_ST_NO_SESSIONS.
156
    result = TPMI_ST_COMMAND_TAG_Unmarshal(&command.tag,
16,292✔
157
                                           &command.parameterBuffer,
158
                                           &command.parameterSize);
159
    if(result != TPM_RC_SUCCESS)
16,292✔
160
        goto Cleanup;
8✔
161
    // Unmarshal the commandSize indicator.
162
    result = UINT32_Unmarshal(&commandSize,
16,284✔
163
                              &command.parameterBuffer,
164
                              &command.parameterSize);
165
    if(result != TPM_RC_SUCCESS)
16,284✔
166
        goto Cleanup;
4✔
167
    // On a TPM that receives bytes on a port, the number of bytes that were
168
    // received on that port is requestSize it must be identical to commandSize.
169
    // In addition, commandSize must not be larger than MAX_COMMAND_SIZE allowed
170
    // by the implementation. The check against MAX_COMMAND_SIZE may be redundant
171
    // as the input processing (the function that receives the command bytes and
172
    // places them in the input buffer) would likely have the input truncated when
173
    // it reaches MAX_COMMAND_SIZE, and requestSize would not equal commandSize.
174
    if(commandSize != requestSize || commandSize > MAX_COMMAND_SIZE)
16,280✔
175
        {
176
            result = TPM_RC_COMMAND_SIZE;
4✔
177
            goto Cleanup;
4✔
178
        }
179
    // Unmarshal the command code.
180
    result = TPM_CC_Unmarshal(&command.code, &command.parameterBuffer,
16,276✔
181
                              &command.parameterSize);
182
    if(result != TPM_RC_SUCCESS)
16,276✔
183
        goto Cleanup;
4✔
184
    // Check to see if the command is implemented.
185
    command.index = CommandCodeToCommandIndex(command.code);
16,272✔
186
    if(UNIMPLEMENTED_COMMAND_INDEX == command.index)
16,272✔
187
        {
188
            result = TPM_RC_COMMAND_CODE;
4✔
189
            goto Cleanup;
4✔
190
        }
191
#if  FIELD_UPGRADE_IMPLEMENTED  == YES
192
    // If the TPM is in FUM, then the only allowed command is
193
    // TPM_CC_FieldUpgradeData.
194
    if(IsFieldUgradeMode() && (command.code != TPM_CC_FieldUpgradeData))
195
        {
196
            result = TPM_RC_UPGRADE;
197
            goto Cleanup;
198
        }
199
    else
200
#endif
201
        // Excepting FUM, the TPM only accepts TPM2_Startup() after
202
        // _TPM_Init. After getting a TPM2_Startup(), TPM2_Startup()
203
        // is no longer allowed.
204
        if((!TPMIsStarted() && command.code != TPM_CC_Startup)
16,268✔
205
           || (TPMIsStarted() && command.code == TPM_CC_Startup))
16,245✔
206
            {
207
                result = TPM_RC_INITIALIZE;
34✔
208
                goto Cleanup;
34✔
209
            }
210
    // Start regular command process.
211
    NvIndexCacheInit();
16,234✔
212
    // Parse Handle buffer.
213
    result = ParseHandleBuffer(&command);
16,234✔
214
    if(result != TPM_RC_SUCCESS)
16,234✔
215
        goto Cleanup;
514✔
216
    // All handles in the handle area are required to reference TPM-resident
217
    // entities.
218
    result = EntityGetLoadStatus(&command);
15,720✔
219
    if(result != TPM_RC_SUCCESS)
15,720✔
220
        goto Cleanup;
369✔
221
    // Authorization session handling for the command.
222
    ClearCpRpHashes(&command);
15,351✔
223
    if(command.tag == TPM_ST_SESSIONS)
15,351✔
224
        {
225
            // Find out session buffer size.
226
            result = UINT32_Unmarshal((UINT32 *)&command.authSize,
5,689✔
227
                                      &command.parameterBuffer,
228
                                      &command.parameterSize);
229
            if(result != TPM_RC_SUCCESS)
5,689✔
230
                goto Cleanup;
4✔
231
            // Perform sanity check on the unmarshaled value. If it is smaller than
232
            // the smallest possible session or larger than the remaining size of
233
            // the command, then it is an error. NOTE: This check could pass but the
234
            // session size could still be wrong. That will be determined after the
235
            // sessions are unmarshaled.
236
            if(command.authSize < 9
5,685✔
237
               || command.authSize > command.parameterSize)
5,669✔
238
                {
239
                    result = TPM_RC_SIZE;
24✔
240
                    goto Cleanup;
24✔
241
                }
242
            command.parameterSize -= command.authSize;
5,661✔
243
            // The actions of ParseSessionBuffer() are described in the introduction.
244
            // As the sessions are parsed command.parameterBuffer is advanced so, on a
245
            // successful return, command.parameterBuffer should be pointing at the
246
            // first byte of the parameters.
247
            result = ParseSessionBuffer(&command);
5,661✔
248
            if(result != TPM_RC_SUCCESS)
5,661✔
249
                goto Cleanup;
275✔
250
        }
251
    else
252
        {
253
            command.authSize = 0;
9,662✔
254
            // The command has no authorization sessions.
255
            // If the command requires authorizations, then CheckAuthNoSession() will
256
            // return an error.
257
            result = CheckAuthNoSession(&command);
9,662✔
258
            if(result != TPM_RC_SUCCESS)
9,662✔
259
                goto Cleanup;
24✔
260
        }
261
    // Set up the response buffer pointers. CommandDispatch will marshal the
262
    // response parameters starting at the address in command.responseBuffer.
263
    //    *response = MemoryGetResponseBuffer(command.index);
264
    // leave space for the command header
265
    command.responseBuffer = *response + STD_RESPONSE_HEADER;
15,024✔
266
    // leave space for the parameter size field if needed
267
    if(command.tag == TPM_ST_SESSIONS)
15,024✔
268
        command.responseBuffer += sizeof(UINT32);
5,386✔
269
    if(IsHandleInResponse(command.index))
15,024✔
270
        command.responseBuffer += sizeof(TPM_HANDLE);
2,486✔
271
    // CommandDispatcher returns a response handle buffer and a response parameter
272
    // buffer if it succeeds. It will also set the parameterSize field in the
273
    // buffer if the tag is TPM_RC_SESSIONS.
274
    result = CommandDispatcher(&command);
15,024✔
275
    if(result != TPM_RC_SUCCESS)
15,024✔
276
        goto Cleanup;
1,890✔
277
    // Build the session area at the end of the parameter area.
278
    BuildResponseSession(&command);
13,134✔
279
 Cleanup:
16,292✔
280
    if(g_clearOrderly == TRUE
16,292✔
281
       && NV_IS_ORDERLY)
433✔
282
        {
283
#if USE_DA_USED
284
            gp.orderlyState = g_daUsed ? SU_DA_USED_VALUE : SU_NONE_VALUE;
2✔
285
#else
286
            gp.orderlyState = SU_NONE_VALUE;
287
#endif
288
            NV_SYNC_PERSISTENT(orderlyState);
2✔
289
        }
290
    // This implementation loads an "evict" object to a transient object slot in
291
    // RAM whenever an "evict" object handle is used in a command so that the
292
    // access to any object is the same. These temporary objects need to be
293
    // cleared from RAM whether the command succeeds or fails.
294
    ObjectCleanupEvict();
16,292✔
295
    // The parameters and sessions have been marshaled. Now tack on the header and
296
    // set the sizes
297
    BuildResponseHeader(&command, *response, result);
16,292✔
298
    // Try to commit all the writes to NV if any NV write happened during this
299
    // command execution. This check should be made for both succeeded and failed
300
    // commands, because a failed one may trigger a NV write in DA logic as well.
301
    // This is the only place in the command execution path that may call the NV
302
    // commit. If the NV commit fails, the TPM should be put in failure mode.
303
    if((g_updateNV != UT_NONE) && !g_inFailureMode)
16,292✔
304
        {
305
            if(g_updateNV == UT_ORDERLY)
6,200✔
306
                NvUpdateIndexOrderlyData();
11✔
307
            if(!NvCommit())
6,200✔
UNCOV
308
                FAIL(FATAL_ERROR_INTERNAL);
×
309
            g_updateNV = UT_NONE;
6,200✔
310
        }
311
    pAssert((UINT32)command.parameterSize <= maxResponse);
16,292✔
312
    // Clear unused bits in response buffer.
313
    MemorySet(*response + *responseSize, 0, maxResponse - *responseSize);
16,292✔
314
    // as a final act, and not before, update the response size.
315
    *responseSize = (UINT32)command.parameterSize;
16,292✔
316
    return;
16,292✔
317
}
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