Coverage Report

Created: 2026-10-17 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/compat/keyring-linux.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2026 Ilya Priven <ikon@google.com>
3
 *
4
 * Permission to use, copy, modify, and distribute this software for any
5
 * purpose with or without fee is hereby granted, provided that the above
6
 * copyright notice and this permission notice appear in all copies.
7
 *
8
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
13
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
14
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
 */
16
17
#include <sys/types.h>
18
#include <sys/syscall.h>
19
20
#include <linux/keyctl.h>
21
#include <errno.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <unistd.h>
25
26
#include "tmux.h"
27
28
/*
29
 * Create a new session keyring since the current one belongs to the login
30
 * session which we're meant to outlive (and pam_keyinit(8) is likely to revoke
31
 * the login session's keyring when it ends). Link the keys from the current
32
 * session keyring into it so they remain available after that.
33
 */
34
void
35
fork_session_keyring(void)
36
0
{
37
0
  int32_t *keys = NULL;
38
0
  long   size = 0, n, i;
39
40
  /* KEYCTL_READ returns the full size; retry if keys were added. */
41
0
  for (;;) {
42
0
    n = syscall(SYS_keyctl, KEYCTL_READ, KEY_SPEC_SESSION_KEYRING,
43
0
        keys, size);
44
0
    if (n <= size)
45
0
      break;
46
0
    size = n;
47
0
    keys = xrealloc(keys, size);
48
0
  }
49
0
  n = n > 0 ? n / sizeof *keys : 0;
50
51
  /*
52
   * Link the current session keyring into the thread keyring so we still
53
   * possess its keys (and so are allowed to link them) after leaving it.
54
   */
55
0
  if (syscall(SYS_keyctl, KEYCTL_LINK, KEY_SPEC_SESSION_KEYRING,
56
0
      KEY_SPEC_THREAD_KEYRING) == -1)
57
0
    log_debug("%s: link failed: %s", __func__, strerror(errno));
58
59
0
  if (syscall(SYS_keyctl, KEYCTL_JOIN_SESSION_KEYRING, NULL) == -1) {
60
0
    log_debug("%s: join failed: %s", __func__, strerror(errno));
61
0
    goto out;
62
0
  }
63
0
  for (i = 0; i < n; i++) {
64
0
    if (syscall(SYS_keyctl, KEYCTL_LINK, keys[i],
65
0
        KEY_SPEC_SESSION_KEYRING) == -1) {
66
0
      log_debug("%s: link %d failed: %s", __func__, keys[i],
67
0
          strerror(errno));
68
0
    }
69
0
  }
70
0
  if (syscall(SYS_keyctl, KEYCTL_LINK, KEY_SPEC_USER_KEYRING,
71
0
      KEY_SPEC_SESSION_KEYRING) == -1)
72
0
    log_debug("%s: link failed: %s", __func__, strerror(errno));
73
74
0
out:
75
0
  syscall(SYS_keyctl, KEYCTL_CLEAR, KEY_SPEC_THREAD_KEYRING);
76
0
  free(keys);
77
0
}