diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | src/basic/missing_syscall.h | 12 | ||||
-rw-r--r-- | src/basic/process-util.c | 3 | ||||
-rw-r--r-- | src/basic/raw-clone.h | 81 | ||||
-rw-r--r-- | src/core/main.c | 5 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 6 | ||||
-rw-r--r-- | src/test/test-util.c | 3 |
7 files changed, 92 insertions, 19 deletions
diff --git a/Makefile.am b/Makefile.am index f8e1fac967..c31c30c051 100644 --- a/Makefile.am +++ b/Makefile.am @@ -746,6 +746,7 @@ noinst_LTLIBRARIES += \ libbasic_la_SOURCES = \ src/basic/missing.h \ src/basic/missing_syscall.h \ + src/basic/raw-clone.h \ src/basic/capability-util.c \ src/basic/capability-util.h \ src/basic/conf-files.c \ diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index d502d3b9ca..e102083684 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -178,18 +178,6 @@ static inline int setns(int fd, int nstype) { /* ======================================================================= */ -static inline int raw_clone(unsigned long flags, void *child_stack) { -#if defined(__s390__) || defined(__CRIS__) - /* On s390 and cris the order of the first and second arguments - * of the raw clone() system call is reversed. */ - return (int) syscall(__NR_clone, child_stack, flags); -#else - return (int) syscall(__NR_clone, flags, child_stack); -#endif -} - -/* ======================================================================= */ - static inline pid_t raw_getpid(void) { #if defined(__alpha__) return (pid_t) syscall(__NR_getxpid); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 1ad8816206..b991e7c6ba 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -48,6 +48,7 @@ #include "macro.h" #include "missing.h" #include "process-util.h" +#include "raw-clone.h" #include "signal-util.h" #include "stat-util.h" #include "string-table.h" @@ -726,7 +727,7 @@ void valgrind_summary_hack(void) { #ifdef HAVE_VALGRIND_VALGRIND_H if (getpid() == 1 && RUNNING_ON_VALGRIND) { pid_t pid; - pid = raw_clone(SIGCHLD, NULL); + pid = raw_clone(SIGCHLD); if (pid < 0) log_emergency_errno(errno, "Failed to fork off valgrind helper: %m"); else if (pid == 0) diff --git a/src/basic/raw-clone.h b/src/basic/raw-clone.h new file mode 100644 index 0000000000..d473828999 --- /dev/null +++ b/src/basic/raw-clone.h @@ -0,0 +1,81 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2016 Michael Karcher + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sched.h> +#include <sys/syscall.h> + +#include "log.h" +#include "macro.h" + +/** + * raw_clone() - uses clone to create a new process with clone flags + * @flags: Flags to pass to the clone system call + * + * Uses the clone system call to create a new process with the cloning + * flags and termination signal passed in the flags parameter. Opposed + * to glibc's clone funtion, using this function does not set up a + * separate stack for the child, but relies on copy-on-write semantics + * on the one stack at a common virtual address, just as fork does. + * + * To obtain copy-on-write semantics, flags must not contain CLONE_VM, + * and thus CLONE_THREAD and CLONE_SIGHAND (which require CLONE_VM) are + * not usabale. + * Additionally, as this function does not pass the ptid, newtls and ctid + * parameters to the kernel, flags must not contain CLONE_PARENT_SETTID, + * CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID or CLONE_SETTLS. + * + * Returns: 0 in the child process and the child process id in the parent. + */ +static inline int raw_clone(unsigned long flags) { + assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID| + CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0); +#if defined(__s390__) || defined(__CRIS__) + /* On s390 and cris the order of the first and second arguments + * of the raw clone() system call is reversed. */ + return (int) syscall(__NR_clone, NULL, flags); +#elif defined(__sparc__) && defined(__arch64__) + { + /** + * sparc64 always returns the other process id in %o0, and + * a boolean flag whether this is the child or the parent in + * %o1. Inline assembly is needed to get the flag returned + * in %o1. + */ + int in_child; + int child_pid; + asm volatile("mov %2, %%g1\n\t" + "mov %3, %%o0\n\t" + "mov 0 , %%o1\n\t" + "t 0x6d\n\t" + "mov %%o1, %0\n\t" + "mov %%o0, %1" : + "=r"(in_child), "=r"(child_pid) : + "i"(__NR_clone), "r"(flags) : + "%o1", "%o0", "%g1" ); + if (in_child) + return 0; + else + return child_pid; + } +#else + return (int) syscall(__NR_clone, flags, NULL); +#endif +} diff --git a/src/core/main.c b/src/core/main.c index 6397aadc73..93098daa9b 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -70,6 +70,7 @@ #include "parse-util.h" #include "proc-cmdline.h" #include "process-util.h" +#include "raw-clone.h" #include "rlimit-util.h" #include "selinux-setup.h" #include "selinux-util.h" @@ -162,7 +163,7 @@ noreturn static void crash(int sig) { /* We want to wait for the core process, hence let's enable SIGCHLD */ (void) sigaction(SIGCHLD, &sa, NULL); - pid = raw_clone(SIGCHLD, NULL); + pid = raw_clone(SIGCHLD); if (pid < 0) log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig)); else if (pid == 0) { @@ -221,7 +222,7 @@ noreturn static void crash(int sig) { log_notice("Executing crash shell in 10s..."); (void) sleep(10); - pid = raw_clone(SIGCHLD, NULL); + pid = raw_clone(SIGCHLD); if (pid < 0) log_emergency_errno(errno, "Failed to fork off crash shell: %m"); else if (pid == 0) { diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index b421c182ce..d1c65e8b0b 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -85,6 +85,7 @@ #include "process-util.h" #include "ptyfwd.h" #include "random-util.h" +#include "raw-clone.h" #include "rm-rf.h" #include "selinux-util.h" #include "signal-util.h" @@ -2938,8 +2939,7 @@ static int outer_child( pid = raw_clone(SIGCHLD|CLONE_NEWNS| (arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS) | (arg_private_network ? CLONE_NEWNET : 0) | - (arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0), - NULL); + (arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0)); if (pid < 0) return log_error_errno(errno, "Failed to fork inner child: %m"); if (pid == 0) { @@ -3608,7 +3608,7 @@ int main(int argc, char *argv[]) { goto finish; } - pid = raw_clone(SIGCHLD|CLONE_NEWNS, NULL); + pid = raw_clone(SIGCHLD|CLONE_NEWNS); if (pid < 0) { if (errno == EINVAL) r = log_error_errno(errno, "clone() failed, do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in): %m"); diff --git a/src/test/test-util.c b/src/test/test-util.c index 05cb1eae76..9b6d2a7968 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -26,6 +26,7 @@ #include "def.h" #include "fileio.h" #include "fs-util.h" +#include "raw-clone.h" #include "rm-rf.h" #include "string-util.h" #include "util.h" @@ -244,7 +245,7 @@ static void test_raw_clone(void) { log_info("before clone: getpid()→"PID_FMT, parent); assert_se(raw_getpid() == parent); - pid = raw_clone(0, NULL); + pid = raw_clone(0); assert_se(pid >= 0); pid2 = raw_getpid(); |