diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2015-09-29 11:36:18 +0200 |
---|---|---|
committer | David Herrmann <dh.herrmann@gmail.com> | 2015-11-16 15:34:41 +0100 |
commit | a832ab6f9953d070ee8f5cf2c7869425760b2645 (patch) | |
tree | 32ac31723b32cbf713a8430b3140ce9ea0942f8b | |
parent | 090d92bd6f66afd7c6bf18ef07315058ce826f01 (diff) |
login: fix re-use of users
If the last reference to a user is released, we queue stop-jobs for the
user-service and slice. Only once those are finished, we drop the
user-object. However, if a new session is opened before the user object is
fully dropped, we currently incorrectly re-use the object. This has the
effect, that we get stale sessions without a valid "systemd --user"
instance.
Fix this by properly allowing user_start() to be called, even if
user->stopping is true.
-rw-r--r-- | src/login/logind-user.c | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/src/login/logind-user.c b/src/login/logind-user.c index b9d9d537e2..778f19b50d 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -452,15 +452,32 @@ int user_start(User *u) { assert(u); - if (u->started) + if (u->started && !u->stopping) return 0; - log_debug("New user %s logged in.", u->name); - - /* Make XDG_RUNTIME_DIR */ - r = user_mkdir_runtime_path(u); - if (r < 0) - return r; + /* + * If u->stopping is set, the user is marked for removal and the slice + * and service stop-jobs are queued. We have to clear that flag before + * queing the start-jobs again. If they succeed, the user object can be + * re-used just fine (pid1 takes care of job-ordering and proper + * restart), but if they fail, we want to force another user_stop() so + * possibly pending units are stopped. + * Note that we don't clear u->started, as we have no clue what state + * the user is in on failure here. Hence, we pretend the user is + * running so it will be properly taken down by GC. However, we clearly + * return an error from user_start() in that case, so no further + * reference to the user is taken. + */ + u->stopping = false; + + if (!u->started) { + log_debug("New user %s logged in.", u->name); + + /* Make XDG_RUNTIME_DIR */ + r = user_mkdir_runtime_path(u); + if (r < 0) + return r; + } /* Create cgroup */ r = user_start_slice(u); @@ -478,16 +495,16 @@ int user_start(User *u) { if (r < 0) return r; - if (!dual_timestamp_is_set(&u->timestamp)) - dual_timestamp_get(&u->timestamp); - - u->started = true; + if (!u->started) { + if (!dual_timestamp_is_set(&u->timestamp)) + dual_timestamp_get(&u->timestamp); + user_send_signal(u, true); + u->started = true; + } /* Save new user data */ user_save(u); - user_send_signal(u, true); - return 0; } |