don't revoke + fork session

This commit is contained in:
Ilya Priven
2026-10-12 22:37:05 +00:00
parent 640617d81c
commit cef1b2f5dc
4 changed files with 54 additions and 39 deletions

View File

@@ -443,8 +443,7 @@ void *recallocarray(void *, size_t, size_t, size_t);
#ifdef HAVE_KEYCTL #ifdef HAVE_KEYCTL
/* keyring-linux.c */ /* keyring-linux.c */
void new_session_keyring(void); void fork_session_keyring(void);
void revoke_session_keyring(void);
#endif #endif
#ifdef HAVE_SYSTEMD #ifdef HAVE_SYSTEMD

View File

@@ -19,40 +19,59 @@
#include <linux/keyctl.h> #include <linux/keyctl.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* Serial of the session keyring we joined, or 0 if none. */
static long keyring_serial;
/* /*
* Create a new session keyring since the current one belongs to the login * Create a new session keyring since the current one belongs to the login
* session which we're meant to outlive (and pam_keyinit(8) is likely to revoke * session which we're meant to outlive (and pam_keyinit(8) is likely to revoke
* the login session's keyring when it ends). * the login session's keyring when it ends). Link the keys from the current
* session keyring into it so they remain available after that.
*/ */
void void
new_session_keyring(void) fork_session_keyring(void)
{ {
long serial; int32_t *keys = NULL;
long size, n = 0, i;
serial = syscall(SYS_keyctl, KEYCTL_JOIN_SESSION_KEYRING, NULL); size = syscall(SYS_keyctl, KEYCTL_READ, KEY_SPEC_SESSION_KEYRING, NULL,
if (serial == -1) { 0);
if (size > 0) {
keys = xmalloc(size);
n = syscall(SYS_keyctl, KEYCTL_READ, KEY_SPEC_SESSION_KEYRING,
keys, size);
if (n > size)
n = size;
n = n > 0 ? n / sizeof *keys : 0;
}
/*
* Link the current session keyring into the thread keyring so we still
* possess its keys (and so are allowed to link them) after leaving it.
*/
if (syscall(SYS_keyctl, KEYCTL_LINK, KEY_SPEC_SESSION_KEYRING,
KEY_SPEC_THREAD_KEYRING) == -1)
log_debug("%s: link failed: %s", __func__, strerror(errno));
if (syscall(SYS_keyctl, KEYCTL_JOIN_SESSION_KEYRING, NULL) == -1) {
log_debug("%s: join failed: %s", __func__, strerror(errno)); log_debug("%s: join failed: %s", __func__, strerror(errno));
return; goto out;
}
for (i = 0; i < n; i++) {
if (syscall(SYS_keyctl, KEYCTL_LINK, keys[i],
KEY_SPEC_SESSION_KEYRING) == -1) {
log_debug("%s: link %d failed: %s", __func__, keys[i],
strerror(errno));
}
} }
if (syscall(SYS_keyctl, KEYCTL_LINK, KEY_SPEC_USER_KEYRING, if (syscall(SYS_keyctl, KEYCTL_LINK, KEY_SPEC_USER_KEYRING,
KEY_SPEC_SESSION_KEYRING) == -1) KEY_SPEC_SESSION_KEYRING) == -1)
log_debug("%s: link failed: %s", __func__, strerror(errno)); log_debug("%s: link failed: %s", __func__, strerror(errno));
keyring_serial = serial;
}
void out:
revoke_session_keyring(void) syscall(SYS_keyctl, KEYCTL_CLEAR, KEY_SPEC_THREAD_KEYRING);
{ free(keys);
if (keyring_serial == 0)
return;
if (syscall(SYS_keyctl, KEYCTL_REVOKE, keyring_serial) == -1)
log_debug("%s: revoke failed: %s", __func__, strerror(errno));
} }

View File

@@ -541,6 +541,21 @@ if test "x$enable_cgroups" = xyes; then
fi fi
fi fi
# Look for linux/keyctl.h, compat/keyring-linux.c used if found and enabled.
AC_ARG_ENABLE(
keyring,
AS_HELP_STRING(--disable-keyring, disable giving the server its own Linux session keyring)
)
if test "x$enable_keyring" != xno; then
AC_CHECK_HEADER(linux/keyctl.h, found_keyctl=yes, found_keyctl=no)
if test "x$found_keyctl" = xyes; then
AC_DEFINE(HAVE_KEYCTL)
elif test "x$enable_keyring" = xyes; then
AC_MSG_ERROR("linux/keyctl.h not found")
fi
fi
AM_CONDITIONAL(HAVE_KEYCTL, [test "x$found_keyctl" = xyes])
# Enable image support. # Enable image support.
AC_ARG_ENABLE( AC_ARG_ENABLE(
images, images,
@@ -804,21 +819,6 @@ else
AC_LIBOBJ(daemon) AC_LIBOBJ(daemon)
fi fi
# Look for linux/keyctl.h, compat/keyring-linux.c used if found and enabled.
AC_ARG_ENABLE(
keyring,
AS_HELP_STRING(--disable-keyring, disable giving the server its own Linux session keyring)
)
if test "x$enable_keyring" != xno; then
AC_CHECK_HEADER(linux/keyctl.h, found_keyctl=yes, found_keyctl=no)
if test "x$found_keyctl" = xyes; then
AC_DEFINE(HAVE_KEYCTL)
elif test "x$enable_keyring" = xyes; then
AC_MSG_ERROR("linux/keyctl.h not found")
fi
fi
AM_CONDITIONAL(HAVE_KEYCTL, [test "x$found_keyctl" = xyes])
# Look for stravis, compat/{vis,unvis}.c used if missing. # Look for stravis, compat/{vis,unvis}.c used if missing.
AC_CHECK_FUNC(stravis, found_stravis=yes, found_stravis=no) AC_CHECK_FUNC(stravis, found_stravis=yes, found_stravis=no)
if test "x$found_stravis" = xyes; then if test "x$found_stravis" = xyes; then

View File

@@ -221,7 +221,7 @@ server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base,
gettimeofday(&start_time, NULL); gettimeofday(&start_time, NULL);
#ifdef HAVE_KEYCTL #ifdef HAVE_KEYCTL
new_session_keyring(); fork_session_keyring();
#endif #endif
#ifdef HAVE_SYSTEMD #ifdef HAVE_SYSTEMD
@@ -263,9 +263,6 @@ server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base,
job_kill_all(); job_kill_all();
prompt_save_history(); prompt_save_history();
#ifdef HAVE_KEYCTL
revoke_session_keyring();
#endif
exit(0); exit(0);
} }