Coverage Report

Created: 2025-08-03 06:18

/src/libtpms/src/tpm2/CommandDispatcher.c
Line
Count
Source (jump to first uncovered line)
1
/********************************************************************************/
2
/*                    */
3
/*         Command Dispatcher           */
4
/*           Written by Ken Goldman       */
5
/*           IBM Thomas J. Watson Research Center     */
6
/*            $Id: CommandDispatcher.c 1658 2021-01-22 23:14:01Z 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 - 2021       */
59
/*                    */
60
/********************************************************************************/
61
62
//* Includes and Typedefs
63
#include "Tpm.h"
64
#include "Marshal.h"
65
66
#if TABLE_DRIVEN_DISPATCH || TABLE_DRIVEN_MARSHAL
67
68
typedef TPM_RC(NoFlagFunction)(void* target, BYTE** buffer, INT32* size);
69
typedef TPM_RC(FlagFunction)(void* target, BYTE** buffer, INT32* size, BOOL flag);
70
71
typedef FlagFunction* UNMARSHAL_t;
72
73
typedef INT16(MarshalFunction)(void* source, BYTE** buffer, INT32* size);
74
typedef MarshalFunction* MARSHAL_t;
75
76
typedef TPM_RC(COMMAND_NO_ARGS)(void);
77
typedef TPM_RC(COMMAND_IN_ARG)(void* in);
78
typedef TPM_RC(COMMAND_OUT_ARG)(void* out);
79
typedef TPM_RC(COMMAND_INOUT_ARG)(void* in, void* out);
80
81
typedef union COMMAND_t
82
{
83
    COMMAND_NO_ARGS*   noArgs;
84
    COMMAND_IN_ARG*    inArg;
85
    COMMAND_OUT_ARG*   outArg;
86
    COMMAND_INOUT_ARG* inOutArg;
87
} COMMAND_t;
88
89
// This structure is used by ParseHandleBuffer() and CommandDispatcher(). The
90
// parameters in this structure are unique for each command. The parameters are:
91
// command      holds the address of the command processing function that is called
92
//              by Command Dispatcher
93
// inSize       This is the size of the command-dependent input structure. The
94
//              input structure holds the unmarshaled handles and command
95
//              parameters. If the command takes no arguments (handles or
96
//              parameters) then inSize will have a value of 0.
97
// outSize      This is the size of the command-dependent output structure. The
98
//              output structure holds the results of the command in an unmarshaled
99
//              form. When command processing is completed, these values are
100
//              marshaled into the output buffer. It is always the case that the
101
//              unmarshaled version of an output structure is larger then the
102
//              marshaled version. This is because the marshaled version contains
103
//              the exact same number of significant bytes but with padding removed.
104
// typesOffsets    This parameter points to the list of data types that are to be
105
//              marshaled or unmarshaled. The list of types follows the 'offsets'
106
//              array. The offsets array is variable sized so the typesOffset filed
107
//              is necessary for the handle and command processing to be able to
108
//              find the types that are being handled. The 'offsets' array may be
109
//              empty. The 'types' structure is described below.
110
// offsets      This is an array of offsets of each of the parameters in the
111
//              command or response. When processing the command parameters (not
112
//              handles) the list contains the offset of the next parameter. For
113
//              example, if the first command parameter has a size of 4 and there is
114
//              a second command parameter, then the offset would be 4, indicating
115
//              that the second parameter starts at 4. If the second parameter has
116
//              a size of 8, and there is a third parameter, then the second entry
117
//              in offsets is 12 (4 for the first parameter and 8 for the second).
118
//              An offset value of 0 in the list indicates the start of the response
119
//              parameter list. When CommandDispatcher hits this value, it will stop
120
//              unmarshaling the parameters and call 'command'. If a command has no
121
//              response parameters and only one command parameter, then offsets can
122
//              be an empty list.
123
124
typedef struct COMMAND_DESCRIPTOR_t
125
{
126
    COMMAND_t command;      // Address of the command
127
    UINT16    inSize;       // Maximum size of the input structure
128
    UINT16    outSize;      // Maximum size of the output structure
129
    UINT16    typesOffset;  // address of the types field
130
    UINT16    offsets[1];
131
} COMMAND_DESCRIPTOR_t;
132
133
// The 'types' list is an encoded byte array. The byte value has two parts. The most
134
// significant bit is used when a parameter takes a flag and indicates if the flag
135
// should be SET or not. The remaining 7 bits are an index into an array of
136
// addresses of marshaling and unmarshaling functions.
137
// The array of functions is divided into 6 sections with a value assigned
138
// to denote the start of that section (and the end of the previous section). The
139
// defined offset values for each section are:
140
// 0                                unmarshaling for handles that do not take flags
141
// HANDLE_FIRST_FLAG_TYPE           unmarshaling for handles that take flags
142
// PARAMETER_FIRST_TYPE             unmarshaling for parameters that do not take flags
143
// PARAMETER_FIRST_FLAG_TYPE        unmarshaling for parameters that take flags
144
// PARAMETER_LAST_TYPE + 1          marshaling for handles
145
// RESPONSE_PARAMETER_FIRST_TYPE    marshaling for parameters
146
// RESPONSE_PARAMETER_LAST_TYPE     is the last value in the list of marshaling and
147
//                                  unmarshaling functions.
148
//
149
// The types list is constructed with a byte of 0xff at the end of the command
150
// parameters and with an 0xff at the end of the response parameters.
151
152
#  if COMPRESSED_LISTS
153
#    define PAD_LIST 0
154
#  else
155
#    define PAD_LIST 1
156
#  endif
157
#  define _COMMAND_TABLE_DISPATCH_
158
#  include "CommandDispatchData.h"
159
160
#  define TEST_COMMAND TPM_CC_Startup
161
162
#  define NEW_CC
163
164
#else
165
166
#  include "Commands.h"
167
168
#endif
169
170
//* Marshal/Unmarshal Functions
171
172
//** ParseHandleBuffer()
173
// This is the table-driven version of the handle buffer unmarshaling code
174
TPM_RC
175
ParseHandleBuffer(COMMAND* command)
176
14.4k
{
177
14.4k
    TPM_RC result;
178
14.4k
#if TABLE_DRIVEN_DISPATCH || TABLE_DRIVEN_MARSHAL
179
14.4k
    COMMAND_DESCRIPTOR_t* desc;
180
14.4k
    BYTE*                 types;
181
14.4k
    BYTE                  type;
182
14.4k
    BYTE                  dType;
183
184
    // Make sure that nothing strange has happened
185
14.4k
    pAssert(
186
14.4k
        command->index < sizeof(s_CommandDataArray) / sizeof(COMMAND_DESCRIPTOR_t*));
187
    // Get the address of the descriptor for this command
188
14.4k
    desc = s_CommandDataArray[command->index];
189
190
14.4k
    pAssert(desc != NULL);
191
    // Get the associated list of unmarshaling data types.
192
14.4k
    types = &((BYTE*)desc)[desc->typesOffset];
193
194
    //    if(s_ccAttr[commandIndex].commandIndex == TEST_COMMAND)
195
    //        commandIndex = commandIndex;
196
    // No handles yet
197
14.4k
    command->handleNum = 0;
198
199
    // Get the first type value
200
14.4k
    for(type = *types++;
201
        // check each byte to make sure that we have not hit the start
202
        // of the parameters
203
16.6k
        (dType = (type & 0x7F)) < PARAMETER_FIRST_TYPE;
204
        // get the next type
205
14.4k
        type = *types++)
206
3.87k
    {
207
#  if TABLE_DRIVEN_MARSHAL
208
        marshalIndex_t index;
209
        index  = unmarshalArray[dType] | ((type & 0x80) ? NULL_FLAG : 0);
210
        result = Unmarshal(index,
211
                           &(command->handles[command->handleNum]),
212
                           &command->parameterBuffer,
213
                           &command->parameterSize);
214
215
#  else
216
        // See if unmarshaling of this handle type requires a flag
217
3.87k
        if(dType < HANDLE_FIRST_FLAG_TYPE)
218
1.69k
        {
219
            // Look up the function to do the unmarshaling
220
1.69k
            NoFlagFunction* f = (NoFlagFunction*)unmarshalArray[dType];
221
            // call it
222
1.69k
            result = f(&(command->handles[command->handleNum]),
223
1.69k
                       &command->parameterBuffer,
224
1.69k
                       &command->parameterSize);
225
1.69k
        }
226
2.17k
        else
227
2.17k
        {
228
            //  Look up the function
229
2.17k
            FlagFunction* f = unmarshalArray[dType];
230
231
            // Call it setting the flag to the appropriate value
232
2.17k
            result = f(&(command->handles[command->handleNum]),
233
2.17k
                       &command->parameterBuffer,
234
2.17k
                       &command->parameterSize,
235
2.17k
                       (type & 0x80) != 0);
236
2.17k
        }
237
3.87k
#  endif
238
239
        // Got a handle
240
        // We do this first so that the match for the handle offset of the
241
        // response code works correctly.
242
3.87k
        command->handleNum += 1;
243
3.87k
        if(result != TPM_RC_SUCCESS)
244
            // if the unmarshaling failed, return the response code with the
245
            // handle indication set
246
1.60k
            return result + TPM_RC_H + (command->handleNum * TPM_RC_1);
247
3.87k
    }
248
#else
249
    BYTE**      handleBufferStart   = &command->parameterBuffer;
250
    INT32*      bufferRemainingSize = &command->parameterSize;
251
    TPM_HANDLE* handles             = &command->handles[0];
252
    UINT32*     handleCount         = &command->handleNum;
253
    *handleCount                    = 0;
254
    switch(command->code)
255
    {
256
#  include "HandleProcess.h"
257
#  undef handles
258
        default:
259
            FAIL(FATAL_ERROR_INTERNAL);
260
            break;
261
    }
262
#endif
263
12.8k
    return TPM_RC_SUCCESS;
264
14.4k
}
265
266
//** CommandDispatcher()
267
// Function to unmarshal the command parameters, call the selected action code, and
268
// marshal the response parameters.
269
TPM_RC
270
CommandDispatcher(COMMAND* command)
271
12.3k
{
272
#if !TABLE_DRIVEN_DISPATCH || TABLE_DRIVEN_MARSHAL
273
    TPM_RC      result;
274
    BYTE**      paramBuffer     = &command->parameterBuffer;
275
    INT32*      paramBufferSize = &command->parameterSize;
276
    BYTE**      responseBuffer  = &command->responseBuffer;
277
    INT32*      respParmSize    = &command->parameterSize;
278
    INT32       rSize;
279
    TPM_HANDLE* handles = &command->handles[0];
280
    //
281
    command->handleNum = 0;           // The command-specific code knows how
282
                                      // many handles there are. This is for
283
                                      // cataloging the number of response
284
                                      // handles
285
    MemoryIoBufferAllocationReset();  // Initialize so that allocation will
286
                                      // work properly
287
    switch(GetCommandCode(command->index))
288
    {
289
#  include "CommandDispatcher.h"
290
291
        default:
292
            FAIL(FATAL_ERROR_INTERNAL);
293
            break;
294
    }
295
Exit:
296
    MemoryIoBufferZero();
297
    return result;
298
#else
299
12.3k
    COMMAND_DESCRIPTOR_t* desc;
300
12.3k
    BYTE*                 types;
301
12.3k
    BYTE                  type;
302
12.3k
    UINT16*               offsets;
303
12.3k
    UINT16                offset = 0;
304
12.3k
    UINT32                maxInSize;
305
12.3k
    BYTE*                 commandIn;
306
12.3k
    INT32                 maxOutSize;
307
12.3k
    BYTE*                 commandOut;
308
12.3k
    COMMAND_t             cmd;
309
12.3k
    TPM_HANDLE*           handles;
310
12.3k
    UINT32                hasInParameters  = 0;
311
12.3k
    BOOL                  hasOutParameters = FALSE;
312
12.3k
    UINT32                pNum             = 0;
313
12.3k
    BYTE                  dType;  // dispatch type
314
12.3k
    TPM_RC                result;
315
    //
316
    // Get the address of the descriptor for this command
317
12.3k
    pAssert(
318
12.3k
        command->index < sizeof(s_CommandDataArray) / sizeof(COMMAND_DESCRIPTOR_t*));
319
12.3k
    desc = s_CommandDataArray[command->index];
320
321
    // Get the list of parameter types for this command
322
12.3k
    pAssert(desc != NULL);
323
12.3k
    types = &((BYTE*)desc)[desc->typesOffset];
324
325
    // Get a pointer to the list of parameter offsets
326
12.3k
    offsets = &desc->offsets[0];
327
    // pointer to handles
328
12.3k
    handles = command->handles;
329
330
    // Get the size required to hold all the unmarshaled parameters for this command
331
12.3k
    maxInSize = desc->inSize;
332
    // and the size of the output parameter structure returned by this command
333
12.3k
    maxOutSize = desc->outSize;
334
335
12.3k
    MemoryIoBufferAllocationReset();
336
    // Get a buffer for the input parameters
337
12.3k
    commandIn = MemoryGetInBuffer(maxInSize);
338
    // And the output parameters
339
12.3k
    commandOut = (BYTE*)MemoryGetOutBuffer((UINT32)maxOutSize);
340
341
    // Get the address of the action code dispatch
342
12.3k
    cmd = desc->command;
343
344
    // Copy any handles into the input buffer
345
14.2k
    for(type = *types++; (type & 0x7F) < PARAMETER_FIRST_TYPE; type = *types++)
346
1.88k
    {
347
        // 'offset' was initialized to zero so the first unmarshaling will always
348
        // be to the start of the data structure
349
1.88k
        *(TPM_HANDLE*)&(commandIn[offset]) = *handles++;
350
        // This check is used so that we don't have to add an additional offset
351
        // value to the offsets list to correspond to the stop value in the
352
        // command parameter list.
353
1.88k
        if(*types != 0xFF)
354
1.87k
            offset = *offsets++;
355
        //        maxInSize -= sizeof(TPM_HANDLE);
356
1.88k
        hasInParameters++;
357
1.88k
    }
358
    // Exit loop with type containing the last value read from types
359
    // maxInSize has the amount of space remaining in the command action input
360
    // buffer. Make sure that we don't have more data to unmarshal than is going to
361
    // fit.
362
363
    // type contains the last value read from types so it is not necessary to
364
    // reload it, which is good because *types now points to the next value
365
28.7k
    for(; (dType = (type & 0x7F)) <= PARAMETER_LAST_TYPE; type = *types++)
366
17.9k
    {
367
17.9k
        pNum++;
368
#  if TABLE_DRIVEN_MARSHAL
369
        {
370
            marshalIndex_t index = unmarshalArray[dType];
371
            index |= (type & 0x80) ? NULL_FLAG : 0;
372
            result = Unmarshal(index,
373
                               &commandIn[offset],
374
                               &command->parameterBuffer,
375
                               &command->parameterSize);
376
        }
377
#  else
378
17.9k
        if(dType < PARAMETER_FIRST_FLAG_TYPE)
379
15.9k
        {
380
15.9k
            NoFlagFunction* f = (NoFlagFunction*)unmarshalArray[dType];
381
15.9k
            result            = f(&commandIn[offset],
382
15.9k
                       &command->parameterBuffer,
383
15.9k
                       &command->parameterSize);
384
15.9k
        }
385
2.06k
        else
386
2.06k
        {
387
2.06k
            FlagFunction* f = unmarshalArray[dType];
388
2.06k
            result          = f(&commandIn[offset],
389
2.06k
                       &command->parameterBuffer,
390
2.06k
                       &command->parameterSize,
391
2.06k
                       (type & 0x80) != 0);
392
2.06k
        }
393
17.9k
#  endif
394
17.9k
        if(result != TPM_RC_SUCCESS)
395
1.60k
        {
396
1.60k
            result += TPM_RC_P + (TPM_RC_1 * pNum);
397
1.60k
            goto Exit;
398
1.60k
        }
399
        // This check is used so that we don't have to add an additional offset
400
        // value to the offsets list to correspond to the stop value in the
401
        // command parameter list.
402
16.3k
        if(*types != 0xFF)
403
5.67k
            offset = *offsets++;
404
16.3k
        hasInParameters++;
405
16.3k
    }
406
    // Should have used all the bytes in the input
407
10.7k
    if(command->parameterSize != 0)
408
55
    {
409
55
        result = TPM_RC_SIZE;
410
55
        goto Exit;
411
55
    }
412
413
    // The command parameter unmarshaling stopped when it hit a value that was out
414
    // of range for unmarshaling values and left *types pointing to the first
415
    // marshaling type. If that type happens to be the STOP value, then there
416
    // are no response parameters. So, set the flag to indicate if there are
417
    // output parameters.
418
10.6k
    hasOutParameters = *types != 0xFF;
419
420
    // There are four cases for calling, with and without input parameters and with
421
    // and without output parameters.
422
10.6k
    if(hasInParameters > 0)
423
10.6k
    {
424
10.6k
        if(hasOutParameters)
425
2.78k
            result = cmd.inOutArg(commandIn, commandOut);
426
7.88k
        else
427
7.88k
            result = cmd.inArg(commandIn);
428
10.6k
    }
429
2
    else
430
2
    {
431
2
        if(hasOutParameters)
432
2
            result = cmd.outArg(commandOut);
433
0
        else
434
0
            result = cmd.noArgs();
435
2
    }
436
10.6k
    if(result != TPM_RC_SUCCESS)
437
778
        goto Exit;
438
439
    // Offset in the marshaled output structure
440
9.89k
    offset = 0;
441
442
    // Process the return handles, if any
443
9.89k
    command->handleNum = 0;
444
445
    // Could make this a loop to process output handles but there is only ever
446
    // one handle in the outputs (for now).
447
9.89k
    type = *types++;
448
9.89k
    if((dType = (type & 0x7F)) < RESPONSE_PARAMETER_FIRST_TYPE)
449
767
    {
450
        // The out->handle value was referenced as TPM_HANDLE in the
451
        // action code so it has to be properly aligned.
452
767
        command->handles[command->handleNum++] =
453
767
            *((TPM_HANDLE*)&(commandOut[offset]));
454
767
        maxOutSize -= sizeof(UINT32);
455
767
        type   = *types++;
456
767
        offset = *offsets++;
457
767
    }
458
    // Use the size of the command action output buffer as the maximum for the
459
    // number of bytes that can get marshaled. Since the marshaling code has
460
    // no pointers to data, all of the data being returned has to be in the
461
    // command action output buffer. If we try to marshal more bytes than
462
    // could fit into the output buffer, we need to fail.
463
14.3k
    for(; (dType = (type & 0x7F)) <= RESPONSE_PARAMETER_LAST_TYPE && !g_inFailureMode;
464
9.89k
        type = *types++)
465
4.43k
    {
466
#  if TABLE_DRIVEN_MARSHAL
467
        marshalIndex_t index = marshalArray[dType];
468
        command->parameterSize += Marshal(
469
            index, &commandOut[offset], &command->responseBuffer, &maxOutSize);
470
#  else
471
4.43k
        const MARSHAL_t f = marshalArray[dType];
472
473
4.43k
        command->parameterSize +=
474
4.43k
            f(&commandOut[offset], &command->responseBuffer, &maxOutSize);
475
4.43k
#  endif
476
4.43k
        offset = *offsets++;
477
4.43k
    }
478
9.89k
    result = (maxOutSize < 0) ? TPM_RC_FAILURE : TPM_RC_SUCCESS;
479
12.3k
Exit:
480
12.3k
    MemoryIoBufferZero();
481
12.3k
    return result;
482
9.89k
#endif
483
9.89k
}