1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-23 21:35:11 +03:00

process-util: add clone_with_nested_stack() helper

This wraps glibc's clone() but deals with the 'stack' parameter in a
sensible way. Only supports invocations without CLONE_VM, i.e. when
child is a CoW copy of parent.
This commit is contained in:
Lennart Poettering 2023-06-22 10:27:17 +02:00
parent 09f9530baf
commit 29c3520f28
2 changed files with 37 additions and 0 deletions

View File

@ -1149,6 +1149,41 @@ static void restore_sigsetp(sigset_t **ssp) {
(void) sigprocmask(SIG_SETMASK, *ssp, NULL);
}
pid_t clone_with_nested_stack(int (*fn)(void *), int flags, void *userdata) {
size_t ps;
pid_t pid;
void *mystack;
/* A wrapper around glibc's clone() call that automatically sets up a "nested" stack. Only supports
* invocations without CLONE_VM, so that we can continue to use the parent's stack mapping.
*
* Note: glibc's clone() wrapper does not synchronize malloc() locks. This means that if the parent
* is threaded these locks will be in an undefined state in the child, and hence memory allocations
* are likely going to run into deadlocks. Hence: if you use this function make sure your parent is
* strictly single-threaded or your child never calls malloc(). */
assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID|
CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0);
/* We allocate some space on the stack to use as the stack for the child (hence "nested"). Note that
* the net effect is that the child will have the start of its stack inside the stack of the parent,
* but since they are a CoW copy of each other that's fine. We allocate one page-aligned page. But
* since we don't want to deal with differences between systems where the stack grows backwards or
* forwards we'll allocate one more and place the stack address in the middle. Except that we also
* want it page aligned, hence we'll allocate one page more. Makes 3. */
ps = page_size();
mystack = alloca(ps*3);
mystack = (uint8_t*) mystack + ps; /* move pointer one page ahead since stacks usually grow backwards */
mystack = (void*) ALIGN_TO((uintptr_t) mystack, ps); /* align to page size (moving things further ahead) */
pid = clone(fn, mystack, flags, userdata);
if (pid < 0)
return -errno;
return pid;
}
int safe_fork_full(
const char *name,
const int stdio_fds[3],

View File

@ -139,6 +139,8 @@ void reset_cached_pid(void);
int must_be_root(void);
pid_t clone_with_nested_stack(int (*fn)(void *), int flags, void *userdata);
typedef enum ForkFlags {
FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */
FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */