killall: gracefully handle processes inserted into containers via nsenter -a
authorLennart Poettering <lennart@poettering.net>
Wed, 20 Nov 2024 11:02:46 +0000 (12:02 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 28 Nov 2024 14:11:07 +0000 (15:11 +0100)
"nsenter -a" doesn't migrate the specified process into the target
cgroup (it really should). Thus the cgroup will remain in a cgroup
that is (due to cgroup ns) outside our visibility. The kernel will
report the cgroup path of such cgroups as starting with "/../". Detect
that and print a reasonably error message instead of trying to resolve
that.

(cherry picked from commit f6793bbcf0e3f0a6daa77add96183b88d5ec2117)

src/basic/cgroup-util.c
src/shared/killall.c

index b0fe0ecbe8f122a320d79ddca4af2b2567421018..e704362a32044cf118dc261dbaafad91ee8e377c 100644 (file)
@@ -838,6 +838,10 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **ret_path) {
                 if (!path)
                         return -ENOMEM;
 
+                /* Refuse cgroup paths from outside our cgroup namespace */
+                if (startswith(path, "/../"))
+                        return -EUNATCH;
+
                 /* Truncate suffix indicating the process is a zombie */
                 e = endswith(path, " (deleted)");
                 if (e)
index a08736480effb6be4f1e406d394888230bff48ba..184aec018bdfa99d4e36f27e52b7dfbae3d8dba5 100644 (file)
@@ -46,13 +46,17 @@ static bool argv_has_at(pid_t pid) {
         return c == '@';
 }
 
-static bool is_survivor_cgroup(const PidRef *pid) {
+static bool is_in_survivor_cgroup(const PidRef *pid) {
         _cleanup_free_ char *cgroup_path = NULL;
         int r;
 
         assert(pidref_is_set(pid));
 
         r = cg_pidref_get_path(/* root= */ NULL, pid, &cgroup_path);
+        if (r == -EUNATCH) {
+                log_warning_errno(r, "Process " PID_FMT " appears to originate in foreign namespace, ignoring.", pid->pid);
+                return true;
+        }
         if (r < 0) {
                 log_warning_errno(r, "Failed to get cgroup path of process " PID_FMT ", ignoring: %m", pid->pid);
                 return false;
@@ -86,7 +90,7 @@ static bool ignore_proc(const PidRef *pid, bool warn_rootfs) {
                 return true; /* also ignore processes where we can't determine this */
 
         /* Ignore processes that are part of a cgroup marked with the user.survive_final_kill_signal xattr */
-        if (is_survivor_cgroup(pid))
+        if (is_in_survivor_cgroup(pid))
                 return true;
 
         r = pidref_get_uid(pid, &uid);