From cef1b2f5dc21afccbc20ea4c5ad44278e0a9ca90 Mon Sep 17 00:00:00 2001 From: Ilya Priven Date: Mon, 12 Oct 2026 22:37:05 +0000 Subject: [PATCH] don't revoke + fork session --- compat.h | 3 +-- compat/keyring-linux.c | 55 ++++++++++++++++++++++++++++-------------- configure.ac | 30 +++++++++++------------ server.c | 5 +--- 4 files changed, 54 insertions(+), 39 deletions(-) diff --git a/compat.h b/compat.h index 4c74b7168..2a81845fb 100644 --- a/compat.h +++ b/compat.h @@ -443,8 +443,7 @@ void *recallocarray(void *, size_t, size_t, size_t); #ifdef HAVE_KEYCTL /* keyring-linux.c */ -void new_session_keyring(void); -void revoke_session_keyring(void); +void fork_session_keyring(void); #endif #ifdef HAVE_SYSTEMD diff --git a/compat/keyring-linux.c b/compat/keyring-linux.c index 967c799b3..11d02c987 100644 --- a/compat/keyring-linux.c +++ b/compat/keyring-linux.c @@ -19,40 +19,59 @@ #include #include +#include #include #include #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 * 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 -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); - if (serial == -1) { + size = syscall(SYS_keyctl, KEYCTL_READ, KEY_SPEC_SESSION_KEYRING, NULL, + 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)); - 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, KEY_SPEC_SESSION_KEYRING) == -1) log_debug("%s: link failed: %s", __func__, strerror(errno)); - keyring_serial = serial; -} -void -revoke_session_keyring(void) -{ - if (keyring_serial == 0) - return; - if (syscall(SYS_keyctl, KEYCTL_REVOKE, keyring_serial) == -1) - log_debug("%s: revoke failed: %s", __func__, strerror(errno)); +out: + syscall(SYS_keyctl, KEYCTL_CLEAR, KEY_SPEC_THREAD_KEYRING); + free(keys); } diff --git a/configure.ac b/configure.ac index b72b84bec..0a7d81d1d 100644 --- a/configure.ac +++ b/configure.ac @@ -541,6 +541,21 @@ if test "x$enable_cgroups" = xyes; then 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. AC_ARG_ENABLE( images, @@ -804,21 +819,6 @@ else AC_LIBOBJ(daemon) 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. AC_CHECK_FUNC(stravis, found_stravis=yes, found_stravis=no) if test "x$found_stravis" = xyes; then diff --git a/server.c b/server.c index a70a1502c..540bfada0 100644 --- a/server.c +++ b/server.c @@ -221,7 +221,7 @@ server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base, gettimeofday(&start_time, NULL); #ifdef HAVE_KEYCTL - new_session_keyring(); + fork_session_keyring(); #endif #ifdef HAVE_SYSTEMD @@ -263,9 +263,6 @@ server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base, job_kill_all(); prompt_save_history(); -#ifdef HAVE_KEYCTL - revoke_session_keyring(); -#endif exit(0); }