diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | TODO | 6 | ||||
-rw-r--r-- | man/logind.conf.xml | 16 | ||||
-rw-r--r-- | man/systemd.socket.xml | 13 | ||||
-rw-r--r-- | src/core/socket.c | 31 | ||||
-rw-r--r-- | src/login/logind-dbus.c | 49 | ||||
-rw-r--r-- | src/login/logind-gperf.gperf | 2 | ||||
-rw-r--r-- | src/login/logind-inhibit.c | 2 | ||||
-rw-r--r-- | src/login/logind-seat-dbus.c | 2 | ||||
-rw-r--r-- | src/login/logind-session.c | 4 | ||||
-rw-r--r-- | src/login/logind-user-dbus.c | 2 | ||||
-rw-r--r-- | src/login/logind.c | 6 | ||||
-rw-r--r-- | src/login/logind.conf.in | 2 | ||||
-rw-r--r-- | src/login/logind.h | 2 | ||||
-rw-r--r-- | src/network/networkd-conf.c | 2 | ||||
-rw-r--r-- | src/network/networkd.h | 1 | ||||
-rw-r--r-- | src/network/test-networkd-conf.c | 4 |
17 files changed, 125 insertions, 21 deletions
diff --git a/.gitignore b/.gitignore index c17f79224b..091b400182 100644 --- a/.gitignore +++ b/.gitignore @@ -235,7 +235,7 @@ /test-ndisc-rs /test-netlink /test-netlink-manual -/test-netword-conf +/test-networkd-conf /test-network /test-network-tables /test-ns @@ -33,6 +33,12 @@ Janitorial Clean-ups: Features: +* make sure the ratelimit object can deal with USEC_INFINITY as way to turn off things + +* maybe: pid1: replace cgroups agent transport by AF_UNIX/SOCK_DGRAM, so that + we aren't hit by socket backlog exhaustion on the dbus AF_UNIX/SOCK_STREAM + socket + * journalctl: make sure -f ends when the container indicated by -M terminates * rework fopen_temporary() to make use of open_tmpfile_linkable() (problem: the diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 6ba35414be..fe92277a1f 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -297,6 +297,22 @@ </varlistentry> <varlistentry> + <term><varname>InhibitorsMax=</varname></term> + + <listitem><para>Controls the maximum number of concurrent inhibitors to permit. Defaults to 8192 + (8K).</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>SessionsMax=</varname></term> + + <listitem><para>Controls the maximum number of concurrent user sessions to manage. Defaults to 8192 + (8K). Depending on how the <filename>pam_systemd.so</filename> module is included in the PAM stack + configuration, further login sessions will either be refused, or permitted but not tracked by + <filename>systemd-logind</filename>.</para></listitem> + </varlistentry> + + <varlistentry> <term><varname>UserTasksMax=</varname></term> <listitem><para>Sets the maximum number of OS tasks each user diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 735268c79d..5bf54d8ef3 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -814,13 +814,14 @@ <listitem><para>Configures a limit on how often this socket unit my be activated within a specific time interval. The <varname>TriggerLimitIntervalSec=</varname> may be used to configure the length of the time interval in the usual time units <literal>us</literal>, <literal>ms</literal>, <literal>s</literal>, - <literal>min</literal>, <literal>h</literal>, … and defaults to 5s (See + <literal>min</literal>, <literal>h</literal>, … and defaults to 2s (See <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details on - the various time units available). The <varname>TriggerLimitBurst=</varname> setting takes an integer value and - specifies the numer of permitted activations per time interval, and defaults to 2500 (thus by default - permitting 2500 activations per 5s). Set either to 0 to disable any form of trigger rate limiting. If the limit - is hit, the socket unit is placed into a failure mode, and will not be connectible anymore until - restarted. Note that this limit is enforced before the service activation is enqueued.</para></listitem> + the various time units understood). The <varname>TriggerLimitBurst=</varname> setting takes a positive integer + value and specifies the number of permitted activations per time interval, and defaults to 200 for + <varname>Accept=yes</varname> sockets (thus by default permitting 200 activations per 2s), and 20 otherwise (20 + activations per 2s). Set either to 0 to disable any form of trigger rate limiting. If the limit is hit, the + socket unit is placed into a failure mode, and will not be connectible anymore until restarted. Note that this + limit is enforced before the service activation is enqueued.</para></listitem> </varlistentry> </variablelist> diff --git a/src/core/socket.c b/src/core/socket.c index d3d4866fe6..016df40b8c 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -100,7 +100,8 @@ static void socket_init(Unit *u) { s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; - RATELIMIT_INIT(s->trigger_limit, 5*USEC_PER_SEC, 2500); + s->trigger_limit.interval = USEC_INFINITY; + s->trigger_limit.burst = (unsigned) -1; } static void socket_unwatch_control_pid(Socket *s) { @@ -328,6 +329,25 @@ static int socket_add_extras(Socket *s) { assert(s); + /* Pick defaults for the trigger limit, if nothing was explicitly configured. We pick a relatively high limit + * in Accept=yes mode, and a lower limit for Accept=no. Reason: in Accept=yes mode we are invoking accept() + * ourselves before the trigger limit can hit, thus incoming connections are taken off the socket queue quickly + * and reliably. This is different for Accept=no, where the spawned service has to take the incoming traffic + * off the queues, which it might not necessarily do. Moreover, while Accept=no services are supposed to + * process whatever is queued in one go, and thus should normally never have to be started frequently. This is + * different for Accept=yes where each connection is processed by a new service instance, and thus frequent + * service starts are typical. */ + + if (s->trigger_limit.interval == USEC_INFINITY) + s->trigger_limit.interval = 2 * USEC_PER_SEC; + + if (s->trigger_limit.burst == (unsigned) -1) { + if (s->accept) + s->trigger_limit.burst = 200; + else + s->trigger_limit.burst = 20; + } + if (have_non_accept_socket(s)) { if (!UNIT_DEREF(s->service)) { @@ -620,8 +640,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { if (!isempty(s->user) || !isempty(s->group)) fprintf(f, - "%sOwnerUser: %s\n" - "%sOwnerGroup: %s\n", + "%sSocketUser: %s\n" + "%sSocketGroup: %s\n", prefix, strna(s->user), prefix, strna(s->group)); @@ -1271,11 +1291,13 @@ static int socket_open_fds(Socket *s) { /* Apply the socket protocol */ switch(p->address.type) { + case SOCK_STREAM: case SOCK_SEQPACKET: if (p->socket->socket_protocol == IPPROTO_SCTP) p->address.protocol = p->socket->socket_protocol; break; + case SOCK_DGRAM: if (p->socket->socket_protocol == IPPROTO_UDPLITE) p->address.protocol = p->socket->socket_protocol; @@ -1339,8 +1361,7 @@ static int socket_open_fds(Socket *s) { } break; - case SOCKET_USB_FUNCTION: - { + case SOCKET_USB_FUNCTION: { _cleanup_free_ char *ep = NULL; ep = path_make_absolute("ep0", p->path); diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index a281f99a34..0a84d75e24 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -265,6 +265,42 @@ 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 property_get_current_inhibitors( + 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->inhibitors)); +} + 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 +761,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 */ @@ -2442,6 +2481,9 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error if (r < 0) return r; + if (hashmap_size(m->inhibitors) >= m->inhibitors_max) + return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.", m->inhibitors_max); + do { id = mfree(id); @@ -2512,6 +2554,13 @@ 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("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RuntimeDirectorySize", "t", bus_property_get_size, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_current_inhibitors, 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_PROPERTY("UserTasksMax", "t", NULL, offsetof(Manager, user_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST), 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 8552c464cc..6bd08adc05 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -34,4 +34,6 @@ 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.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max) +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-inhibit.c b/src/login/logind-inhibit.c index a0e3ba2b7c..6c78e0dddc 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -317,7 +317,7 @@ int inhibitor_create_fifo(Inhibitor *i) { if (r < 0) return r; - r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE); + r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE-10); if (r < 0) return r; } diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index 3cee10d009..f934a5326a 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -306,7 +306,7 @@ const sd_bus_vtable seat_vtable[] = { SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), - SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0), SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), diff --git a/src/login/logind-session.c b/src/login/logind-session.c index a8b1d5943d..d2f1f7bc62 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -897,7 +897,9 @@ int session_create_fifo(Session *s) { if (r < 0) return r; - r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE); + /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new + * sessions). */ + r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10); if (r < 0) return r; } diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index b73f9ea69e..af6392e025 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -245,7 +245,7 @@ const sd_bus_vtable user_vtable[] = { SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0), - SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0), SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), diff --git a/src/login/logind.c b/src/login/logind.c index a48e2fc61e..caf149cfb7 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -62,7 +62,9 @@ static void manager_reset_config(Manager *m) { m->idle_action = HANDLE_IGNORE; m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ - m->user_tasks_max = UINT64_C(12288); + m->user_tasks_max = 12288; + m->sessions_max = 8192; + m->inhibitors_max = 8192; m->kill_user_processes = KILL_USER_PROCESSES; @@ -686,7 +688,7 @@ static int manager_connect_bus(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to register name: %m"); - r = sd_bus_attach_event(m->bus, m->event, 0); + r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL); if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop: %m"); diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in index 3c96def45d..32c0844cb6 100644 --- a/src/login/logind.conf.in +++ b/src/login/logind.conf.in @@ -32,4 +32,6 @@ #IdleActionSec=30min #RuntimeDirectorySize=10% #RemoveIPC=yes +#InhibitorsMax=8192 +#SessionsMax=8192 #UserTasksMax=12288 diff --git a/src/login/logind.h b/src/login/logind.h index 6748af3c07..90431eb4b0 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -133,6 +133,8 @@ struct Manager { size_t runtime_dir_size; uint64_t user_tasks_max; + uint64_t sessions_max; + uint64_t inhibitors_max; }; int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device); diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 6072c1e2de..b67a1f6d09 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -70,7 +70,7 @@ int config_parse_duid_rawdata( for (;;) { int n1, n2, len, r; uint32_t byte; - char *cbyte; + _cleanup_free_ char *cbyte = NULL; r = extract_first_word(&rvalue, &cbyte, ":", 0); if (r < 0) { diff --git a/src/network/networkd.h b/src/network/networkd.h index 26d9e7d6e0..ab512f0d08 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -41,7 +41,6 @@ #include "networkd-netdev-tuntap.h" #include "networkd-netdev-veth.h" #include "networkd-netdev-vlan.h" -#include "networkd-netdev-vlan.h" #include "networkd-netdev-vxlan.h" #include "networkd-network.h" #include "networkd-util.h" diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index 8a62a2a567..9bd30b82c6 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -47,10 +47,12 @@ static void test_config_parse_duid_type(void) { static void test_config_parse_duid_rawdata_one(const char *rvalue, int ret, const DUID* expected) { DUID actual = {}; int r; + _cleanup_free_ char *d = NULL; r = config_parse_duid_rawdata("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL); + d = hexmem(actual.raw_data, actual.raw_data_len); log_info_errno(r, "\"%s\" → \"%s\" (%m)", - rvalue, strnull(hexmem(actual.raw_data, actual.raw_data_len))); + rvalue, strnull(d)); assert_se(r == ret); if (expected) { assert_se(actual.raw_data_len == expected->raw_data_len); |