Coverage Report

Created: 2025-10-28 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tpm2/ExecCommand.c
Line
Count
Source
1
// This file was extracted from the TCG Published
2
// Trusted Platform Module Library
3
// Part 4: Supporting Routines
4
// Family "2.0"
5
// Level 00 Revision 01.16
6
// October 30, 2014
7
8
#include     "InternalRoutines.h"
9
#include     "ExecCommand_fp.h"
10
#include     "HandleProcess_fp.h"
11
#include     "SessionProcess_fp.h"
12
#include     "CommandDispatcher_fp.h"
13
//
14
//     Uncomment this next #include if doing static command/response buffer sizing
15
//
16
// #include "CommandResponseSizes_fp.h"
17
//
18
//
19
//           ExecuteCommand()
20
//
21
//     The function performs the following steps.
22
//     a) Parses the command header from input buffer.
23
//     b) Calls ParseHandleBuffer() to parse the handle area of the command.
24
//     c) Validates that each of the handles references a loaded entity.
25
//
26
//     d) Calls ParseSessionBuffer() () to:
27
//          1) unmarshal and parse the session area;
28
//          2) check the authorizations; and
29
//          3) when necessary, decrypt a parameter.
30
//     e) Calls CommandDispatcher() to:
31
//          1) unmarshal the command parameters from the command buffer;
32
//          2) call the routine that performs the command actions; and
33
//          3) marshal the responses into the response buffer.
34
//     f)   If any error occurs in any of the steps above create the error response and return.
35
//     g) Calls BuildResponseSession() to:
36
//          1) when necessary, encrypt a parameter
37
//          2) build the response authorization sessions
38
//          3) update the audit sessions and nonces
39
//     h) Assembles handle, parameter and session buffers for response and return.
40
//
41
LIB_EXPORT void
42
ExecuteCommand(
43
    unsigned    int      requestSize,       //   IN: command buffer size
44
    unsigned    char    *request,           //   IN: command buffer
45
    unsigned    int     *responseSize,      //   OUT: response buffer size
46
    unsigned    char    **response          //   OUT: response buffer
47
    )
48
456
{
49
    // Command local variables
50
456
    TPM_ST               tag;                         // these first three variables are the
51
456
    UINT32               commandSize;
52
456
    TPM_CC               commandCode = 0;
53
456
    BYTE                     *parmBufferStart;        // pointer to the first byte of an
54
                                                      // optional parameter buffer
55
456
    UINT32                    parmBufferSize = 0;// number of bytes in parameter area
56
456
    UINT32                    handleNum = 0;          // number of handles unmarshaled into
57
                                                      // the handles array
58
456
    TPM_HANDLE                handles[MAX_HANDLE_NUM];// array to hold handles in the
59
                                                 // command. Only handles in the handle
60
                                                 // area are stored here, not handles
61
                                                 // passed as parameters.
62
    // Response local variables
63
456
    TPM_RC               result;                      // return code for the command
64
456
    TPM_ST                    resTag;                 // tag for the response
65
456
    UINT32                    resHandleSize = 0; //       size of the handle area in the
66
                                                 //       response. This is needed so that the
67
                                                 //       handle area can be skipped when
68
                                                 //       generating the rpHash.
69
456
    UINT32                    resParmSize = 0;        // the size of the response parameters
70
                                                      // These values go in the rpHash.
71
456
    UINT32                    resAuthSize = 0;        // size of authorization area in the
72
//
73
                                                   // response
74
456
   INT32                      size;                // remaining data to be unmarshaled
75
                                                   // or remaining space in the marshaling
76
                                                   // buffer
77
456
   BYTE                      *buffer;              // pointer into the buffer being used
78
                                                   // for marshaling or unmarshaling
79
456
   INT32                      bufferSize;          // size of buffer being used for
80
                                                   // marshaling or unmarshaling
81
456
   UINT32                     i;                    // local temp
82
// This next function call is used in development to size the command and response
83
// buffers. The values printed are the sizes of the internal structures and
84
// not the sizes of the canonical forms of the command response structures. Also,
85
// the sizes do not include the tag, commandCode, requestSize, or the authorization
86
// fields.
87
//CommandResponseSizes();
88
   // Set flags for NV access state. This should happen before any other
89
   // operation that may require a NV write. Note, that this needs to be done
90
   // even when in failure mode. Otherwise, g_updateNV would stay SET while in
91
   // Failure mode and the NB would be written on each call.
92
456
   g_updateNV = FALSE;
93
456
   g_clearOrderly = FALSE;
94
   // As of Sept 25, 2013, the failure mode handling has been incorporated in the
95
   // reference code. This implementation requires that the system support
96
   // setjmp/longjmp. This code is put here because of the complexity being
97
   // added to the platform and simulator code to deal with all the variations
98
   // of errors.
99
456
   if(g_inFailureMode)
100
0
   {
101
       // Do failure mode processing
102
0
       TpmFailureMode (requestSize, request, responseSize, response);
103
0
       return;
104
0
   }
105
456
#ifndef EMBEDDED_MODE
106
456
   if(setjmp(g_jumpBuffer) != 0)
107
0
   {
108
       // Get here if we got a longjump putting us into failure mode
109
0
       g_inFailureMode = TRUE;
110
0
       result = TPM_RC_FAILURE;
111
0
       goto Fail;
112
0
   }
113
456
#endif  // EMBEDDED_MODE   ^^^ not defined
114
   // Assume that everything is going to work.
115
456
   result = TPM_RC_SUCCESS;
116
   // Query platform to get the NV state. The result state is saved internally
117
   // and will be reported by NvIsAvailable(). The reference code requires that
118
   // accessibility of NV does not change during the execution of a command.
119
   // Specifically, if NV is available when the command execution starts and then
120
   // is not available later when it is necessary to write to NV, then the TPM
121
   // will go into failure mode.
122
456
   NvCheckState();
123
   // Due to the limitations of the simulation, TPM clock must be explicitly
124
   // synchronized with the system clock whenever a command is received.
125
   // This function call is not necessary in a hardware TPM. However, taking
126
   // a snapshot of the hardware timer at the beginning of the command allows
127
   // the time value to be consistent for the duration of the command execution.
128
456
   TimeUpdateToCurrent();
129
   // Any command through this function will unceremoniously end the
130
   // _TPM_Hash_Data/_TPM_Hash_End sequence.
131
456
   if(g_DRTMHandle != TPM_RH_UNASSIGNED)
132
0
       ObjectTerminateEvent();
133
     // Get command buffer size and command buffer.
134
456
     size = requestSize;
135
456
     buffer = request;
136
     // Parse command header: tag, commandSize and commandCode.
137
     // First parse the tag. The unmarshaling routine will validate
138
     // that it is either TPM_ST_SESSIONS or TPM_ST_NO_SESSIONS.
139
456
     result = TPMI_ST_COMMAND_TAG_Unmarshal(&tag, &buffer, &size);
140
456
     if(result != TPM_RC_SUCCESS)
141
2
         goto Cleanup;
142
     // Unmarshal the commandSize indicator.
143
454
     result = UINT32_Unmarshal(&commandSize, &buffer, &size);
144
454
     if(result != TPM_RC_SUCCESS)
145
0
         goto Cleanup;
146
     // On a TPM that receives bytes on a port, the number of bytes that were
147
     // received on that port is requestSize it must be identical to commandSize.
148
     // In addition, commandSize must not be larger than MAX_COMMAND_SIZE allowed
149
     // by the implementation. The check against MAX_COMMAND_SIZE may be redundant
150
     // as the input processing (the function that receives the command bytes and
151
     // places them in the input buffer) would likely have the input truncated when
152
     // it reaches MAX_COMMAND_SIZE, and requestSize would not equal commandSize.
153
454
     if(commandSize != requestSize || commandSize > MAX_COMMAND_SIZE)
154
14
     {
155
14
         result = TPM_RC_COMMAND_SIZE;
156
14
         goto Cleanup;
157
14
     }
158
     // Unmarshal the command code.
159
440
     result = TPM_CC_Unmarshal(&commandCode, &buffer, &size);
160
440
     if(result != TPM_RC_SUCCESS)
161
2
         goto Cleanup;
162
     // Check to see if the command is implemented.
163
438
     if(!CommandIsImplemented(commandCode))
164
0
     {
165
0
         result = TPM_RC_COMMAND_CODE;
166
0
         goto Cleanup;
167
0
     }
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() && (commandCode != 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
438
        if((    !TPMIsStarted() && commandCode != TPM_CC_Startup)
182
438
             || (TPMIsStarted() && commandCode == TPM_CC_Startup))
183
0
        {
184
0
             result = TPM_RC_INITIALIZE;
185
0
             goto Cleanup;
186
0
        }
187
     // Start regular command process.
188
     // Parse Handle buffer.
189
438
     result = ParseHandleBuffer(commandCode, &buffer, &size, handles, &handleNum);
190
438
     if(result != TPM_RC_SUCCESS)
191
18
        goto Cleanup;
192
   // Number of handles retrieved from handle area should be less than
193
   // MAX_HANDLE_NUM.
194
420
   pAssert(handleNum <= MAX_HANDLE_NUM);
195
   // All handles in the handle area are required to reference TPM-resident
196
   // entities.
197
491
   for(i = 0; i < handleNum; i++)
198
71
   {
199
71
       result = EntityGetLoadStatus(&handles[i], commandCode);
200
71
       if(result != TPM_RC_SUCCESS)
201
0
       {
202
0
           if(result == TPM_RC_REFERENCE_H0)
203
0
               result = result + i;
204
0
           else
205
0
               result = RcSafeAddToResult(result, TPM_RC_H + g_rcIndex[i]);
206
0
           goto Cleanup;
207
0
       }
208
71
   }
209
   // Authorization session handling for the command.
210
420
   if(tag == TPM_ST_SESSIONS)
211
56
   {
212
56
       BYTE        *sessionBufferStart;// address of the session area first byte
213
                                       // in the input buffer
214
56
        UINT32        authorizationSize;   // number of bytes in the session area
215
        // Find out session buffer size.
216
56
        result = UINT32_Unmarshal(&authorizationSize, &buffer, &size);
217
56
        if(result != TPM_RC_SUCCESS)
218
0
            goto Cleanup;
219
        // Perform sanity check on the unmarshaled    value. If it is smaller than
220
        // the smallest possible session or larger    than the remaining size of
221
        // the command, then it is an error. NOTE:    This check could pass but the
222
        // session size could still be wrong. That    will be determined after the
223
        // sessions are unmarshaled.
224
56
        if(    authorizationSize < 9
225
56
            || authorizationSize > (UINT32) size)
226
2
        {
227
2
             result = TPM_RC_SIZE;
228
2
             goto Cleanup;
229
2
        }
230
        // The sessions, if any, follows authorizationSize.
231
54
        sessionBufferStart = buffer;
232
        // The parameters follow the session area.
233
54
        parmBufferStart = sessionBufferStart + authorizationSize;
234
        // Any data left over after removing the authorization sessions is
235
        // parameter data. If the command does not have parameters, then an
236
        // error will be returned if the remaining size is not zero. This is
237
        // checked later.
238
54
        parmBufferSize = size - authorizationSize;
239
        // The actions of ParseSessionBuffer() are described in the introduction.
240
54
        result = ParseSessionBuffer(commandCode,
241
54
                                    handleNum,
242
54
                                    handles,
243
54
                                    sessionBufferStart,
244
54
                                    authorizationSize,
245
54
                                    parmBufferStart,
246
54
                                    parmBufferSize);
247
54
         if(result != TPM_RC_SUCCESS)
248
9
             goto Cleanup;
249
54
   }
250
364
   else
251
364
   {
252
       // Whatever remains in the input buffer is used for the parameters of the
253
       // command.
254
364
       parmBufferStart = buffer;
255
364
       parmBufferSize = size;
256
         // The command has no authorization sessions.
257
         // If the command requires authorizations, then CheckAuthNoSession() will
258
         // return an error.
259
364
         result = CheckAuthNoSession(commandCode, handleNum, handles,
260
364
                                      parmBufferStart, parmBufferSize);
261
364
         if(result != TPM_RC_SUCCESS)
262
1
             goto Cleanup;
263
364
   }
264
   // CommandDispatcher returns a response handle buffer and a response parameter
265
   // buffer if it succeeds. It will also set the parameterSize field in the
266
   // buffer if the tag is TPM_RC_SESSIONS.
267
408
   result = CommandDispatcher(tag,
268
408
                              commandCode,
269
408
                              (INT32 *) &parmBufferSize,
270
408
                              parmBufferStart,
271
408
                              handles,
272
408
                              &resHandleSize,
273
408
                              &resParmSize);
274
408
   if(result != TPM_RC_SUCCESS)
275
170
       goto Cleanup;
276
   // Build the session area at the end of the parameter area.
277
238
   BuildResponseSession(tag,
278
238
                        commandCode,
279
238
                        resHandleSize,
280
238
                        resParmSize,
281
238
                        &resAuthSize);
282
456
Cleanup:
283
   // This implementation loads an "evict" object to a transient object slot in
284
   // RAM whenever an "evict" object handle is used in a command so that the
285
   // access to any object is the same. These temporary objects need to be
286
   // cleared from RAM whether the command succeeds or fails.
287
456
   ObjectCleanupEvict();
288
456
#ifndef EMBEDDED_MODE
289
456
Fail:
290
456
#endif  // EMBEDDED_MODE  ^^^ not defined
291
   // The response will contain at least a response header.
292
456
   *responseSize = sizeof(TPM_ST) + sizeof(UINT32) + sizeof(TPM_RC);
293
   // If the command completed successfully, then build the rest of the response.
294
456
   if(result == TPM_RC_SUCCESS)
295
238
   {
296
       // Outgoing tag will be the same as the incoming tag.
297
238
       resTag = tag;
298
       // The overall response will include the handles, parameters,
299
       // and authorizations.
300
238
       *responseSize += resHandleSize + resParmSize + resAuthSize;
301
         // Adding parameter size field.
302
238
         if(tag == TPM_ST_SESSIONS)
303
8
             *responseSize += sizeof(UINT32);
304
238
         if(      g_clearOrderly == TRUE
305
0
               && gp.orderlyState != SHUTDOWN_NONE)
306
0
         {
307
0
                gp.orderlyState = SHUTDOWN_NONE;
308
0
                NvWriteReserved(NV_ORDERLY, &gp.orderlyState);
309
0
                g_updateNV = TRUE;
310
0
         }
311
238
     }
312
218
     else
313
218
     {
314
         // The command failed.
315
         // If this was a failure due to a bad command tag, then need to return
316
         // a TPM 1.2 compatible response
317
218
         if(result == TPM_RC_BAD_TAG)
318
2
              resTag = TPM_ST_RSP_COMMAND;
319
216
         else
320
              // return 2.0 compatible response
321
216
              resTag = TPM_ST_NO_SESSIONS;
322
218
     }
323
     // Try to commit all the writes to NV if any NV write happened during this
324
     // command execution. This check should be made for both succeeded and failed
325
     // commands, because a failed one may trigger a NV write in DA logic as well.
326
     // This is the only place in the command execution path that may call the NV
327
     // commit. If the NV commit fails, the TPM should be put in failure mode.
328
456
     if(g_updateNV && !g_inFailureMode)
329
228
     {
330
228
         g_updateNV = FALSE;
331
228
         if(!NvCommit()) {
332
0
              FAIL(FATAL_ERROR_INTERNAL);
333
#ifdef EMBEDDED_MODE
334
        // Make sure we pass errors along
335
        result = TPM_RC_FAILURE;
336
        resTag = TPM_ST_NO_SESSIONS;
337
#endif
338
0
   }
339
228
     }
340
     // Marshal the response header.
341
456
     buffer = MemoryGetResponseBuffer(commandCode);
342
456
     bufferSize = 10;
343
456
     TPM_ST_Marshal(&resTag, &buffer, &bufferSize);
344
456
     UINT32_Marshal((UINT32 *)responseSize, &buffer, &bufferSize);
345
456
     pAssert(*responseSize <= MAX_RESPONSE_SIZE);
346
456
     TPM_RC_Marshal(&result, &buffer, &bufferSize);
347
456
     *response = MemoryGetResponseBuffer(commandCode);
348
     // Clear unused bit in response buffer.
349
456
     MemorySet(*response + *responseSize, 0, MAX_RESPONSE_SIZE - *responseSize);
350
456
     return;
351
456
}