]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: set pids.max=0 before sending SIGKILL to cgroup
authorLuca Boccassi <luca.boccassi@gmail.com>
Fri, 29 May 2026 21:49:34 +0000 (22:49 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Sat, 20 Jun 2026 09:53:04 +0000 (10:53 +0100)
When doing the final SIGKILL when stopping units ensure no more
processes can be created by setting pids.max=0 in the cgroup.

src/core/unit.c

index 8684471d57ee1dfdd4e9939e7c955540116f62a0..0936e422958962aa9874fbc6162dc6ccd69f8523 100644 (file)
@@ -5032,6 +5032,35 @@ static int unit_kill_context_one(
         return !is_alien;
 }
 
+typedef struct PidsMaxRestore {
+        const char *cgroup_path;
+        uint64_t max;
+        Unit *unit;
+} PidsMaxRestore;
+
+static void pids_max_restore(PidsMaxRestore *p) {
+        int r;
+
+        assert(p);
+        assert(p->unit);
+
+        if (!p->cgroup_path)
+                return;
+
+        char value[DECIMAL_STR_MAX(uint64_t) + 1] = "max";
+        if (p->max != CGROUP_LIMIT_MAX)
+                xsprintf(value, "%" PRIu64, p->max);
+
+        r = cg_set_attribute(p->cgroup_path, "pids.max", value);
+        if (r < 0)
+                log_unit_warning_errno(p->unit,
+                                       r,
+                                       "Failed to restore pids.max to %s for control group %s, ignoring: %m",
+                                       value, empty_to_root(p->cgroup_path));
+
+        p->cgroup_path = NULL;
+}
+
 int unit_kill_context(Unit *u, KillOperation k) {
         bool wait_for_exit = false, send_sighup;
         cg_kill_log_func_t log_func = NULL;
@@ -5068,8 +5097,32 @@ int unit_kill_context(Unit *u, KillOperation k) {
         CGroupRuntime *crt = unit_get_cgroup_runtime(u);
         if (crt && crt->cgroup_path &&
             (c->kill_mode == KILL_CONTROL_GROUP || (c->kill_mode == KILL_MIXED && k == KILL_KILL))) {
+                _cleanup_(pids_max_restore) PidsMaxRestore state = {
+                        .unit = u,
+                };
                 _cleanup_set_free_ Set *pid_set = NULL;
 
+                /* Stop more processes from being spawned when zapping the cgroup. Restore previous state
+                 * before returning. */
+                if (sig == SIGKILL) {
+                        r = cg_get_attribute_as_uint64(crt->cgroup_path, "pids.max", &state.max);
+                        if (r < 0)
+                                log_unit_warning_errno(u,
+                                                       r,
+                                                       "Failed to read pids.max for control group %s, ignoring: %m",
+                                                       empty_to_root(crt->cgroup_path));
+                        else {
+                                r = cg_set_attribute(crt->cgroup_path, "pids.max", "0");
+                                if (r < 0)
+                                        log_unit_warning_errno(u,
+                                                               r,
+                                                               "Failed to set pids.max to 0 for control group %s, ignoring: %m",
+                                                               empty_to_root(crt->cgroup_path));
+                                else
+                                        state.cgroup_path = crt->cgroup_path;
+                        }
+                }
+
                 /* Exclude the main/control pids from being killed via the cgroup */
                 r = unit_pid_set(u, &pid_set);
                 if (r < 0)