Coverage Report

Created: 2025-11-11 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cryptsetup/lib/utils_keyring.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * kernel keyring utilities
4
 *
5
 * Copyright (C) 2016-2025 Red Hat, Inc. All rights reserved.
6
 * Copyright (C) 2016-2025 Ondrej Kozina
7
 */
8
9
#include <assert.h>
10
#include <ctype.h>
11
#include <errno.h>
12
#include <fcntl.h>
13
#include <stdio.h>
14
#include <stdbool.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <unistd.h>
18
#include <sys/syscall.h>
19
20
#include "libcryptsetup.h"
21
#include "libcryptsetup_macros.h"
22
#include "utils_keyring.h"
23
24
#if KERNEL_KEYRING
25
26
static const struct {
27
  key_type_t type;
28
  const char *type_name;
29
} key_types[] = {
30
  { LOGON_KEY,     "logon" },
31
  { USER_KEY,      "user" },
32
  { BIG_KEY,       "big_key" },
33
  { TRUSTED_KEY,   "trusted" },
34
  { ENCRYPTED_KEY, "encrypted" },
35
};
36
37
#include <linux/keyctl.h>
38
39
/* request_key */
40
static key_serial_t request_key(const char *type,
41
  const char *description,
42
  const char *callout_info,
43
  key_serial_t keyring)
44
0
{
45
0
  return syscall(__NR_request_key, type, description, callout_info, keyring);
46
0
}
47
48
/* add_key */
49
static key_serial_t add_key(const char *type,
50
  const char *description,
51
  const void *payload,
52
  size_t plen,
53
  key_serial_t keyring)
54
0
{
55
0
  return syscall(__NR_add_key, type, description, payload, plen, keyring);
56
0
}
57
58
/* keyctl_describe */
59
static long keyctl_describe(key_serial_t id, char *buffer, size_t buflen)
60
0
{
61
0
  return syscall(__NR_keyctl, KEYCTL_DESCRIBE, id, buffer, buflen);
62
0
}
63
64
/* keyctl_read */
65
static long keyctl_read(key_serial_t key, char *buffer, size_t buflen)
66
0
{
67
0
  return syscall(__NR_keyctl, KEYCTL_READ, key, buffer, buflen);
68
0
}
69
70
/* keyctl_link */
71
static long keyctl_link(key_serial_t key, key_serial_t keyring)
72
0
{
73
0
  return syscall(__NR_keyctl, KEYCTL_LINK, key, keyring);
74
0
}
75
76
/* keyctl_unlink */
77
static long keyctl_unlink(key_serial_t key, key_serial_t keyring)
78
0
{
79
0
  return syscall(__NR_keyctl, KEYCTL_UNLINK, key, keyring);
80
0
}
81
82
/* inspired by keyutils written by David Howells (dhowells@redhat.com) */
83
static key_serial_t keyring_process_proc_keys_line(char *line, const char *type, const char *desc,
84
               key_serial_t destringid)
85
0
{
86
0
  char typebuf[41], rdesc[1024], *kdesc, *cp;
87
0
  int ndesc, n;
88
0
  key_serial_t id;
89
0
  int dlen;
90
91
0
  assert(desc);
92
0
  dlen = strlen(desc);
93
0
  cp = line + strlen(line);
94
95
0
  ndesc = 0;
96
0
  n = sscanf(line, "%x %*s %*u %*s %*x %*d %*d %40s %n",
97
0
      &id, typebuf, &ndesc);
98
0
  if (n == 2 && ndesc > 0 && ndesc <= cp - line) {
99
0
    if (strcmp(typebuf, type) != 0)
100
0
      return 0;
101
0
    kdesc = line + ndesc;
102
0
    if (memcmp(kdesc, desc, dlen) != 0)
103
0
      return 0;
104
0
    if (kdesc[dlen] != ':' &&
105
0
        kdesc[dlen] != '\0' &&
106
0
        kdesc[dlen] != ' ')
107
0
      return 0;
108
0
    kdesc[dlen] = '\0';
109
110
    /* The key type appends extra stuff to the end of the
111
     * description after a colon in /proc/keys.  Colons,
112
     * however, are allowed in descriptions, so we need to
113
     * make a further check. */
114
0
    n = keyctl_describe(id, rdesc, sizeof(rdesc) - 1);
115
0
    if (n < 0)
116
0
      return 0;
117
0
    if ((size_t)n >= sizeof(rdesc) - 1)
118
0
      return 0;
119
0
    rdesc[n] = '\0';
120
121
0
    cp = strrchr(rdesc, ';');
122
0
    if (!cp)
123
0
      return 0;
124
0
    cp++;
125
0
    if (strcmp(cp, desc) != 0)
126
0
      return 0;
127
128
129
0
    if (destringid && keyctl_link(id, destringid) == -1)
130
0
      return 0;
131
132
0
    return id;
133
0
  }
134
135
0
  return 0;
136
0
}
137
138
/* inspired by keyutils written by David Howells (dhowells@redhat.com), returns 0 ID on failure */
139
140
static key_serial_t find_key_by_type_and_desc(const char *type, const char *desc, key_serial_t destringid)
141
0
{
142
0
  key_serial_t id;
143
0
  int f;
144
0
  char buf[1024];
145
0
  char *newline;
146
0
  size_t buffer_len = 0;
147
148
0
  ssize_t n;
149
150
0
  do {
151
0
    id = request_key(type, desc, NULL, 0);
152
0
  } while (id < 0 && errno == EINTR);
153
154
0
  if (id < 0 && errno == ENOMEM)
155
0
    return 0;
156
157
0
  if (id >= 0)
158
0
    return id;
159
160
0
  f = open("/proc/keys", O_RDONLY);
161
0
  if (f < 0)
162
0
    return 0;
163
164
0
  while ((n = read(f, buf + buffer_len, sizeof(buf) - buffer_len - 1)) > 0) {
165
    /* coverity[overflow:FALSE] */
166
0
    buffer_len += (size_t)n;
167
0
    buf[buffer_len] = '\0';
168
0
    newline = strchr(buf, '\n');
169
0
    while (newline != NULL && buffer_len != 0) {
170
0
      *newline = '\0';
171
172
0
      if ((id = keyring_process_proc_keys_line(buf, type, desc, destringid))) {
173
0
        close(f);
174
0
        return id;
175
0
      }
176
177
0
      buffer_len -= newline - buf + 1;
178
0
      if (buffer_len >= sizeof(buf)) {
179
0
        close(f);
180
0
        return 0;
181
0
      }
182
0
      memmove(buf, newline + 1, buffer_len);
183
0
      buf[buffer_len] = '\0';
184
0
      newline = strchr(buf, '\n');
185
0
    }
186
0
  }
187
188
0
  close(f);
189
0
  return 0;
190
0
}
191
192
int keyring_check(void)
193
0
{
194
  /* logon type key descriptions must be in format "prefix:description" */
195
0
  return syscall(__NR_request_key, "logon", "dummy", NULL, 0) == -1l && errno != ENOSYS;
196
0
}
197
198
key_serial_t keyring_add_key_to_keyring(key_type_t ktype,
199
    const char *key_desc,
200
    const void *key,
201
    size_t key_size,
202
    key_serial_t keyring)
203
0
{
204
0
  const char *type_name = key_type_name(ktype);
205
206
0
  if (!type_name || !key_desc)
207
0
    return -EINVAL;
208
209
0
  return add_key(type_name, key_desc, key, key_size, keyring);
210
0
}
211
212
key_serial_t keyring_add_key_in_thread_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
213
0
{
214
0
  return keyring_add_key_to_keyring(ktype, key_desc, key, key_size, KEY_SPEC_THREAD_KEYRING);
215
0
}
216
217
key_serial_t keyring_request_key_id(key_type_t key_type,
218
    const char *key_description)
219
0
{
220
0
  key_serial_t kid;
221
222
0
  do {
223
0
    kid = request_key(key_type_name(key_type), key_description, NULL, 0);
224
0
  } while (kid < 0 && errno == EINTR);
225
226
0
  return kid;
227
0
}
228
229
int keyring_read_keysize(key_serial_t kid,
230
    size_t *r_key_size)
231
0
{
232
0
  long r;
233
234
0
  assert(r_key_size);
235
236
  /* just get payload size */
237
0
  r = keyctl_read(kid, NULL, 0);
238
0
  if (r > 0) {
239
0
    *r_key_size = r;
240
0
    return 0;
241
0
  }
242
243
0
  return -EINVAL;
244
0
}
245
246
int keyring_read_key(key_serial_t kid,
247
    char **key,
248
    size_t *key_size)
249
0
{
250
0
  int r;
251
0
  size_t len;
252
0
  char *buf = NULL;
253
254
0
  assert(key);
255
0
  assert(key_size);
256
257
  /* just get payload size */
258
0
  r = keyring_read_keysize(kid, &len);
259
0
  if (r < 0)
260
0
    return r;
261
262
0
  buf = crypt_safe_alloc(len);
263
0
  if (!buf)
264
0
    return -ENOMEM;
265
266
  /* retrieve actual payload data */
267
0
  r = keyctl_read(kid, buf, len);
268
0
  if (r < 0) {
269
0
    crypt_safe_free(buf);
270
0
    return -EINVAL;
271
0
  }
272
273
0
  *key = buf;
274
0
  *key_size = len;
275
276
0
  return 0;
277
0
}
278
279
int keyring_unlink_key_from_keyring(key_serial_t kid, key_serial_t keyring_id)
280
0
{
281
0
  return keyctl_unlink(kid, keyring_id) < 0 ? -EINVAL : 0;
282
0
}
283
284
int keyring_unlink_key_from_thread_keyring(key_serial_t kid)
285
0
{
286
0
  return keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING) < 0 ? -EINVAL : 0;
287
0
}
288
289
const char *key_type_name(key_type_t type)
290
0
{
291
0
  unsigned int i;
292
293
0
  for (i = 0; i < ARRAY_SIZE(key_types); i++)
294
0
    if (type == key_types[i].type)
295
0
      return key_types[i].type_name;
296
297
0
  return NULL;
298
0
}
299
300
key_type_t keyring_type_and_name(const char *key_name, const char **name)
301
0
{
302
0
  char type[16], *name_tmp;
303
0
  size_t type_len;
304
305
0
  if (!key_name || key_name[0] != '%')
306
0
    return INVALID_KEY;
307
308
0
  key_name++;
309
0
  if (!*key_name || *key_name == ':')
310
0
    return INVALID_KEY;
311
312
0
  name_tmp = strchr(key_name, ':');
313
0
  if (!name_tmp)
314
0
    return INVALID_KEY;
315
0
  name_tmp++;
316
317
0
  type_len = name_tmp - key_name - 1;
318
0
  if (type_len >= sizeof(type) - 1)
319
0
    return INVALID_KEY;
320
321
0
  memcpy(type, key_name, type_len);
322
0
  type[type_len] = '\0';
323
324
0
  if (name)
325
0
    *name = name_tmp;
326
327
0
  return key_type_by_name(type);
328
0
}
329
330
key_serial_t keyring_find_key_id_by_name(const char *key_name)
331
0
{
332
0
  key_serial_t id = 0;
333
0
  char *end;
334
0
  char *name_copy, *name_copy_p;
335
336
0
  assert(key_name);
337
338
0
  if (key_name[0] == '@') {
339
0
    if (strcmp(key_name, "@t" ) == 0) return KEY_SPEC_THREAD_KEYRING;
340
0
    if (strcmp(key_name, "@p" ) == 0) return KEY_SPEC_PROCESS_KEYRING;
341
0
    if (strcmp(key_name, "@s" ) == 0) return KEY_SPEC_SESSION_KEYRING;
342
0
    if (strcmp(key_name, "@u" ) == 0) return KEY_SPEC_USER_KEYRING;
343
0
    if (strcmp(key_name, "@us") == 0) return KEY_SPEC_USER_SESSION_KEYRING;
344
0
    if (strcmp(key_name, "@g" ) == 0) return KEY_SPEC_GROUP_KEYRING;
345
0
    if (strcmp(key_name, "@a" ) == 0) return KEY_SPEC_REQKEY_AUTH_KEY;
346
347
0
    return 0;
348
0
  }
349
350
  /* handle a lookup-by-name request "%<type>:<desc>", eg: "%keyring:_ses" */
351
0
  name_copy = strdup(key_name);
352
0
  if (!name_copy)
353
0
    goto out;
354
0
  name_copy_p = name_copy;
355
356
0
  if (name_copy_p[0] == '%') {
357
0
    const char *type;
358
359
0
    name_copy_p++;
360
0
    if (!*name_copy_p)
361
0
      goto out;
362
363
0
    if (*name_copy_p == ':') {
364
0
      type = "keyring";
365
0
      name_copy_p++;
366
0
    } else {
367
0
      type = name_copy_p;
368
0
      name_copy_p = strchr(name_copy_p, ':');
369
0
      if (!name_copy_p)
370
0
        goto out;
371
0
      *(name_copy_p++) = '\0';
372
0
    }
373
374
0
    if (!*name_copy_p)
375
0
      goto out;
376
377
0
    id = find_key_by_type_and_desc(type, name_copy_p, 0);
378
0
    goto out;
379
0
  }
380
381
0
  id = strtoul(key_name, &end, 0);
382
0
  if (*end)
383
0
    id = 0;
384
385
0
out:
386
0
  free(name_copy);
387
388
0
  return id;
389
0
}
390
391
static bool numbered(const char *str)
392
0
{
393
0
  char *endp;
394
395
0
  errno = 0;
396
0
  (void) strtol(str, &endp, 0);
397
0
  if (errno == ERANGE)
398
0
    return false;
399
400
0
  return *endp == '\0' ? true : false;
401
0
}
402
403
key_serial_t keyring_find_keyring_id_by_name(const char *keyring_name)
404
0
{
405
0
  assert(keyring_name);
406
407
  /* "%:" is abbreviation for the type keyring */
408
0
  if ((keyring_name[0] == '@' && keyring_name[1] != 'a') ||
409
0
      strstr(keyring_name, "%:") || strstr(keyring_name, "%keyring:") ||
410
0
      numbered(keyring_name))
411
0
    return keyring_find_key_id_by_name(keyring_name);
412
413
0
  return 0;
414
0
}
415
416
key_type_t key_type_by_name(const char *name)
417
0
{
418
0
  unsigned int i;
419
420
0
  for (i = 0; i < ARRAY_SIZE(key_types); i++)
421
0
    if (!strcmp(key_types[i].type_name, name))
422
0
      return key_types[i].type;
423
424
0
  return INVALID_KEY;
425
0
}
426
427
#else /* KERNEL_KEYRING */
428
#pragma GCC diagnostic ignored "-Wunused-parameter"
429
430
int keyring_check(void)
431
{
432
  return 0;
433
}
434
435
key_serial_t keyring_add_key_in_thread_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
436
{
437
  return -ENOTSUP;
438
}
439
440
key_serial_t keyring_request_key_id(key_type_t key_type,
441
    const char *key_description)
442
{
443
  return -ENOTSUP;
444
}
445
446
int keyring_read_keysize(key_serial_t kid,
447
    size_t *r_key_size)
448
{
449
  return -ENOTSUP;
450
}
451
452
int keyring_read_key(key_serial_t kid,
453
    char **key,
454
    size_t *key_size)
455
{
456
  return -ENOTSUP;
457
}
458
459
int keyring_read_by_id(const char *key_desc, char **passphrase, size_t *passphrase_len)
460
{
461
  return -ENOTSUP;
462
}
463
464
const char *key_type_name(key_type_t type)
465
{
466
  return NULL;
467
}
468
469
key_type_t keyring_type_and_name(const char *key_name, const char **name)
470
{
471
  return INVALID_KEY;
472
}
473
474
key_serial_t keyring_find_key_id_by_name(const char *key_name)
475
{
476
  return 0;
477
}
478
479
key_serial_t keyring_find_keyring_id_by_name(const char *keyring_name)
480
{
481
  return 0;
482
}
483
484
key_type_t key_type_by_name(const char *name)
485
{
486
  return INVALID_KEY;
487
}
488
489
key_serial_t keyring_add_key_to_keyring(key_type_t ktype,
490
          const char *key_desc,
491
          const void *key,
492
          size_t key_size,
493
          key_serial_t keyring_to_link)
494
{
495
  return -ENOTSUP;
496
}
497
498
int keyring_unlink_key_from_keyring(key_serial_t kid, key_serial_t keyring_id)
499
{
500
  return -ENOTSUP;
501
}
502
503
int keyring_unlink_key_from_thread_keyring(key_serial_t kid)
504
{
505
  return -ENOTSUP;
506
}
507
#endif