]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: donate the fdset to do_reexecute() to avoid a double free
authorLuca Boccassi <luca.boccassi@gmail.com>
Wed, 1 Jul 2026 15:59:43 +0000 (16:59 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 1 Jul 2026 21:46:45 +0000 (22:46 +0100)
do_reexecute() freed the FDSet on the switch-root/soft-reboot fallback
but the caller's copy stayed live, so main() freed it again if every
fallback exec then failed. Donate the fdset instead: pass it with
TAKE_PTR() and take ownership via a _cleanup_ local, freeing it exactly
once on every exit path.

Follow-up for 3c7878f94b02f65676889fa58a937ff4d4de4a4d

src/core/main.c

index f8a7bd0760dcbfea6cb4c81c233d318f8d5f7d58..01911630dc4a0238f23661aecebfd2faaabbcf67 100644 (file)
@@ -2123,7 +2123,7 @@ static int do_reexecute(
                 char* argv[],
                 const struct rlimit *saved_rlimit_nofile,
                 const struct rlimit *saved_rlimit_memlock,
-                FDSet *fds,
+                FDSet *_fds, /* donated */
                 const char *switch_root_dir,
                 const char *switch_root_init,
                 uint64_t saved_capability_ambient_set,
@@ -2139,6 +2139,9 @@ static int do_reexecute(
         assert(saved_rlimit_memlock);
         assert(ret_error_message);
 
+        /* The fdset is donated to us, take ownership so it is freed on all exit paths. */
+        _cleanup_fdset_free_ FDSet *fds = TAKE_PTR(_fds);
+
         /* Close and disarm the watchdog, so that the new instance can reinitialize it, but the machine
          * doesn't get rebooted while we do that. */
         watchdog_close(/* disarm= */ true);
@@ -3848,7 +3851,7 @@ finish:
                                  argc, argv,
                                  &saved_rlimit_nofile,
                                  &saved_rlimit_memlock,
-                                 fds,
+                                 TAKE_PTR(fds),
                                  switch_root_dir,
                                  switch_root_init,
                                  saved_ambient_set,