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

stefanberger / swtpm / #2905

16 Mar 2026 08:52PM UTC coverage: 73.216%. Remained the same
#2905

push

travis-ci

web-flow
Merge 8ab773bdc into 4a9949609

13 of 20 new or added lines in 4 files covered. (65.0%)

77 existing lines in 3 files now uncovered.

7728 of 10555 relevant lines covered (73.22%)

10184.45 hits per line

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

82.16
/src/swtpm/ctrlchannel.c
1
/*
2
 * ctrlchannel.c -- control channel implementation
3
 *
4
 * (c) Copyright IBM Corporation 2015.
5
 *
6
 * Author: Stefan Berger <stefanb@us.ibm.com>
7
 *
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions are
12
 * met:
13
 *
14
 * Redistributions of source code must retain the above copyright notice,
15
 * this list of conditions and the following disclaimer.
16
 *
17
 * Redistributions in binary form must reproduce the above copyright
18
 * notice, this list of conditions and the following disclaimer in the
19
 * documentation and/or other materials provided with the distribution.
20
 *
21
 * Neither the names of the IBM Corporation nor the names of its
22
 * contributors may be used to endorse or promote products derived from
23
 * this software without specific prior written permission.
24
 *
25
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
 */
37

38
#include "config.h"
39

40
#include <errno.h>
41
#include <string.h>
42
#include <stdlib.h>
43
#include <sys/socket.h>
44
#include <stdint.h>
45
#include <stddef.h>
46
#include <time.h>
47
#include <poll.h>
48

49
#include <libtpms/tpm_library.h>
50
#include <libtpms/tpm_error.h>
51
#include <libtpms/tpm_tis.h>
52
#include <libtpms/tpm_memory.h>
53

54
#include "sys_dependencies.h"
55
#include "ctrlchannel.h"
56
#include "logging.h"
57
#include "tpm_ioctl.h"
58
#include "tpmlib.h"
59
#include "swtpm_nvstore.h"
60
#include "locality.h"
61
#include "mainloop.h"
62
#include "utils.h"
63
#include "swtpm_debug.h"
64
#include "swtpm_utils.h"
65

66
/* local variables */
67

68
struct ctrlchannel {
69
    int fd;
70
    int clientfd;
71
    char *sockpath;
72
};
73

74
struct ctrlchannel *ctrlchannel_new(int fd, bool is_client,
443✔
75
                                    const char *sockpath)
76
{
77
    struct ctrlchannel *cc = calloc(1, sizeof(struct ctrlchannel));
443✔
78

79
    if (!cc) {
443✔
80
        logprintf(STDERR_FILENO, "Out of memory");
×
81
        return NULL;
×
82
    }
83

84
    if (sockpath) {
443✔
85
        cc->sockpath = strdup(sockpath);
151✔
86
        if (!cc->sockpath) {
151✔
87
            logprintf(STDERR_FILENO, "Out of memory");
×
88
            free(cc);
×
89
            return NULL;
×
90
        }
91
    }
92

93
    cc->fd = cc->clientfd = -1;
443✔
94
    if (is_client)
443✔
95
        cc->clientfd = fd;
152✔
96
    else
97
        cc->fd = fd;
291✔
98

99
    return cc;
100
}
101

102
int ctrlchannel_get_fd(struct ctrlchannel *cc)
432✔
103
{
104
    if (!cc)
432✔
105
        return -1;
106

107
    return cc->fd;
429✔
108
}
109

110
int ctrlchannel_get_client_fd(struct ctrlchannel *cc)
432✔
111
{
112
    if (!cc)
432✔
113
        return -1;
114

115
    return cc->clientfd;
429✔
116
}
117

118
int ctrlchannel_set_client_fd(struct ctrlchannel *cc, int fd)
432✔
119
{
120
    int clientfd;
432✔
121

122
    if (!cc)
432✔
123
        return -1;
124

125
    clientfd = cc->clientfd;
429✔
126
    cc->clientfd = fd;
429✔
127

128
    return clientfd;
429✔
129
}
130

131
static int ctrlchannel_return_state(ptm_getstate *pgs, int fd,
56✔
132
                                    struct mainLoopParams *mlp)
133
{
134
    uint32_t blobtype = be32toh(pgs->u.req.type);
56✔
135
    const char *blobname;
56✔
136
    uint32_t tpm_number = 0;
56✔
137
    unsigned char *blob = NULL;
56✔
138
    uint32_t blob_length = 0, return_length;
56✔
139
    TPM_BOOL is_encrypted = 0;
56✔
140
    TPM_BOOL decrypt =
56✔
141
        (be32toh(pgs->u.req.state_flags) & PTM_STATE_FLAG_DECRYPTED) != 0;
56✔
142
    TPM_RESULT res = 0;
56✔
143
    uint32_t offset = be32toh(pgs->u.req.offset);
56✔
144
    ptm_getstate pgs_res;
56✔
145
    uint32_t state_flags;
56✔
146
    struct iovec iov[2];
56✔
147
    int iovcnt, n;
56✔
148

149
    blobname = tpmlib_get_blobname(blobtype);
56✔
150
    if (!blobname)
56✔
151
        res = TPM_FAIL;
×
152

153
    if (res == 0 && blobtype == PTM_BLOB_TYPE_VOLATILE)
56✔
154
        res = SWTPM_NVRAM_Store_Volatile();
30✔
155

156
    if (res == 0)
56✔
157
        res = SWTPM_NVRAM_GetStateBlob(&blob, &blob_length,
56✔
158
                                       tpm_number, blobname, decrypt,
159
                                       &is_encrypted);
160

161
    /* make sure the volatile state file is gone */
162
    if (blobtype == PTM_BLOB_TYPE_VOLATILE)
56✔
163
        SWTPM_NVRAM_DeleteName(tpm_number, blobname, FALSE);
30✔
164

165
    if (offset < blob_length) {
56✔
166
        return_length = blob_length - offset;
53✔
167
    } else {
168
        return_length = 0;
169
    }
170

171
    state_flags = (is_encrypted) ? PTM_STATE_FLAG_ENCRYPTED : 0;
56✔
172
    pgs_res.u.resp.tpm_result = htobe32(res);
56✔
173
    pgs_res.u.resp.state_flags = htobe32(state_flags);
56✔
174
    pgs_res.u.resp.totlength = htobe32(return_length);
56✔
175
    pgs_res.u.resp.length = htobe32(return_length);
56✔
176

177
    iov[0].iov_base = &pgs_res;
56✔
178
    iov[0].iov_len = offsetof(ptm_getstate, u.resp.data);
56✔
179
    iovcnt = 1;
56✔
180

181
    SWTPM_PrintAll(" Ctrl Rsp:", " ", iov[0].iov_base, iov[0].iov_len);
56✔
182

183
    if (res == 0 && return_length) {
56✔
184
        iov[1].iov_base = &blob[offset];
53✔
185
        iov[1].iov_len = return_length;
53✔
186
        iovcnt = 2;
53✔
187

188
        SWTPM_PrintAll(" Ctrl Rsp Continued:", " ",
53✔
189
                       iov[1].iov_base, min(iov[1].iov_len, 1024));
53✔
190
    }
191

192
    n = writev_full(fd, iov, iovcnt);
56✔
193
    if (n < 0) {
56✔
194
        logprintf(STDERR_FILENO,
×
195
                  "Error: Could not send response: %s\n", strerror(errno));
×
196
        close(fd);
×
197
        fd = -1;
×
198
    }
199

200
    free(blob);
56✔
201

202
    if (fd >= 0 && blobtype == PTM_BLOB_TYPE_SAVESTATE)
56✔
203
        mainloop_unlock_nvram(mlp, DEFAULT_LOCKING_RETRIES);
7✔
204

205
    return fd;
56✔
206
}
207

208
static int ctrlchannel_receive_state(ptm_setstate *pss, ssize_t n, int fd)
63✔
209
{
210
    uint32_t blobtype = be32toh(pss->u.req.type);
63✔
211
    uint32_t tpm_number = 0;
63✔
212
    unsigned char *blob = NULL;
63✔
213
    uint32_t blob_length = be32toh(pss->u.req.length);
63✔
214
    uint32_t remain = blob_length, offset = 0;
63✔
215
    TPM_RESULT res;
63✔
216
    uint32_t flags = be32toh(pss->u.req.state_flags);
63✔
217
    TPM_BOOL is_encrypted = (flags & PTM_STATE_FLAG_ENCRYPTED) != 0;
63✔
218

219
    if (blob_length > 512 * 1024) {
63✔
NEW
220
        logprintf(STDERR_FILENO,
×
221
                  "Unreasonable large state of %u bytes.\n", blob_length);
NEW
222
        res = TPM_FAIL;
×
NEW
223
        goto err_send_resp;
×
224
    }
225

226
    blob = malloc(blob_length);
63✔
227
    if (!blob) {
63✔
UNCOV
228
        logprintf(STDERR_FILENO,
×
229
                  "Could not allocate %u bytes.\n", blob_length);
230
        res = TPM_FAIL;
×
UNCOV
231
        goto err_send_resp;
×
232
    }
233

234
    n -= offsetof(ptm_setstate, u.req.data);
63✔
235
    /* n holds the number of available data bytes */
236

237
    while (true) {
114✔
238
        if (n < 0 || (uint32_t)n > remain) {
114✔
UNCOV
239
            res = TPM_BAD_PARAMETER;
×
UNCOV
240
            goto err_send_resp;
×
241
        }
242
        memcpy(&blob[offset], pss->u.req.data, n);
114✔
243
        offset += n;
114✔
244
        remain -= n;
114✔
245
        if (remain) {
114✔
246
            n = read_eintr(fd, pss->u.req.data, sizeof(pss->u.req.data));
51✔
247
            if (n < 0) {
51✔
UNCOV
248
                close(fd);
×
UNCOV
249
                fd = -1;
×
UNCOV
250
                goto err_fd_broken;
×
251
            } else if (n == 0) {
51✔
UNCOV
252
                res = TPM_BAD_PARAMETER;
×
UNCOV
253
                goto err_send_resp;
×
254
            }
255
        } else {
256
            break;
257
        }
258
    }
259

260
    res = SWTPM_NVRAM_SetStateBlob(blob, blob_length, is_encrypted,
63✔
261
                                   tpm_number, blobtype);
262

263
err_send_resp:
63✔
264
    pss->u.resp.tpm_result = htobe32(res);
63✔
265
    n = write_full(fd, pss, sizeof(pss->u.resp.tpm_result));
63✔
266
    if (n < 0) {
63✔
UNCOV
267
        logprintf(STDERR_FILENO,
×
UNCOV
268
                  "Error: Could not send response: %s\n", strerror(errno));
×
UNCOV
269
        close(fd);
×
UNCOV
270
        fd = -1;
×
271
    }
272

273
err_fd_broken:
63✔
274

275
    free(blob);
63✔
276

277
    return fd;
63✔
278
}
279

280
/* timespec_diff: calculate difference between two timespecs
281
 *
282
 * @end: end time
283
 * @start: start time; must be earlier than @end
284
 * @diff: result
285
 *
286
 * This function will return a negative tv_sec in result, if
287
 * @end is earlier than @start, the time difference otherwise.
288
 */
289
static void timespec_diff(struct timespec *end,
63✔
290
                          struct timespec *start,
291
                          struct timespec *diff)
292
{
293
    diff->tv_nsec = end->tv_nsec - start->tv_nsec;
63✔
294
    diff->tv_sec = end->tv_sec - start->tv_sec;
63✔
295
    if (diff->tv_nsec < 0) {
63✔
296
        diff->tv_nsec += 1E9;
30✔
297
        diff->tv_sec -= 1;
30✔
298
    }
299
}
63✔
300

301
struct input {
302
    uint32_t cmd;
303
    /* ptm_hdata is the largest buffer to receive */
304
    uint8_t body[sizeof(ptm_hdata)];
305
};
306

307
/*
308
 * ctrlchannel_recv_cmd: Receive a command on the control channel
309
 *
310
 * @fd: file descriptor for control channel
311
 * @msg: prepared msghdr struct for receiving data with single
312
 *       msg_iov.
313
 *
314
 * This function returns 0 or a negative number if an error receiving
315
 * the command occurred, including a timeout. In case of success,
316
 * the number of bytes received is returned.
317
 */
318
static ssize_t ctrlchannel_recv_cmd(int fd,
40,783✔
319
                                    struct msghdr *msg)
320
{
321
    ssize_t n;
40,783✔
322
    size_t recvd = 0;
40,783✔
323
    size_t needed = offsetof(struct input, body);
40,783✔
324
    struct input *input = (struct input *)msg->msg_iov[0].iov_base;
40,783✔
325
    struct pollfd pollfd =  {
40,783✔
326
        .fd = fd,
327
        .events = POLLIN,
328
    };
329
    struct timespec deadline, now, timeout;
40,783✔
330
    int to;
40,783✔
331
    size_t buffer_len = msg->msg_iov[0].iov_len;
40,783✔
332
    /* Read-write */
333
    ptm_init *init_p;
40,783✔
334
    ptm_reset_est *pre;
40,783✔
335
    ptm_hdata *phd;
40,783✔
336
    ptm_getstate *pgs;
40,783✔
337
    ptm_setstate *pss;
40,783✔
338
    ptm_loc *pl;
40,783✔
339
    const void *msg_iov = msg->msg_iov;
40,783✔
340

341
    clock_gettime(CLOCK_REALTIME, &deadline);
40,783✔
342

343
    /* maximum allowed time is 500ms to receive everything */
344
    deadline.tv_nsec += 500 * 1E6;
40,783✔
345
    if (deadline.tv_nsec >= 1E9) {
40,783✔
346
        deadline.tv_nsec -= 1E9;
20,836✔
347
        deadline.tv_sec += 1;
20,836✔
348
    }
349

350
    while (recvd < buffer_len) {
40,846✔
351
        if (!recvd) {
40,817✔
352
            n = recvmsg(fd, msg, 0);
40,783✔
353
            /* address a coverity issue by validating msg */
354
            if (msg_iov != msg->msg_iov ||
40,783✔
355
                msg->msg_iov[0].iov_base != input ||
40,783✔
356
                msg->msg_iov[0].iov_len > buffer_len)
40,783✔
357
                return -1;
358
        } else
359
            n = read_eintr(fd, (char *)msg->msg_iov[0].iov_base + recvd,
34✔
360
                           buffer_len - recvd);
361
        if (n <= 0)
40,817✔
362
            return n;
18,555✔
363
        /* recvd += n; will never overflow due to buffer_len upper bound */
364
        if (__builtin_add_overflow(recvd, n, &recvd)) {
22,262✔
UNCOV
365
            errno = EOVERFLOW;
×
UNCOV
366
            return -1;
×
367
        }
368
        /* we need to at least see the cmd */
369
        if (recvd < offsetof(struct input, body))
22,262✔
UNCOV
370
            goto wait_chunk;
×
371

372
        switch (be32toh(input->cmd)) {
22,262✔
373
        case CMD_GET_CAPABILITY:
374
            break;
375
        case CMD_INIT:
9,059✔
376
            needed = offsetof(struct input, body) +
9,059✔
377
                     sizeof(init_p->u.req);
378
            break;
9,059✔
379
        case CMD_SHUTDOWN:
380
            break;
381
        case CMD_GET_TPMESTABLISHED:
382
            break;
383
        case CMD_SET_LOCALITY:
57✔
384
            needed = offsetof(struct input, body) +
57✔
385
                     sizeof(pl->u.req);
386
            break;
57✔
387
        case CMD_HASH_START:
388
            break;
389
        case CMD_HASH_DATA:
3,131✔
390
            needed = offsetof(struct input, body) +
3,131✔
391
                     offsetof(struct ptm_hdata, u.req.data);
392
            if (recvd >= needed) {
3,131✔
393
                phd = (struct ptm_hdata *)&input->body;
3,131✔
394
                needed += be32toh(phd->u.req.length);
3,131✔
395
            }
396
            break;
397
        case CMD_HASH_END:
398
            break;
399
        case CMD_CANCEL_TPM_CMD:
400
            break;
401
        case CMD_STORE_VOLATILE:
402
            break;
403
        case CMD_RESET_TPMESTABLISHED:
26✔
404
            needed = offsetof(struct input, body) +
26✔
405
                     sizeof(pre->u.req);
406
            break;
26✔
407
        case CMD_GET_STATEBLOB:
56✔
408
            needed = offsetof(struct input, body) +
56✔
409
                     sizeof(pgs->u.req);
410
            break;
56✔
411
        case CMD_SET_STATEBLOB:
97✔
412
            needed = offsetof(struct input, body) +
97✔
413
                     offsetof(struct ptm_setstate, u.req.data);
414
            if (recvd >= needed) {
97✔
415
                pss = (struct ptm_setstate *)&input->body;
97✔
416
                needed += be32toh(pss->u.req.length);
97✔
417
            }
418
            break;
419
        case CMD_STOP:
420
            break;
421
        case CMD_GET_CONFIG:
422
            break;
423
        case CMD_SET_BUFFERSIZE:
424
            break;
425
        }
426

427
        if (recvd >= needed)
22,262✔
428
            break;
429

430
wait_chunk:
63✔
431
        clock_gettime(CLOCK_REALTIME, &now);
63✔
432
        timespec_diff(&deadline, &now, &timeout);
63✔
433

434
        if (timeout.tv_sec < 0)
63✔
435
            break;
436
        to = timeout.tv_sec * 1000 + timeout.tv_nsec / 1E6;
63✔
437

438
        /* wait for the next chunk */
439
        while (true) {
63✔
440
            n = poll(&pollfd, 1, to);
63✔
441
            if (n < 0 && errno == EINTR)
63✔
UNCOV
442
                continue;
×
443
            if (n <= 0)
63✔
UNCOV
444
                return n;
×
445
            break;
446
        }
447
        /* we should have data now */
448
    }
449
    return recvd;
22,228✔
450
}
451

452
static uint32_t get_ptm_caps_supported(TPMLIB_TPMVersion tpmversion)
12✔
453
{
454
    uint32_t caps =
12✔
455
              PTM_CAP_INIT
456
            | PTM_CAP_SHUTDOWN
457
            | PTM_CAP_GET_TPMESTABLISHED
458
            | PTM_CAP_SET_LOCALITY
459
            | PTM_CAP_HASHING
460
            | PTM_CAP_CANCEL_TPM_CMD
461
            | PTM_CAP_STORE_VOLATILE
462
            | PTM_CAP_RESET_TPMESTABLISHED
463
            | PTM_CAP_GET_STATEBLOB
464
            | PTM_CAP_SET_STATEBLOB
465
            | PTM_CAP_STOP
466
            | PTM_CAP_GET_CONFIG
467
#ifndef __CYGWIN__
468
            | PTM_CAP_SET_DATAFD
469
#endif
470
            | PTM_CAP_SET_BUFFERSIZE
471
            | PTM_CAP_GET_INFO
472
            | PTM_CAP_LOCK_STORAGE;
473
    if (tpmversion == TPMLIB_TPM_VERSION_2)
12✔
474
        caps |= PTM_CAP_SEND_COMMAND_HEADER;
5✔
475

476
    return caps;
12✔
477
}
478

479
/*
480
 * ctrlchannel_process_fd: Read command from control channel and execute it
481
 *
482
 * @fd: file descriptor for control channel
483
 * @terminate: pointer to a boolean that will be set to true by this
484
 *             function in case the process should shut down; CMD_SHUTDOWN
485
 *             will set this
486
 * @locality: pointer to locality identifier that must point to the global
487
 *            locality variable and that will receive the new locality
488
 *            number when set via CMD_SET_LOCALITY
489
 * @tpm_running: indicates whether the TPM is running; may be changed by
490
 *               this function in case TPM is stopped or started
491
 * @mlp: mainloop parameters used; may be altered by this function in case of
492
 *       CMD_SET_DATAFD
493
 *
494
 * This function returns the passed file descriptor or -1 in case the
495
 * file descriptor was closed.
496
 */
497
int ctrlchannel_process_fd(int fd,
40,783✔
498
                           bool *terminate,
499
                           TPM_MODIFIER_INDICATOR *locality,
500
                           bool *tpm_running,
501
                           struct mainLoopParams *mlp)
502
{
503
    struct input input = {0, };
40,783✔
504
    struct output {
40,783✔
505
        uint8_t body[sizeof(struct ptm_hdata)]; /* ptm_hdata is largest */
506
    } output;
507
    ssize_t n;
40,783✔
508
    struct iovec iov = {
40,783✔
509
        .iov_base = &input,
510
        .iov_len = sizeof(input),
511
    };
512
    char control[CMSG_SPACE(sizeof(int))];
40,783✔
513
    struct msghdr msg = {
40,783✔
514
        .msg_iov = &iov,
515
        .msg_iovlen = 1,
516
        .msg_control = control,
517
        .msg_controllen = sizeof(control),
518
    };
519
    struct cmsghdr *cmsg = NULL;
40,783✔
520
    int *data_fd = NULL;
40,783✔
521

522
    /* Write-only */
523
    ptm_cap_n *ptm_caps_n = (ptm_cap_n *)&output.body;
40,783✔
524
    ptm_res *res_p = (ptm_res *)&output.body;
40,783✔
525
    ptm_est *te = (ptm_est *)&output.body;
40,783✔
526
    ptm_getconfig *pgc = (ptm_getconfig *)&output.body;
40,783✔
527
    /* Read-write */
528
    ptm_init *init_p;
40,783✔
529
    ptm_reset_est *re;
40,783✔
530
    ptm_hdata *data;
40,783✔
531
    ptm_getstate *pgs;
40,783✔
532
    ptm_setstate *pss;
40,783✔
533
    ptm_loc *pl;
40,783✔
534
    ptm_setbuffersize *psbs;
40,783✔
535
    ptm_getinfo *pgi, _pgi;
40,783✔
536
    ptm_lockstorage *pls;
40,783✔
537

538
    size_t out_len = 0;
40,783✔
539
    TPM_RESULT res;
40,783✔
540
    uint32_t remain;
40,783✔
541
    uint32_t buffersize, maxsize, minsize;
40,783✔
542
    uint64_t info_flags;
40,783✔
543
    uint32_t offset;
40,783✔
544
    char *info_data = NULL;
40,783✔
545
    size_t length;
40,783✔
546
    TPM_MODIFIER_INDICATOR orig_locality;
40,783✔
547

548
    if (fd < 0)
40,783✔
549
        return -1;
550

551
    n = ctrlchannel_recv_cmd(fd, &msg);
40,783✔
552
    if (n <= 0) {
40,783✔
553
        goto err_socket;
18,555✔
554
    }
555

556
    SWTPM_PrintAll(" Ctrl Cmd:", " ", msg.msg_iov->iov_base, min(n, 1024));
22,228✔
557

558
    if ((size_t)n < sizeof(input.cmd)) {
22,228✔
UNCOV
559
        goto err_bad_input;
×
560
    }
561

562
    n -= sizeof(input.cmd);
22,228✔
563

564
    switch (be32toh(input.cmd)) {
22,228✔
565
    case CMD_GET_CAPABILITY:
566
        /* must always succeed */
567
        ptm_caps_n->u.resp.tpm_result = htobe32(TPM_SUCCESS);
12✔
568
        ptm_caps_n->u.resp.caps = htobe32(get_ptm_caps_supported(mlp->tpmversion));
17✔
569

570
        out_len = sizeof(*ptm_caps_n);
12✔
571
        break;
12✔
572

573
    case CMD_INIT:
9,059✔
574
        if (n != (ssize_t)sizeof(ptm_init)) /* r/w */
9,059✔
UNCOV
575
            goto err_bad_input;
×
576

577
        if (*tpm_running && !mlp->disable_auto_shutdown)
9,059✔
578
            tpmlib_maybe_send_tpm2_shutdown(mlp->tpmversion,
8,850✔
579
                                            &mlp->lastCommand, &mlp->ps);
580

581
        init_p = (ptm_init *)input.body;
9,059✔
582

583
        TPMLIB_Terminate();
9,059✔
584

585
        *tpm_running = false;
9,059✔
586

587
        mlp->storage_locked = !mlp->incoming_migration;
9,059✔
588

589
        res = tpmlib_start(be32toh(init_p->u.req.init_flags),
18,118✔
590
                           mlp->tpmversion, mlp->storage_locked,
591
                           mlp->json_profile);
9,059✔
592
        if (res) {
9,059✔
593
            logprintf(STDERR_FILENO,
12✔
594
                      "Error: Could not initialize the TPM\n");
595
        } else {
596
            *tpm_running = true;
9,047✔
597
            SWTPM_G_FREE(mlp->json_profile);
9,047✔
598
        }
599

600
        *res_p = htobe32(res);
9,059✔
601
        out_len = sizeof(ptm_res);
9,059✔
602
        break;
9,059✔
603

604
    case CMD_STOP:
42✔
605
        if (n != 0) /* wo */
42✔
UNCOV
606
            goto err_bad_input;
×
607

608
        if (*tpm_running && !mlp->disable_auto_shutdown)
42✔
609
            tpmlib_maybe_send_tpm2_shutdown(mlp->tpmversion,
24✔
610
                                            &mlp->lastCommand,
611
                                            &mlp->ps);
612

613
        TPMLIB_Terminate();
42✔
614

615
        *tpm_running = false;
42✔
616

617
        *res_p = htobe32(TPM_SUCCESS);
42✔
618
        out_len = sizeof(ptm_res);
42✔
619
        break;
42✔
620

621
    case CMD_SHUTDOWN:
422✔
622
        if (n != 0) /* wo */
422✔
UNCOV
623
            goto err_bad_input;
×
624

625
        if (*tpm_running && !mlp->disable_auto_shutdown)
422✔
626
            tpmlib_maybe_send_tpm2_shutdown(mlp->tpmversion,
395✔
627
                                            &mlp->lastCommand,
628
                                            &mlp->ps);
629

630
        TPMLIB_Terminate();
422✔
631

632
        *tpm_running = false;
422✔
633

634
        *res_p = htobe32(TPM_SUCCESS);
422✔
635
        out_len = sizeof(ptm_res);
422✔
636

637
        *terminate = true;
422✔
638
        break;
422✔
639

640
    case CMD_GET_TPMESTABLISHED:
72✔
641
        if (!*tpm_running)
72✔
642
            goto err_not_running;
6✔
643

644
        if (n != 0) /* wo */
66✔
UNCOV
645
            goto err_bad_input;
×
646

647
        out_len = sizeof(te->u.resp);
66✔
648
        memset(output.body, 0, out_len);
66✔
649

650
        res = htobe32(TPM_IO_TpmEstablished_Get(&te->u.resp.bit));
66✔
651
        te->u.resp.tpm_result = res;
66✔
652

653
        break;
66✔
654

655
    case CMD_RESET_TPMESTABLISHED:
26✔
656
        if (!*tpm_running)
26✔
UNCOV
657
            goto err_not_running;
×
658

659
        if (n < (ssize_t)sizeof(re->u.req.loc)) /* rw */
26✔
UNCOV
660
            goto err_bad_input;
×
661

662
        re = (ptm_reset_est *)input.body;
26✔
663

664
        if (re->u.req.loc > 4) {
26✔
665
            res = htobe32(TPM_BAD_LOCALITY);
666
        } else {
667
            orig_locality = *locality;
26✔
668
            *locality = re->u.req.loc;
26✔
669

670
            res = htobe32(TPM_IO_TpmEstablished_Reset());
26✔
671

672
            *locality = orig_locality;
26✔
673
        }
674

675
        *res_p = res;
26✔
676
        out_len = sizeof(re->u.resp);
26✔
677
        break;
26✔
678

679
    case CMD_SET_LOCALITY:
57✔
680
        if (n < (ssize_t)sizeof(pl->u.req.loc)) /* rw */
57✔
UNCOV
681
            goto err_bad_input;
×
682

683
        pl = (ptm_loc *)input.body;
57✔
684
        if (pl->u.req.loc > 4 ||
57✔
685
            (pl->u.req.loc == 4 &&
6✔
686
             mlp->locality_flags & LOCALITY_FLAG_REJECT_LOCALITY_4)) {
6✔
687
            res = TPM_BAD_LOCALITY;
688
        } else {
689
            res = TPM_SUCCESS;
57✔
690
            *locality = pl->u.req.loc;
57✔
691
        }
692

693
        *res_p = htobe32(res);
57✔
694
        out_len = sizeof(re->u.resp);
57✔
695
        break;
57✔
696

697
    case CMD_HASH_START:
57✔
698
        if (!*tpm_running)
57✔
UNCOV
699
            goto err_not_running;
×
700

701
        if (n != 0) /* wo */
57✔
UNCOV
702
            goto err_bad_input;
×
703

704
        *res_p = htobe32(TPM_IO_Hash_Start());
57✔
705
        out_len = sizeof(ptm_res);
57✔
706

707
        break;
57✔
708

709
    case CMD_HASH_DATA:
3,131✔
710
        if (!*tpm_running)
3,131✔
UNCOV
711
            goto err_not_running;
×
712

713
        if (n < (ssize_t)offsetof(ptm_hdata, u.req.data)) /* rw */
3,131✔
UNCOV
714
            goto err_bad_input;
×
715

716
        data = (ptm_hdata *)&input.body;
3,131✔
717
        remain = be32toh(data->u.req.length);
3,131✔
718
        n -= sizeof(data->u.req.length);
3,131✔
719
        if (n < 0 || remain < (uint32_t)n)
3,131✔
UNCOV
720
            goto err_bad_input;
×
721
        /* n has the available number of bytes to hash */
722

723
        while (true) {
3,131✔
724
            res = TPM_IO_Hash_Data(data->u.req.data, n);
3,131✔
725
            if (res)
3,131✔
726
                break;
727
            remain -= n;
3,131✔
728
            if (!remain)
3,131✔
729
                break;
730

UNCOV
731
            n = read_eintr(fd, &data->u.req.data, sizeof(data->u.req.data));
×
UNCOV
732
            if (n <= 0) {
×
733
                res = TPM_IOERROR;
734
                break;
735
            }
736
        }
737

738
        data = (ptm_hdata *)&output.body;
3,131✔
739

740
        data->u.resp.tpm_result = htobe32(res);
3,131✔
741
        out_len = sizeof(data->u.resp.tpm_result);
3,131✔
742

743
        break;
3,131✔
744

745
    case CMD_HASH_END:
57✔
746
        if (!*tpm_running)
57✔
UNCOV
747
            goto err_not_running;
×
748

749
        if (n != 0) /* wo */
57✔
UNCOV
750
            goto err_bad_input;
×
751

752
        *res_p = htobe32(TPM_IO_Hash_End());
57✔
753
        out_len = sizeof(ptm_res);
57✔
754

755
        break;
57✔
756

757
    case CMD_CANCEL_TPM_CMD:
×
UNCOV
758
        if (!*tpm_running)
×
UNCOV
759
            goto err_not_running;
×
760

UNCOV
761
        if (n != 0) /* wo */
×
UNCOV
762
            goto err_bad_input;
×
763

764
        /* for cancellation to work, the TPM would have to
765
         * execute in another thread that polls on a cancel
766
         * flag
767
         */
768
        *res_p = htobe32(TPMLIB_CancelCommand());
×
769
        out_len = sizeof(ptm_res);
×
UNCOV
770
        break;
×
771

772
    case CMD_STORE_VOLATILE:
8,841✔
773
        if (!*tpm_running)
8,841✔
UNCOV
774
            goto err_not_running;
×
775

776
        if (n != 0) /* wo */
8,841✔
777
            goto err_bad_input;
×
778

779
        *res_p = htobe32(SWTPM_NVRAM_Store_Volatile());
8,841✔
780
        out_len = sizeof(ptm_res);
8,841✔
781
        break;
8,841✔
782

783
    case CMD_GET_STATEBLOB:
56✔
784
        if (!*tpm_running)
56✔
UNCOV
785
            goto err_not_running;
×
786

787
        pgs = (ptm_getstate *)input.body;
56✔
788
        if (n < (ssize_t)sizeof(pgs->u.req)) /* rw */
56✔
UNCOV
789
            goto err_bad_input;
×
790

791
        return ctrlchannel_return_state(pgs, fd, mlp);
56✔
792

793
    case CMD_SET_STATEBLOB:
63✔
794
        if (*tpm_running)
63✔
UNCOV
795
            goto err_running;
×
796

797
        /* tpm state dir must be set */
798
        SWTPM_NVRAM_Init();
63✔
799
        if ((*terminate = !mainloop_ensure_locked_storage(mlp)))
63✔
UNCOV
800
            goto err_io;
×
801

802
        pss = (ptm_setstate *)input.body;
63✔
803
        if (n < (ssize_t)offsetof(ptm_setstate, u.req.data)) /* rw */
63✔
UNCOV
804
            goto err_bad_input;
×
805

806
        return ctrlchannel_receive_state(pss, n, fd);
63✔
807

808
    case CMD_GET_CONFIG:
17✔
809
        if (n != 0) /* wo */
17✔
UNCOV
810
            goto err_bad_input;
×
811

812
        pgc->u.resp.tpm_result = htobe32(0);
17✔
813
        pgc->u.resp.flags = htobe32(0);
17✔
814
        if (SWTPM_NVRAM_Has_FileKey())
17✔
815
            pgc->u.resp.flags |= htobe32(PTM_CONFIG_FLAG_FILE_KEY);
6✔
816
        if (SWTPM_NVRAM_Has_MigrationKey())
17✔
817
            pgc->u.resp.flags |= htobe32(PTM_CONFIG_FLAG_MIGRATION_KEY);
6✔
818

819
        out_len = sizeof(pgc->u.resp);
820
        break;
821

822
    case CMD_SET_DATAFD:
2✔
823
#ifdef __CYGWIN__
824
        if (1)
825
            goto err_running;
826
#endif
827
        if (mlp->fd != -1)
2✔
UNCOV
828
            goto err_io;
×
829

830
        cmsg = CMSG_FIRSTHDR(&msg);
2✔
831
        if (!cmsg || cmsg->cmsg_len < CMSG_LEN(sizeof(int)) ||
2✔
832
             cmsg->cmsg_level != SOL_SOCKET ||
2✔
833
             cmsg->cmsg_type != SCM_RIGHTS ||
834
             !(data_fd = (int *)CMSG_DATA(cmsg)) ||
2✔
835
             *data_fd < 0) {
2✔
UNCOV
836
            logprintf(STDERR_FILENO, "no valid data socket in message; cmsg = "
×
837
                                     "%p", cmsg);
UNCOV
838
            goto err_bad_input;
×
839
        }
840

841
        mlp->flags |= MAIN_LOOP_FLAG_USE_FD | MAIN_LOOP_FLAG_KEEP_CONNECTION;
2✔
842
        mlp->fd = *data_fd;
2✔
843

844
        *res_p = htobe32(TPM_SUCCESS);
2✔
845
        out_len = sizeof(ptm_res);
2✔
846
        break;
2✔
847

848
    case CMD_SET_BUFFERSIZE:
18✔
849
        psbs = (ptm_setbuffersize *)input.body;
18✔
850
        if (n < (ssize_t)sizeof(psbs->u.req)) /* rw */
18✔
UNCOV
851
            goto err_bad_input;
×
852

853
        buffersize = be32toh(psbs->u.req.buffersize);
18✔
854

855
        if (buffersize > 0 && *tpm_running)
18✔
856
            goto err_running;
6✔
857

858
        buffersize = TPMLIB_SetBufferSize(buffersize,
12✔
859
                                          &minsize,
860
                                          &maxsize);
861

862
        *res_p = htobe32(TPM_SUCCESS);
12✔
863

864
        psbs = (ptm_setbuffersize *)&output.body;
12✔
865
        out_len = sizeof(psbs->u.resp);
12✔
866

867
        psbs->u.resp.buffersize = htobe32(buffersize);
12✔
868
        psbs->u.resp.minsize = htobe32(minsize);
12✔
869
        psbs->u.resp.maxsize = htobe32(maxsize);
12✔
870

871
        break;
12✔
872

873
    case CMD_GET_INFO:
265✔
874
        if (n < (ssize_t)sizeof(pgi->u.req)) /* rw */
265✔
UNCOV
875
            goto err_bad_input;
×
876

877
        /* copy since flags needs to be 8-byte aligned  */
878
        memcpy(&_pgi, input.body, sizeof(_pgi));
265✔
879
        pgi = &_pgi;
265✔
880

881
        info_flags = be64toh(pgi->u.req.flags);
265✔
882

883
        info_data = TPMLIB_GetInfo(info_flags);
265✔
884
        if (!info_data)
265✔
UNCOV
885
            goto err_memory;
×
886

887
        offset = be32toh(pgi->u.req.offset);
265✔
888
        if (offset >= strlen(info_data)) {
265✔
UNCOV
889
            free(info_data);
×
UNCOV
890
            goto err_bad_input;
×
891
        }
892

893
        length = min(strlen(info_data) + 1 - offset,
265✔
894
                     sizeof(pgi->u.resp.buffer));
895

896
        pgi = (ptm_getinfo *)&output.body;
265✔
897
        pgi->u.resp.tpm_result = htobe32(0);
265✔
898
        pgi->u.resp.totlength = htobe32(strlen(info_data) + 1);
265✔
899
        pgi->u.resp.length = htobe32(length);
265✔
900
        /* client has to collect whole string in case buffer is too small */
901
        memcpy(pgi->u.resp.buffer, &info_data[offset], length);
265✔
902
        free(info_data);
265✔
903

904
        out_len = offsetof(ptm_getinfo, u.resp.buffer) + length;
265✔
905

906
        break;
265✔
907

908
    case CMD_LOCK_STORAGE:
30✔
909
        if (n < (ssize_t)sizeof(pls->u.req)) /* rw */
30✔
UNCOV
910
            goto err_bad_input;
×
911

912
        pls = (ptm_lockstorage *)input.body;
30✔
913

914
        mlp->locking_retries = be32toh(pls->u.req.retries);
30✔
915

916
        pls = (ptm_lockstorage *)&output.body;
30✔
917
        out_len = sizeof(pls->u.resp);
30✔
918

919
        if (!mainloop_ensure_locked_storage(mlp))
30✔
UNCOV
920
            pls->u.resp.tpm_result = htobe32(TPM_FAIL);
×
921
        else
922
            pls->u.resp.tpm_result = htobe32(TPM_SUCCESS);
30✔
923

924
        break;
925

926
    default:
1✔
927
        logprintf(STDERR_FILENO,
1✔
928
                  "Error: Unknown command: 0x%08x\n", be32toh(input.cmd));
929

930
        *res_p = htobe32(TPM_BAD_ORDINAL);
1✔
931
        out_len = sizeof(ptm_res);
1✔
932
    }
933

934
send_resp:
22,109✔
935
    SWTPM_PrintAll(" Ctrl Rsp:", " ", output.body, min(out_len, 1024));
22,109✔
936

937
    n = write_full(fd, output.body, out_len);
22,109✔
938
    if (n < 0) {
22,109✔
UNCOV
939
        logprintf(STDERR_FILENO,
×
UNCOV
940
                  "Error: Could not send response: %s\n", strerror(errno));
×
UNCOV
941
        close(fd);
×
UNCOV
942
        fd = -1;
×
943
    }
944

945
    return fd;
946

947
err_bad_input:
×
948
    *res_p = htobe32(TPM_BAD_PARAMETER);
×
949
    out_len = sizeof(ptm_res);
×
950

UNCOV
951
    goto send_resp;
×
952

953
err_running:
12✔
954
err_not_running:
12✔
955
    *res_p = htobe32(TPM_BAD_ORDINAL);
12✔
956
    out_len = sizeof(ptm_res);
12✔
957

958
    goto send_resp;
12✔
959

UNCOV
960
err_io:
×
UNCOV
961
    *res_p = htobe32(TPM_IOERROR);
×
UNCOV
962
    out_len = sizeof(ptm_res);
×
963

UNCOV
964
    goto send_resp;
×
965

UNCOV
966
err_memory:
×
967
    *res_p = htobe32(TPM_SIZE);
×
968
    out_len = sizeof(ptm_res);
×
969

UNCOV
970
    goto send_resp;
×
971

972
err_socket:
18,555✔
973
    close(fd);
18,555✔
974

975
    return -1;
18,555✔
976
}
977

978
void ctrlchannel_free(struct ctrlchannel *cc)
638✔
979
{
980
    if (!cc)
638✔
981
        return;
982

983
    if (cc->fd >= 0)
443✔
984
        close(cc->fd);
291✔
985
    if (cc->clientfd >= 0)
443✔
986
        close(cc->clientfd);
7✔
987
    if (cc->sockpath) {
443✔
988
        unlink(cc->sockpath);
151✔
989
        free(cc->sockpath);
151✔
990
    }
991
    free(cc);
443✔
992
}
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