From 183e0738427b83667512276a3e8c10274c0824cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 May 2016 18:57:15 +0200 Subject: [PATCH] logind: enforce a limit on current user sessions We really should put limits on all resources we manage, hence add one to the number of concurrent sessions, too. This was previously unbounded, hence set a relatively high limit of 8K by default. Note that most PAM setups will actually invoke pam_systemd prefixed with "-", so that the return code of pam_systemd is ignored, and the login attempt succeeds anyway. On systems like this the session will be created but is not tracked by systemd. --- man/logind.conf.xml | 9 +++++++++ src/login/logind-dbus.c | 23 +++++++++++++++++++++++ src/login/logind-gperf.gperf | 1 + src/login/logind.c | 1 + src/login/logind.conf.in | 1 + src/login/logind.h | 1 + 6 files changed, 36 insertions(+) diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 6ba35414bef..405dcf90414 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -296,6 +296,15 @@ memory as is needed. + + SessionsMax= + + Controls the maximum number of concurrent user sessions to manage. Defaults to 8192 + (8K). Depending on how the pam_systemd.so module is included in the PAM stack + configuration, further login sessions will either be refused, or permitted but not tracked by + systemd-logind. + + UserTasksMax= diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index a281f99a343..5067e5d1a84 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -265,6 +265,24 @@ static int property_get_docked( return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m)); } +static int property_get_current_sessions( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + + assert(bus); + assert(reply); + assert(m); + + return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->sessions)); +} + static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_free_ char *p = NULL; Manager *m = userdata; @@ -725,6 +743,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus m->seat0->positions[vtnr]->class != SESSION_GREETER) return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session"); + if (hashmap_size(m->sessions) >= m->sessions_max) + return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max); + audit_session_from_pid(leader, &audit_id); if (audit_id > 0) { /* Keep our session IDs and the audit session IDs in sync */ @@ -2512,6 +2533,8 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0), SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0), SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0), + SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_current_sessions, 0, 0), SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index 8552c464cca..1d576812608 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -34,4 +34,5 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec) Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size) Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc) +Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max) Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max) diff --git a/src/login/logind.c b/src/login/logind.c index a48e2fc61ec..39f53cab360 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -63,6 +63,7 @@ static void manager_reset_config(Manager *m) { m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ m->user_tasks_max = UINT64_C(12288); + m->sessions_max = UINT64_C(8192); m->kill_user_processes = KILL_USER_PROCESSES; diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in index 3c96def45d9..62842186255 100644 --- a/src/login/logind.conf.in +++ b/src/login/logind.conf.in @@ -32,4 +32,5 @@ #IdleActionSec=30min #RuntimeDirectorySize=10% #RemoveIPC=yes +#SessionsMax=8192 #UserTasksMax=12288 diff --git a/src/login/logind.h b/src/login/logind.h index 6748af3c07e..23c3e2963a6 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -133,6 +133,7 @@ struct Manager { size_t runtime_dir_size; uint64_t user_tasks_max; + uint64_t sessions_max; }; int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device);