From: Luca Boccassi Date: Wed, 1 Jul 2026 15:59:43 +0000 (+0100) Subject: core: donate the fdset to do_reexecute() to avoid a double free X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=b64a44707d4e0e15974b21cb17cbc6df506b9a7f;p=thirdparty%2Fsystemd.git core: donate the fdset to do_reexecute() to avoid a double free 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 --- diff --git a/src/core/main.c b/src/core/main.c index f8a7bd0760d..01911630dc4 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -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,