core: apply ReloadLimit to reexec too
authorLuca Boccassi <bluca@debian.org>
Fri, 29 Mar 2024 01:29:07 +0000 (01:29 +0000)
committerLuca Boccassi <bluca@debian.org>
Fri, 29 Mar 2024 12:03:32 +0000 (12:03 +0000)
Same reason as the reload, reexec is disruptive and it requires the
same privileges, so if somebody wants to limit reloads, they'll also
want to limit reexecs, so use the same setting.

man/systemd-system.conf.xml
src/core/dbus-manager.c
src/core/main.c
src/core/manager-serialize.c
src/core/manager.h
test/units/testsuite-59.sh

index e6611d04e7a26d01eb557c09c11d0c579ffa11b7..88f13d05b61c58877a090c6f7b6b3ec1f711fc64 100644 (file)
         <term><varname>ReloadLimitIntervalSec=</varname></term>
         <term><varname>ReloadLimitBurst=</varname></term>
 
-        <listitem><para>Rate limiting for daemon-reload requests. Default to unset, and any number of daemon-reload
-        operations can be requested at any time. <varname>ReloadLimitIntervalSec=</varname> takes a value in seconds
-        to configure the rate limit window, and <varname>ReloadLimitBurst=</varname> takes a positive integer to
-        configure the maximum allowed number of reloads within the configured time window.</para>
+        <listitem><para>Rate limiting for daemon-reload and (since v256) daemon-reexec requests. The setting
+        applies to both operations, but the rate limits are tracked separately. Defaults to unset, and any
+        number of operations can be requested at any time. <varname>ReloadLimitIntervalSec=</varname> takes
+        a value in seconds to configure the rate limit window, and <varname>ReloadLimitBurst=</varname>
+        takes a positive integer to configure the maximum allowed number of operations within the configured
+        time window.</para>
 
         <xi:include href="version-info.xml" xpointer="v253"/></listitem>
       </varlistentry>
index bba466b90089b0427c573dd40914d509b0d1d0d5..fa85a5e6980be5e1f4b5497bd56d7a94998af8ca 100644 (file)
@@ -1599,7 +1599,7 @@ static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *
         log_caller(message, m, "Reloading");
 
         /* Check the rate limit after the authorization succeeds, to avoid denial-of-service issues. */
-        if (!ratelimit_below(&m->reload_ratelimit)) {
+        if (!ratelimit_below(&m->reload_reexec_ratelimit)) {
                 log_warning("Reloading request rejected due to rate limit.");
                 return sd_bus_error_setf(error,
                                          SD_BUS_ERROR_LIMITS_EXCEEDED,
@@ -1644,6 +1644,14 @@ static int method_reexecute(sd_bus_message *message, void *userdata, sd_bus_erro
         /* Write a log message noting the unit or process who requested the Reexecute() */
         log_caller(message, m, "Reexecuting");
 
+        /* Check the rate limit after the authorization succeeds, to avoid denial-of-service issues. */
+        if (!ratelimit_below(&m->reload_reexec_ratelimit)) {
+                log_warning("Reexecuting request rejected due to rate limit.");
+                return sd_bus_error_setf(error,
+                                         SD_BUS_ERROR_LIMITS_EXCEEDED,
+                                         "Reexecute() request rejected due to rate limit.");
+        }
+
         /* We don't send a reply back here, the client should
          * just wait for us disconnecting. */
 
index 1aeab10ddbc588eabf8f22a3282ebf55c54240c6..6f91a15b22b4248b914cf61c8ee6284a185f5e27 100644 (file)
@@ -810,8 +810,8 @@ static void set_manager_settings(Manager *m) {
         m->cad_burst_action = arg_cad_burst_action;
         /* Note that we don't do structured initialization here, otherwise it will reset the rate limit
          * counter on every daemon-reload. */
-        m->reload_ratelimit.interval = arg_reload_limit_interval_sec;
-        m->reload_ratelimit.burst = arg_reload_limit_burst;
+        m->reload_reexec_ratelimit.interval = arg_reload_limit_interval_sec;
+        m->reload_reexec_ratelimit.burst = arg_reload_limit_burst;
 
         manager_set_watchdog(m, WATCHDOG_RUNTIME, arg_runtime_watchdog);
         manager_set_watchdog(m, WATCHDOG_REBOOT, arg_reboot_watchdog);
index d3382084cbf9d8693c43e16f0526b58f3408bc35..884332b3249e536c7f6fe6db11c4050d11df45f4 100644 (file)
@@ -156,7 +156,7 @@ int manager_serialize(
         }
 
         (void) serialize_ratelimit(f, "dump-ratelimit", &m->dump_ratelimit);
-        (void) serialize_ratelimit(f, "reload-ratelimit", &m->reload_ratelimit);
+        (void) serialize_ratelimit(f, "reload-reexec-ratelimit", &m->reload_reexec_ratelimit);
 
         bus_track_serialize(m->subscribed, f, "subscribed");
 
@@ -520,8 +520,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                                 (void) varlink_server_deserialize_one(m->varlink_server, val, fds);
                 } else if ((val = startswith(l, "dump-ratelimit=")))
                         deserialize_ratelimit(&m->dump_ratelimit, "dump-ratelimit", val);
-                else if ((val = startswith(l, "reload-ratelimit=")))
-                        deserialize_ratelimit(&m->reload_ratelimit, "reload-ratelimit", val);
+                else if ((val = startswith(l, "reload-reexec-ratelimit=")))
+                        deserialize_ratelimit(&m->reload_reexec_ratelimit, "reload-reexec-ratelimit", val);
                 else if ((val = startswith(l, "soft-reboots-count="))) {
                         unsigned n;
 
index 0e2531a4a7d9007666f6bfb58e05d671cecc0853..9541a5e0b469dd23bc67d8f689eb8910d5df4e4a 100644 (file)
@@ -491,8 +491,8 @@ struct Manager {
         /* Reference to RestrictFileSystems= BPF program */
         struct restrict_fs_bpf *restrict_fs;
 
-        /* Allow users to configure a rate limit for Reload() operations */
-        RateLimit reload_ratelimit;
+        /* Allow users to configure a rate limit for Reload()/Reexecute() operations */
+        RateLimit reload_reexec_ratelimit;
         /* Dump*() are slow, so always rate limit them to 10 per 10 minutes */
         RateLimit dump_ratelimit;
 
index 61564dc1664e1800f8a3278cc051350219ace053..0e044037b85ade90b9b754fa0aaf18a0ecacda0d 100755 (executable)
@@ -104,6 +104,14 @@ sleep 10
 
 systemctl daemon-reload
 
+# Same test for reexec, but we wait here
+timeout 15 bash -c 'while systemctl daemon-reexec; do true; done'
+
+# Rate limit should reset after 9s
+sleep 10
+
+systemctl daemon-reexec
+
 # Let's now test the notify-reload logic
 
 cat >/run/notify-reload-test.sh <<EOF