|
|
c28716f |
From 33f835ec7c74629d4a6982c3b75630af2cd5d65b Mon Sep 17 00:00:00 2001
|
|
|
c28716f |
From: Simon McVittie <simon.mcvittie@collabora.co.uk>
|
|
|
c28716f |
Date: Wed, 17 Jun 2015 16:45:49 +0100
|
|
|
c28716f |
Subject: [PATCH] logind: save /run/systemd/users/UID before starting
|
|
|
c28716f |
user@.service
|
|
|
c28716f |
|
|
|
c28716f |
Previously, this had a race condition during a user's first login.
|
|
|
c28716f |
Some component calls CreateSession (most likely by a PAM service
|
|
|
c28716f |
other than 'systemd-user' running pam_systemd), with the following
|
|
|
c28716f |
results:
|
|
|
c28716f |
|
|
|
c28716f |
- logind:
|
|
|
c28716f |
* create the user's XDG_RUNTIME_DIR
|
|
|
c28716f |
* tell pid 1 to create user-UID.slice
|
|
|
c28716f |
* tell pid 1 to start user@UID.service
|
|
|
c28716f |
|
|
|
c28716f |
Then these two processes race:
|
|
|
c28716f |
|
|
|
c28716f |
- logind:
|
|
|
c28716f |
* save information including XDG_RUNTIME_DIR to /run/systemd/users/UID
|
|
|
c28716f |
|
|
|
c28716f |
- the subprocess of pid 1 responsible for user@service:
|
|
|
c28716f |
* start a 'systemd-user' PAM session, which reads XDG_RUNTIME_DIR
|
|
|
c28716f |
and puts it in the environment
|
|
|
c28716f |
* run systemd --user, which requires XDG_RUNTIME_DIR in the
|
|
|
c28716f |
environment
|
|
|
c28716f |
|
|
|
c28716f |
If logind wins the race, which usually happens, everything is fine;
|
|
|
c28716f |
but if the subprocesses of pid 1 win the race, which can happen
|
|
|
c28716f |
under load, then systemd --user exits unsuccessfully.
|
|
|
c28716f |
|
|
|
c28716f |
To avoid this race, we have to write out /run/systemd/users/UID
|
|
|
c28716f |
even though the service has not "officially" started yet;
|
|
|
c28716f |
previously this did an early-return without saving anything.
|
|
|
c28716f |
Record its state as OPENING in this case.
|
|
|
c28716f |
|
|
|
c28716f |
Bug: https://github.com/systemd/systemd/issues/232
|
|
|
c28716f |
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
|
|
|
c28716f |
(cherry picked from commit 71161305f191d1fe1242ccca47657f9ab51caad4)
|
|
|
c28716f |
---
|
|
|
c28716f |
src/login/logind-user.c | 22 +++++++++++++++++-----
|
|
|
c28716f |
1 file changed, 17 insertions(+), 5 deletions(-)
|
|
|
c28716f |
|
|
|
c28716f |
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
|
|
|
c28716f |
index f4c4490e8f..21acf2afe3 100644
|
|
|
c28716f |
--- a/src/login/logind-user.c
|
|
|
c28716f |
+++ b/src/login/logind-user.c
|
|
|
c28716f |
@@ -104,7 +104,7 @@ void user_free(User *u) {
|
|
|
c28716f |
free(u);
|
|
|
c28716f |
}
|
|
|
c28716f |
|
|
|
c28716f |
-int user_save(User *u) {
|
|
|
c28716f |
+static int user_save_internal(User *u) {
|
|
|
c28716f |
_cleanup_free_ char *temp_path = NULL;
|
|
|
c28716f |
_cleanup_fclose_ FILE *f = NULL;
|
|
|
c28716f |
int r;
|
|
|
c28716f |
@@ -112,9 +112,6 @@ int user_save(User *u) {
|
|
|
c28716f |
assert(u);
|
|
|
c28716f |
assert(u->state_file);
|
|
|
c28716f |
|
|
|
c28716f |
- if (!u->started)
|
|
|
c28716f |
- return 0;
|
|
|
c28716f |
-
|
|
|
c28716f |
r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
|
|
|
c28716f |
if (r < 0)
|
|
|
c28716f |
goto finish;
|
|
|
c28716f |
@@ -257,6 +254,15 @@ finish:
|
|
|
c28716f |
return r;
|
|
|
c28716f |
}
|
|
|
c28716f |
|
|
|
c28716f |
+int user_save(User *u) {
|
|
|
c28716f |
+ assert(u);
|
|
|
c28716f |
+
|
|
|
c28716f |
+ if (!u->started)
|
|
|
c28716f |
+ return 0;
|
|
|
c28716f |
+
|
|
|
c28716f |
+ return user_save_internal (u);
|
|
|
c28716f |
+}
|
|
|
c28716f |
+
|
|
|
c28716f |
int user_load(User *u) {
|
|
|
c28716f |
_cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
|
|
|
c28716f |
Session *s = NULL;
|
|
|
c28716f |
@@ -452,6 +458,12 @@ int user_start(User *u) {
|
|
|
c28716f |
if (r < 0)
|
|
|
c28716f |
return r;
|
|
|
c28716f |
|
|
|
c28716f |
+ /* Save the user data so far, because pam_systemd will read the
|
|
|
c28716f |
+ * XDG_RUNTIME_DIR out of it while starting up systemd --user.
|
|
|
c28716f |
+ * We need to do user_save_internal() because we have not
|
|
|
c28716f |
+ * "officially" started yet. */
|
|
|
c28716f |
+ user_save_internal(u);
|
|
|
c28716f |
+
|
|
|
c28716f |
/* Spawn user systemd */
|
|
|
c28716f |
r = user_start_service(u);
|
|
|
c28716f |
if (r < 0)
|
|
|
c28716f |
@@ -703,7 +715,7 @@ UserState user_get_state(User *u) {
|
|
|
c28716f |
if (u->stopping)
|
|
|
c28716f |
return USER_CLOSING;
|
|
|
c28716f |
|
|
|
c28716f |
- if (u->slice_job || u->service_job)
|
|
|
c28716f |
+ if (!u->started || u->slice_job || u->service_job)
|
|
|
c28716f |
return USER_OPENING;
|
|
|
c28716f |
|
|
|
c28716f |
if (u->sessions) {
|