From fc0bb7ccc763ec79efe7a8a58220e9bc80f34f81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 16 May 2024 17:06:24 +0200 Subject: [PATCH] logind: make ReleaseSession "unprivileged" and allow closing of own session Fixes https://github.com/systemd/systemd/issues/28514. Quoting https://github.com/systemd/systemd/issues/28514#issuecomment-1831781486: > Whenever PAM is enabled for a service, we set up the PAM session and then > fork off a process whose only job is to eventually close the PAM session when > the service dies. That services we run with service privileges, both to > minimize attack surface and because we want to use PR_SET_DEATHSIG to be get > a notification via signal whenever the main process dies. But that only works > if we have the same credentials as that main process. > > Now, if pam_systemd runs inside the PAM stack (which it normally does) it's > session close hook will ask logind to synchronously end the session via a bus > call. Currently that call is not accessible to unprivileged clients. And > that's the part we need to relax: allow users to end their own sessions. The check is implemented in a way that allows the kill if the sender is in the target session. I found 'sudo systemctl --user -M "zbyszek@" is-system-running' to be a convenient reproducer. Before: May 16 16:25:26 x1c systemd[1]: run-u24754.service: Deactivated successfully. May 16 16:25:26 x1c dbus-broker[1489]: A security policy denied :1.24757 to send method call /org/freedesktop/login1:org.freedesktop.login1.Manager.ReleaseSession to org.freedesktop.login1. May 16 16:25:26 x1c (sd-pam)[3036470]: pam_systemd(login:session): Failed to release session: Access denied May 16 16:25:26 x1c systemd[1]: Stopping session-114.scope... May 16 16:25:26 x1c systemd[1]: session-114.scope: Deactivated successfully. May 16 16:25:26 x1c systemd[1]: Stopped session-114.scope. May 16 16:25:26 x1c systemd[1]: session-c151.scope: Deactivated successfully. May 16 16:25:26 x1c systemd-logind[1513]: Session c151 logged out. Waiting for processes to exit. May 16 16:25:26 x1c systemd-logind[1513]: Removed session c151. After: May 16 17:02:15 x1c systemd[1]: run-u24770.service: Deactivated successfully. May 16 17:02:15 x1c systemd[1]: Stopping session-115.scope... May 16 17:02:15 x1c systemd[1]: session-c153.scope: Deactivated successfully. May 16 17:02:15 x1c systemd[1]: session-115.scope: Deactivated successfully. May 16 17:02:15 x1c systemd[1]: Stopped session-115.scope. May 16 17:02:15 x1c systemd-logind[1513]: Session c153 logged out. Waiting for processes to exit. May 16 17:02:15 x1c systemd-logind[1513]: Removed session c153. Edit: this seems to also fix https://github.com/systemd/systemd/issues/8598. It seems that with the call to ReleaseSession, we wait for the pam session close hooks to finish. I inserted a 'sleep(10)' after the call to ReleaseSession in pam_systemd, and things block on that, nothing is killed prematurely. --- man/org.freedesktop.login1.xml | 1 - src/login/logind-dbus.c | 11 +++++++++-- src/login/org.freedesktop.login1.conf | 4 ++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml index dffd16e325..20936a6936 100644 --- a/man/org.freedesktop.login1.xml +++ b/man/org.freedesktop.login1.xml @@ -104,7 +104,6 @@ node /org/freedesktop/login1 { out s seat_id, out u vtnr, out b existing); - @org.freedesktop.systemd1.Privileged("true") ReleaseSession(in s session_id); ActivateSession(in s session_id); ActivateSessionOnSeat(in s session_id, diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 70fc9aeebf..5fdf28ced0 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1172,7 +1172,7 @@ static int method_create_session_pidfd(sd_bus_message *message, void *userdata, static int method_release_session(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = ASSERT_PTR(userdata); - Session *session; + Session *session, *sender_session; const char *name; int r; @@ -1186,6 +1186,13 @@ static int method_release_session(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; + r = get_sender_session(m, message, /* consult_display= */ false, error, &sender_session); + if (r < 0) + return r; + + if (session != sender_session) + return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session"); + r = session_release(session); if (r < 0) return r; @@ -3767,7 +3774,7 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_ARGS("s", session_id), SD_BUS_NO_RESULT, method_release_session, - 0), + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_ARGS("ActivateSession", SD_BUS_ARGS("s", session_id), SD_BUS_NO_RESULT, diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf index dd6e3651e3..dff944f172 100644 --- a/src/login/org.freedesktop.login1.conf +++ b/src/login/org.freedesktop.login1.conf @@ -274,6 +274,10 @@ send_interface="org.freedesktop.login1.Manager" send_member="FlushDevices"/> + +