mirror of
https://github.com/systemd/systemd.git
synced 2024-10-26 08:55:40 +03:00
async: make sure to set argv[0][0] to '@' to avoid being killed in killing spree
Prompted by: #32223
This commit is contained in:
parent
fecea05e15
commit
319c8e3189
@ -1457,11 +1457,20 @@ int safe_fork_full(
|
||||
sigset_t saved_ss, ss;
|
||||
_unused_ _cleanup_(restore_sigsetp) sigset_t *saved_ssp = NULL;
|
||||
bool block_signals = false, block_all = false, intermediary = false;
|
||||
_cleanup_free_ char *prefixed_name = NULL;
|
||||
int prio, r;
|
||||
|
||||
assert(!FLAGS_SET(flags, FORK_DETACH) || !ret_pid);
|
||||
assert(!FLAGS_SET(flags, FORK_DETACH|FORK_WAIT));
|
||||
|
||||
if (name && FLAGS_SET(flags, FORK_ARGV00_AT)) {
|
||||
/* Optionally, ensure argv[0][0] is '@', in order to implement https://systemd.io/ROOT_STORAGE_DAEMONS */
|
||||
prefixed_name = strjoin("@", name);
|
||||
if (!prefixed_name)
|
||||
return -ENOMEM;
|
||||
name = prefixed_name;
|
||||
}
|
||||
|
||||
/* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always
|
||||
* returns the child's PID in *ret_pid. Returns == 0 in the child, and > 0 in the parent. */
|
||||
|
||||
|
@ -186,6 +186,7 @@ typedef enum ForkFlags {
|
||||
FORK_DETACH = 1 << 18, /* Double fork if needed to ensure PID1/subreaper is parent */
|
||||
FORK_NEW_NETNS = 1 << 19, /* Run child in its own network namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
|
||||
FORK_PACK_FDS = 1 << 20, /* Rearrange the passed FDs to be FD 3,4,5,etc. Updates the array in place (combine with FORK_CLOSE_ALL_FDS!) */
|
||||
FORK_ARGV00_AT = 1 << 21, /* Prefix supplied name with '@', to exclude child process from final killing spree */
|
||||
} ForkFlags;
|
||||
|
||||
int safe_fork_full(
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "argv-util.h"
|
||||
#include "async.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
@ -22,7 +23,14 @@ int asynchronous_sync(pid_t *ret_pid) {
|
||||
* original process ever, and a thread would do that as the process can't exit with threads hanging in blocking
|
||||
* syscalls. */
|
||||
|
||||
r = safe_fork("(sd-sync)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|(ret_pid ? 0 : FORK_DETACH), ret_pid);
|
||||
/* Note that we set argv[0][0] = '@' here if we are called from PID 1, which tells the
|
||||
* switch-root/soft-reboot/shutdown killing spree to leave this process around. After all the killing
|
||||
* is likely not going to work anyway, and given the limited scope of the child it's really not worth
|
||||
* killing it. */
|
||||
|
||||
r = safe_fork("(sd-sync)",
|
||||
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|(ret_pid ? 0 : FORK_DETACH)|(getpid_cached() == 1 ? FORK_ARGV00_AT : 0),
|
||||
ret_pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
@ -41,12 +49,23 @@ int asynchronous_sync(pid_t *ret_pid) {
|
||||
static int close_func(void *p) {
|
||||
unsigned v = PTR_TO_UINT(p);
|
||||
|
||||
(void) prctl(PR_SET_NAME, (unsigned long*) "(sd-close)");
|
||||
|
||||
/* Note: 💣 This function is invoked in a child process created via glibc's clone() wrapper. In such
|
||||
* children memory allocation is not allowed, since glibc does not release malloc mutexes in
|
||||
* clone() 💣 */
|
||||
|
||||
/* This is a poor man's version of rename_process(). We don't use the real thing to avoid any memory
|
||||
* allocations. We set argv[0][0] to '@' if invoked by PID 1 to exclude us from the
|
||||
* switch-root/soft-reboot/shutdown killing spree, since it would likely fail anyway, and with a
|
||||
* process of such minimal scope is not really worh the effort anyway. */
|
||||
const char *comm;
|
||||
if (getppid() == 1) {
|
||||
if (saved_argc >= 1 && !isempty(saved_argv[0]))
|
||||
saved_argv[0][0] = '@';
|
||||
comm = "@(sd-close)";
|
||||
} else
|
||||
comm = "(sd-close)";
|
||||
(void) prctl(PR_SET_NAME, comm);
|
||||
|
||||
if (v & NEED_DOUBLE_FORK) {
|
||||
pid_t pid;
|
||||
|
||||
@ -117,9 +136,15 @@ int asynchronous_rm_rf(const char *p, RemoveFlags flags) {
|
||||
assert(p);
|
||||
|
||||
/* Forks off a child that destroys the specified path. This will be best effort only, i.e. the child
|
||||
* will attempt to do its thing, but we won't wait for it or check its success. */
|
||||
* will attempt to do its thing, but we won't wait for it or check its success.
|
||||
*
|
||||
* We do set argv[0][0] = '@' here however (if we are invoked as PID 1), to ensure that the this is
|
||||
* excluded from the switch-root/soft-reboot/poweroff killing spree, and can definitely complete it's
|
||||
* job. */
|
||||
|
||||
r = safe_fork("(sd-rmrf)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DETACH, NULL);
|
||||
r = safe_fork("(sd-rmrf)",
|
||||
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DETACH|(getpid_cached() == 1 ? FORK_ARGV00_AT : 0),
|
||||
/* ret_pid= */ NULL);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user