summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--src/basic/missing_syscall.h12
-rw-r--r--src/basic/process-util.c3
-rw-r--r--src/basic/raw-clone.h81
-rw-r--r--src/core/main.c5
-rw-r--r--src/nspawn/nspawn.c6
-rw-r--r--src/test/test-util.c3
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();