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

stefanberger / swtpm / #2824

13 May 2025 12:34PM UTC coverage: 72.964% (-0.5%) from 73.462%
#2824

push

travis-ci

web-flow
Merge c2b02e9b2 into 1544c99ca

7033 of 9639 relevant lines covered (72.96%)

13748.12 hits per line

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

44.64
/src/swtpm/utils.c
1
/*
2
 * utils.s -- utilities
3
 *
4
 * (c) Copyright IBM Corporation 2014, 2015, 2019.
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 <grp.h>
41
#include <pwd.h>
42
#include <fcntl.h>
43
#include <unistd.h>
44
#include <limits.h>
45
#include <stdlib.h>
46
#include <string.h>
47
#include <errno.h>
48

49
#if defined __APPLE__
50
#include <fcntl.h>
51
#include <sys/param.h>
52
#endif
53

54
#include "utils.h"
55
#include "logging.h"
56
#include "tpmlib.h"
57
#include "swtpm_debug.h"
58

59
void uninstall_sighandlers()
287✔
60
{
61
    if (signal(SIGTERM, SIG_DFL) == SIG_ERR)
287✔
62
        logprintf(STDERR_FILENO, "Could not uninstall signal handler for SIGTERM.\n");
×
63

64
    if (signal(SIGPIPE, SIG_DFL) == SIG_ERR)
287✔
65
        logprintf(STDERR_FILENO, "Could not uninstall signal handler for SIGPIPE.\n");
×
66
}
287✔
67

68
int install_sighandlers(int pipefd[2], sighandler_t handler)
287✔
69
{
70
    if (pipe(pipefd) < 0) {
287✔
71
        logprintf(STDERR_FILENO, "Error: Could not open pipe.\n");
×
72
        goto err_exit;
×
73
    }
74

75
    if (signal(SIGTERM, handler) == SIG_ERR) {
287✔
76
        logprintf(STDERR_FILENO, "Could not install signal handler for SIGTERM.\n");
×
77
        goto err_close_pipe;
×
78
    }
79

80
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
287✔
81
        logprintf(STDERR_FILENO, "Could not install signal handler for SIGPIPE.\n");
×
82
        goto err_close_pipe;
×
83
    }
84

85
    return 0;
86

87
err_close_pipe:
×
88
    close(pipefd[0]);
×
89
    pipefd[0] = -1;
×
90
    close(pipefd[1]);
×
91
    pipefd[1] = -1;
×
92

93
err_exit:
94
    return -1;
95
}
96

97
int
98
change_process_owner(const char *user)
×
99
{
100
    struct passwd *passwd;
×
101
    long int uid, gid;
×
102
    char *endptr = NULL;
×
103

104
    uid = strtoul(user, &endptr, 10);
×
105
    if (*endptr != '\0') {
×
106
        /* a string */
107
        passwd = getpwnam(user);
×
108
        if (!passwd) {
×
109
            logprintf(STDERR_FILENO,
×
110
                      "Error: User '%s' does not exist.\n",
111
                      user);
112
            return -14;
×
113
        }
114

115
        if (initgroups(passwd->pw_name, passwd->pw_gid) < 0) {
×
116
            logprintf(STDERR_FILENO,
×
117
                      "Error: initgroups(%s, %d) failed.\n",
118
                      passwd->pw_name, passwd->pw_gid);
119
           return -10;
×
120
        }
121
        gid = passwd->pw_gid;
×
122
        uid = passwd->pw_uid;
×
123
    } else {
124
        /* an integer */
125
        if ((unsigned long int)uid > UINT_MAX) {
×
126
            logprintf(STDERR_FILENO,
×
127
                      "Error: uid %s outside valid range.\n",
128
                      user);
129
            return -13;
×
130
        }
131
        gid = uid;
132
    }
133

134
    if (setgid(gid) < 0) {
×
135
        logprintf(STDERR_FILENO,
×
136
                  "Error: setgid(%d) failed.\n",
137
                  gid);
138
        return -11;
×
139
    }
140
    if (setuid(uid) < 0) {
×
141
        logprintf(STDERR_FILENO,
×
142
                  "Error: setuid(%d) failed.\n",
143
                  uid);
144
        return -12;
×
145
    }
146
    return 0;
147
}
148

149
int
150
do_chroot(const char *path)
×
151
{
152
    if (chroot(path) < 0) {
×
153
        logprintf(STDERR_FILENO, "chroot failed: %s\n",
×
154
                  strerror(errno));
×
155
        return -1;
×
156
    }
157

158
    if (chdir("/") < 0) {
×
159
        logprintf(STDERR_FILENO, "chdir failed: %s\n",
×
160
                  strerror(errno));
×
161
        return -1;
×
162
    }
163
    return 0;
164
}
165

166
void tpmlib_debug_libtpms_parameters(TPMLIB_TPMVersion tpmversion)
287✔
167
{
168
    switch (tpmversion) {
287✔
169
    case TPMLIB_TPM_VERSION_1_2:
170
        TPM_DEBUG("TPM 1.2: Compiled for %u auth, %u transport, "
171
                  "and %u DAA session slots\n",
172
            tpmlib_get_tpm_property(TPMPROP_TPM_MIN_AUTH_SESSIONS),
173
            tpmlib_get_tpm_property(TPMPROP_TPM_MIN_TRANS_SESSIONS),
174
            tpmlib_get_tpm_property(TPMPROP_TPM_MIN_DAA_SESSIONS));
175
        TPM_DEBUG("TPM 1.2: Compiled for %u key slots, %u owner evict slots\n",
176
            tpmlib_get_tpm_property(TPMPROP_TPM_KEY_HANDLES),
177
            tpmlib_get_tpm_property(TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES));
178
        TPM_DEBUG("TPM 1.2: Compiled for %u counters, %u saved sessions\n",
179
            tpmlib_get_tpm_property(TPMPROP_TPM_MIN_COUNTERS),
180
            tpmlib_get_tpm_property(TPMPROP_TPM_MIN_SESSION_LIST));
181
        TPM_DEBUG("TPM 1.2: Compiled for %u family, "
182
                  "%u delegate table entries\n",
183
            tpmlib_get_tpm_property(TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN),
184
            tpmlib_get_tpm_property(TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN));
185
        TPM_DEBUG("TPM 1.2: Compiled for %u total NV, %u savestate, "
186
                  "%u volatile space\n",
187
            tpmlib_get_tpm_property(TPMPROP_TPM_MAX_NV_SPACE),
188
            tpmlib_get_tpm_property(TPMPROP_TPM_MAX_SAVESTATE_SPACE),
189
            tpmlib_get_tpm_property(TPMPROP_TPM_MAX_VOLATILESTATE_SPACE));
190
#if 0
191
        TPM_DEBUG("TPM1.2: Compiled for %u NV defined space\n",
192
            tpmlib_get_tpm_property(TPMPROP_TPM_MAX_NV_DEFINED_SIZE));
193
#endif
194
    break;
195
    case TPMLIB_TPM_VERSION_2:
196
    break;
197
    }
198
}
287✔
199

200
char *fd_to_filename(int fd)
×
201
{
202
#if defined __linux__
203

204
    char buffer[64];
×
205
    char *path;
×
206

207
    snprintf(buffer, sizeof(buffer), "/proc/self/fd/%d", fd);
×
208

209
    path = realpath(buffer, NULL);
×
210
    if (!path) {
×
211
        logprintf(STDERR_FILENO, "Could not read %s: %s\n",
×
212
                  buffer, strerror(errno));
×
213
        return NULL;
×
214
    }
215

216
    return path;
217

218
#elif defined __APPLE__
219

220
    char *path = malloc(MAXPATHLEN);
221
    if (!path) {
222
        logprintf(STDERR_FILENO, "Out of memory.\n");
223
        return NULL;
224
    }
225
    if (fcntl(fd, F_GETPATH, path) < 0) {
226
        logprintf(STDERR_FILENO, "fcntl for F_GETPATH failed: %\n",
227
                  strerror(errno));
228
        free(path);
229
        return NULL;
230
    }
231
    return path;
232

233
#else
234
    (void)fd;
235
    logprintf(STDERR_FILENO,
236
              "Cannot convert file descriptor to filename on this platform.\n");
237
    return NULL;
238

239
#endif
240
}
241

242
/*
243
 * write_full: Write all bytes of a buffer into the file descriptor
244
 *             and handle partial writes on the way.
245
 *
246
 * @fd: file descriptor to write to
247
 * @buffer: buffer
248
 * @buflen: length of buffer
249
 *
250
 * Returns -1 in case not all bytes could be transferred, number of
251
 * bytes written otherwise (must be equal to buflen).
252
 */
253
ssize_t write_full(int fd, const void *buffer, size_t buflen)
80,002✔
254
{
255
    size_t written = 0;
80,002✔
256
    ssize_t n;
80,002✔
257

258
    while (written < buflen) {
160,004✔
259
        n = write(fd, buffer, buflen - written);
80,002✔
260
        if (n == 0)
80,002✔
261
            return -1;
262
        if (n < 0) {
80,002✔
263
            if (errno == EINTR)
×
264
                continue;
×
265
            return -1;
266
        }
267
        written += n;
80,002✔
268
        buffer += n;
80,002✔
269
    }
270
    return written;
80,002✔
271
}
272

273
/*
274
 * writev_full: Write all bytes of an iovec into the file descriptor
275
 *              and handle partial writes on the way.
276
 * @fd: file descriptor to write to
277
 * @iov: pointer to iov
278
 * @iovcnt: length of iov array
279
 *
280
 * Returns -1 in case not all bytes could be transferred, number of
281
 * bytes written otherwise (must be equal to buflen).
282
 */
283
ssize_t writev_full(int fd, const struct iovec *iov, int iovcnt)
20,794✔
284
{
285
    int i;
20,794✔
286
    size_t off;
20,794✔
287
    unsigned char *buf;
20,794✔
288
    ssize_t n;
20,794✔
289
    size_t bytecount = 0;
20,794✔
290
    size_t numbufs = 0;
20,794✔
291
    size_t lastidx = -1;
20,794✔
292

293
    for (i = 0; i < iovcnt; i++) {
83,117✔
294
        if (iov[i].iov_len) {
62,323✔
295
            bytecount += iov[i].iov_len;
31,475✔
296
            numbufs++;
31,475✔
297
            lastidx = i;
31,475✔
298
        }
299
    }
300

301
    if (numbufs == 1)
20,794✔
302
        return write_full(fd, iov[lastidx].iov_base, iov[lastidx].iov_len);
15,427✔
303

304
    buf = malloc(bytecount);
5,367✔
305
    if (!buf) {
5,367✔
306
        errno = ENOMEM;
×
307
        return -1;
×
308
    }
309

310
    off = 0;
311
    for (i = 0; i < iovcnt; i++) {
21,415✔
312
        if (!iov[i].iov_len)
16,048✔
313
            continue;
×
314
        memcpy(&buf[off], iov[i].iov_base, iov[i].iov_len);
16,048✔
315
        off += iov[i].iov_len;
16,048✔
316
    }
317

318
    n = write_full(fd, buf, off);
5,367✔
319

320
    free(buf);
5,367✔
321

322
    return n;
5,367✔
323
}
324

325
/*
326
 * read_einter: Read bytes from a file descriptor into a buffer
327
 *              and handle EINTR. Perform one read().
328
 *
329
 * @fd: file descriptor to read from
330
 * @buffer: buffer
331
 * @buflen: length of buffer
332
 *
333
 * Returns -1 in case an error occurred, number of bytes read otherwise.
334
 */
335
ssize_t read_eintr(int fd, void *buffer, size_t buflen)
225✔
336
{
337
    ssize_t n;
225✔
338

339
    while (true) {
225✔
340
        n = read(fd, buffer, buflen);
225✔
341
        if (n < 0) {
225✔
342
            if (errno == EINTR)
×
343
                continue;
×
344
            return -1;
345
        }
346
        return n;
347
    }
348
}
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