]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
process-util: revamp flags handling in namespace_fork()
authorMike Yuan <me@yhndnzj.com>
Sun, 14 Dec 2025 15:02:17 +0000 (16:02 +0100)
committerMike Yuan <me@yhndnzj.com>
Sat, 20 Dec 2025 13:14:24 +0000 (14:14 +0100)
* Specifying all 3 of FORK_DEATHSIG_SIG{KILL,TERM,INT} for
  the middle man makes zero sense. Use SIGKILL only.
* Make sure operations on except_fds work sensibly - close/pack/
  de-ocloexecify fds only in the second level, so that the namespace
  fds remain usable across first safe_fork().
* Fire FORK_NEW_*NS after attaching to the desired namespaces,
  not already in the outer process.
* Insist on PDEATHSIG being enabled to ensure propagation of killing.
* Suppress more redundant flags.

src/basic/process-util.c

index 700fba5cbaede1e21ad59b0f27ebf54ff541aad1..0a87c5ec770ffac0fee3cef5f91fb93354bd41be 100644 (file)
@@ -1901,14 +1901,21 @@ int namespace_fork_full(
 
         /* This is much like safe_fork(), but forks twice, and joins the specified namespaces in the middle
          * process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that
-         * /proc/self/fd works correctly. */
+         * /proc/self/fd works correctly.
+         *
+         * TODO: once we can rely on PIDFD_INFO_EXIT, do not keep the middle process around and instead
+         * return the pidfd of the inner process for direct tracking. */
+
+        /* Insist on PDEATHSIG being enabled, as the pid returned is the one of the middle man, and otherwise
+         * killing of it won't be propagated to the inner child. */
+        assert((flags & (FORK_DEATHSIG_SIGKILL|FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT)) != 0);
+        assert((flags & (FORK_DETACH|FORK_FREEZE)) == 0);
         assert(!FLAGS_SET(flags, FORK_ALLOW_DLOPEN)); /* never allow loading shared library from another ns */
 
         r = pidref_safe_fork_full(
                         outer_name,
-                        NULL,
-                        except_fds, n_except_fds,
-                        (flags|FORK_DEATHSIG_SIGINT|FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGKILL) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE),
+                        /* stdio_fds = */ NULL, /* except_fds = */ NULL, /* n_except_fds = */ 0,
+                        (flags|FORK_DEATHSIG_SIGKILL) & ~(FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT|FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS|FORK_NEW_NETNS|FORK_NEW_PIDNS|FORK_CLOSE_ALL_FDS|FORK_PACK_FDS|FORK_CLOEXEC_OFF|FORK_RLIMIT_NOFILE_SAFE),
                         ret);
         if (r < 0)
                 return r;
@@ -1928,7 +1935,7 @@ int namespace_fork_full(
                                 inner_name,
                                 NULL,
                                 except_fds, n_except_fds,
-                                flags & ~(FORK_WAIT|FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REARRANGE_STDIO),
+                                flags & ~(FORK_WAIT|FORK_RESET_SIGNALS|FORK_REARRANGE_STDIO|FORK_FLUSH_STDIO|FORK_STDOUT_TO_STDERR),
                                 &pidref_inner);
                 if (r < 0)
                         _exit(EXIT_FAILURE);
@@ -1939,6 +1946,11 @@ int namespace_fork_full(
                         return 0;
                 }
 
+                log_close();
+                log_set_open_when_needed(true);
+
+                (void) close_all_fds(&pidref_inner.fd, 1);
+
                 r = pidref_wait_for_terminate_and_check(
                                 inner_name,
                                 &pidref_inner,