diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2015-09-29 11:36:18 +0200 |
---|---|---|
committer | Sven Eden <yamakuzure@gmx.net> | 2017-04-26 12:58:55 +0200 |
commit | 2c0a91fedc150195f54d91bf75515e4bfff0d753 (patch) | |
tree | 18c8451147a981b8ab239dbff40798145b6fbe60 | |
parent | 5814139990daf10155b4fb0951ee456ac9c97a4b (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 "elogind --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 0f7f31aa8..27f737000 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -481,15 +481,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); @@ -507,16 +524,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; } |