core: apply ReloadLimit to reexec too

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.
This commit is contained in:
Luca Boccassi 2024-03-29 01:29:07 +00:00
parent 9b1db2dbc4
commit 8312b17a29
6 changed files with 30 additions and 12 deletions

View file

@ -624,10 +624,12 @@
<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>

View 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. */

View 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);

View 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;

View 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;

View file

@ -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