Merge pull request #32010 from bluca/reexec_rate_limit

core: serialize reload rate limit and apply ReloadLimit to reexec too
This commit is contained in:
Luca Boccassi 2024-03-29 17:16:36 +00:00 committed by GitHub
commit a7f2019055
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 30 additions and 9 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,6 +156,7 @@ int manager_serialize(
}
(void) serialize_ratelimit(f, "dump-ratelimit", &m->dump_ratelimit);
(void) serialize_ratelimit(f, "reload-reexec-ratelimit", &m->reload_reexec_ratelimit);
bus_track_serialize(m->subscribed, f, "subscribed");
@ -519,6 +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-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