[LTP] [PATCH v7] Add EPERM test for clone and clone3
Stephen Bertram
sbertram@redhat.com
Wed Nov 19 19:56:40 CET 2025
Confirming EPERM is returned when CAP_SYS_ADMIN is
removed from clone and clone3.
And for clone3 the set_tid_size is greater than 0.
Signed-off-by: Stephen Bertram <sbertram@redhat.com>
---
runtest/syscalls | 2 +
testcases/kernel/syscalls/clone/.gitignore | 1 +
testcases/kernel/syscalls/clone/clone11.c | 74 ++++++++++++++++++
testcases/kernel/syscalls/clone3/.gitignore | 1 +
testcases/kernel/syscalls/clone3/clone304.c | 87 +++++++++++++++++++++
5 files changed, 165 insertions(+)
create mode 100644 testcases/kernel/syscalls/clone/clone11.c
create mode 100644 testcases/kernel/syscalls/clone3/clone304.c
diff --git a/runtest/syscalls b/runtest/syscalls
index 54d94c0ca..a1ef7548b 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -124,10 +124,12 @@ clone07 clone07
clone08 clone08
clone09 clone09
clone10 clone10
+clone11 clone11
clone301 clone301
clone302 clone302
clone303 clone303
+clone304 clone304
close01 close01
close02 close02
diff --git a/testcases/kernel/syscalls/clone/.gitignore b/testcases/kernel/syscalls/clone/.gitignore
index adfb8257d..0edcfef5d 100644
--- a/testcases/kernel/syscalls/clone/.gitignore
+++ b/testcases/kernel/syscalls/clone/.gitignore
@@ -8,3 +8,4 @@
/clone08
/clone09
/clone10
+/clone11
diff --git a/testcases/kernel/syscalls/clone/clone11.c b/testcases/kernel/syscalls/clone/clone11.c
new file mode 100644
index 000000000..e0ae9db62
--- /dev/null
+++ b/testcases/kernel/syscalls/clone/clone11.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Stephen Bertram <sbertram@redhat.com>
+ */
+
+/*\
+ * This test verifies that :man2:`clone` fails with EPERM when CAP_SYS_ADMIN
+ * has been dropped.
+ */
+
+#define _GNU_SOURCE
+#define DESC(x) .flags = x, .sflags = #x
+
+#include "tst_test.h"
+#include "clone_platform.h"
+#include "lapi/sched.h"
+
+static void *child_stack;
+static int *child_pid;
+
+static struct tcase {
+ uint64_t flags;
+ const char *sflags;
+} tcases[] = {
+ { DESC(CLONE_NEWPID) },
+ { DESC(CLONE_NEWCGROUP) },
+ { DESC(CLONE_NEWIPC) },
+ { DESC(CLONE_NEWNET) },
+ { DESC(CLONE_NEWNS) },
+ { DESC(CLONE_NEWUTS) },
+};
+
+static int child_fn(void *arg LTP_ATTRIBUTE_UNUSED)
+{
+ *child_pid = getpid();
+ _exit(0);
+}
+
+static void run(unsigned int n)
+{
+ struct tcase *tc = &tcases[n];
+
+ TST_EXP_FAIL(ltp_clone(tc->flags, child_fn, NULL, CHILD_STACK_SIZE,
+ child_stack), EPERM, "clone(%s) should fail with EPERM",
+ tc->sflags);
+}
+
+static void setup(void)
+{
+ child_pid = SAFE_MMAP(NULL, sizeof(*child_pid), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+}
+
+static void cleanup(void)
+{
+ if (child_pid)
+ SAFE_MUNMAP(child_pid, sizeof(*child_pid));
+}
+
+static struct tst_test test = {
+ .tcnt = ARRAY_SIZE(tcases),
+ .setup = setup,
+ .test = run,
+ .cleanup = cleanup,
+ .needs_root = 1,
+ .caps = (struct tst_cap []) {
+ TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN),
+ {},
+ },
+ .bufs = (struct tst_buffers []) {
+ {&child_stack, .size = CHILD_STACK_SIZE},
+ {},
+ },
+};
diff --git a/testcases/kernel/syscalls/clone3/.gitignore b/testcases/kernel/syscalls/clone3/.gitignore
index 10369954b..e9b5312f4 100644
--- a/testcases/kernel/syscalls/clone3/.gitignore
+++ b/testcases/kernel/syscalls/clone3/.gitignore
@@ -1,3 +1,4 @@
clone301
clone302
clone303
+clone304
diff --git a/testcases/kernel/syscalls/clone3/clone304.c b/testcases/kernel/syscalls/clone3/clone304.c
new file mode 100644
index 000000000..a53e5fdca
--- /dev/null
+++ b/testcases/kernel/syscalls/clone3/clone304.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Stephen Bertram <sbertram@redhat.com>
+ */
+
+/*\
+ * This test verifies that :man2:`clone3` fails with EPERM when CAP_SYS_ADMIN
+ * has been dropped and ``clone_args.set_tid_size`` is greater than zero.
+ */
+
+#define _GNU_SOURCE
+#define DESC(x) .flags = x, .sflags = #x
+
+#include "tst_test.h"
+#include "lapi/sched.h"
+
+enum case_type {
+ K_SET_TID, /* flags = 0 || CLONE_NEW*, set_tid_size > 0 => EPERM */
+ K_NAMESPACE_ONLY, /* flags = CLONE_NEW*, set_tid_size = 0 => EPERM */
+};
+
+static struct clone_args args = {0};
+static pid_t tid_array[1] = {1};
+
+static struct tcase {
+ uint64_t flags;
+ const char *sflags;
+ enum case_type type;
+} tcases[] = {
+ { DESC(CLONE_NEWPID), K_NAMESPACE_ONLY },
+ { DESC(CLONE_NEWCGROUP), K_NAMESPACE_ONLY },
+ { DESC(CLONE_NEWIPC), K_NAMESPACE_ONLY },
+ { DESC(CLONE_NEWNET), K_NAMESPACE_ONLY },
+ { DESC(CLONE_NEWNS), K_NAMESPACE_ONLY },
+ { DESC(CLONE_NEWUTS), K_NAMESPACE_ONLY },
+
+ { DESC(CLONE_NEWPID), K_SET_TID },
+ { DESC(CLONE_NEWCGROUP), K_SET_TID },
+ { DESC(CLONE_NEWIPC), K_SET_TID },
+ { DESC(CLONE_NEWNET), K_SET_TID },
+ { DESC(CLONE_NEWNS), K_SET_TID },
+ { DESC(CLONE_NEWUTS), K_SET_TID },
+
+ { DESC(0), K_SET_TID },
+};
+
+static void run(unsigned int n)
+{
+ struct tcase *tc = &tcases[n];
+
+ args.flags = tc->flags;
+
+ if (tc->type == K_NAMESPACE_ONLY) {
+ args.set_tid = 0;
+ args.set_tid_size = 0;
+ } else {
+ args.set_tid = (uint64_t)(uintptr_t)tid_array;
+ args.set_tid_size = 1;
+ }
+
+ TST_EXP_FAIL(clone3(&args, sizeof(args)), EPERM,
+ "clone3(%s) set_tid_size=%ld",
+ tc->sflags, args.set_tid_size);
+}
+
+static void setup(void)
+{
+ clone3_supported_by_kernel();
+
+ memset(&args, 0, sizeof(args));
+ SAFE_UNSHARE(CLONE_NEWUSER | CLONE_NEWNS);
+}
+
+static struct tst_test test = {
+ .tcnt = ARRAY_SIZE(tcases),
+ .setup = setup,
+ .test = run,
+ .needs_root = 1,
+ .caps = (struct tst_cap []) {
+ TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN),
+ {},
+ },
+ .bufs = (struct tst_buffers []) {
+ {&args, .size = sizeof(struct clone_args)},
+ {},
+ },
+};
--
2.49.0
More information about the ltp
mailing list