Skip to content

Commit 8d18c72

Browse files
sbertramrhwangli5665
authored andcommitted
syscalls: Add EPERM test for clone and clone3
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 <[email protected]> Reviewed-by: Li Wang <[email protected]>
1 parent 869f4cb commit 8d18c72

File tree

5 files changed

+167
-0
lines changed

5 files changed

+167
-0
lines changed

runtest/syscalls

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,12 @@ clone07 clone07
124124
clone08 clone08
125125
clone09 clone09
126126
clone10 clone10
127+
clone11 clone11
127128

128129
clone301 clone301
129130
clone302 clone302
130131
clone303 clone303
132+
clone304 clone304
131133

132134
close01 close01
133135
close02 close02

testcases/kernel/syscalls/clone/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
/clone08
99
/clone09
1010
/clone10
11+
/clone11
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2025 Stephen Bertram <[email protected]>
4+
*/
5+
6+
/*\
7+
* This test verifies that :man2:`clone` fails with EPERM when CAP_SYS_ADMIN
8+
* has been dropped.
9+
*/
10+
11+
#define _GNU_SOURCE
12+
#define DESC(x) .flags = x, .sflags = #x
13+
14+
#include "tst_test.h"
15+
#include "clone_platform.h"
16+
#include "lapi/sched.h"
17+
18+
static void *child_stack;
19+
static int *child_pid;
20+
21+
static struct tcase {
22+
uint64_t flags;
23+
const char *sflags;
24+
} tcases[] = {
25+
{ DESC(CLONE_NEWPID) },
26+
{ DESC(CLONE_NEWCGROUP) },
27+
{ DESC(CLONE_NEWIPC) },
28+
{ DESC(CLONE_NEWNET) },
29+
{ DESC(CLONE_NEWNS) },
30+
{ DESC(CLONE_NEWUTS) },
31+
};
32+
33+
static int child_fn(void *arg LTP_ATTRIBUTE_UNUSED)
34+
{
35+
*child_pid = getpid();
36+
_exit(0);
37+
}
38+
39+
static void run(unsigned int n)
40+
{
41+
struct tcase *tc = &tcases[n];
42+
43+
TST_EXP_FAIL(ltp_clone(tc->flags, child_fn, NULL, CHILD_STACK_SIZE, child_stack),
44+
EPERM, "clone(%s) should fail with EPERM",
45+
tc->sflags);
46+
}
47+
48+
static void setup(void)
49+
{
50+
child_pid = SAFE_MMAP(NULL, sizeof(*child_pid),
51+
PROT_READ | PROT_WRITE,
52+
MAP_SHARED | MAP_ANONYMOUS,
53+
-1, 0);
54+
}
55+
56+
static void cleanup(void)
57+
{
58+
if (child_pid)
59+
SAFE_MUNMAP(child_pid, sizeof(*child_pid));
60+
}
61+
62+
static struct tst_test test = {
63+
.tcnt = ARRAY_SIZE(tcases),
64+
.setup = setup,
65+
.test = run,
66+
.cleanup = cleanup,
67+
.needs_root = 1,
68+
.caps = (struct tst_cap[]) {
69+
TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN),
70+
{},
71+
},
72+
.bufs = (struct tst_buffers[]) {
73+
{&child_stack, .size = CHILD_STACK_SIZE},
74+
{},
75+
},
76+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
clone301
22
clone302
33
clone303
4+
clone304
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2025 Stephen Bertram <[email protected]>
4+
*/
5+
6+
/*\
7+
* This test verifies that :man2:`clone3` fails with EPERM when CAP_SYS_ADMIN
8+
* has been dropped and ``clone_args.set_tid_size`` is greater than zero.
9+
*/
10+
11+
#define _GNU_SOURCE
12+
#define DESC(x) .flags = x, .sflags = #x
13+
14+
#include "tst_test.h"
15+
#include "lapi/sched.h"
16+
17+
enum case_type {
18+
K_SET_TID, /* flags = 0 || CLONE_NEW*, set_tid_size > 0 => EPERM */
19+
K_NAMESPACE_ONLY, /* flags = CLONE_NEW*, set_tid_size = 0 => EPERM */
20+
};
21+
22+
static struct clone_args args = {0};
23+
static pid_t tid_array[1] = {1};
24+
25+
static struct tcase {
26+
uint64_t flags;
27+
const char *sflags;
28+
enum case_type type;
29+
} tcases[] = {
30+
{ DESC(CLONE_NEWPID), K_NAMESPACE_ONLY },
31+
{ DESC(CLONE_NEWCGROUP), K_NAMESPACE_ONLY },
32+
{ DESC(CLONE_NEWIPC), K_NAMESPACE_ONLY },
33+
{ DESC(CLONE_NEWNET), K_NAMESPACE_ONLY },
34+
{ DESC(CLONE_NEWNS), K_NAMESPACE_ONLY },
35+
{ DESC(CLONE_NEWUTS), K_NAMESPACE_ONLY },
36+
37+
{ DESC(CLONE_NEWPID), K_SET_TID },
38+
{ DESC(CLONE_NEWCGROUP), K_SET_TID },
39+
{ DESC(CLONE_NEWIPC), K_SET_TID },
40+
{ DESC(CLONE_NEWNET), K_SET_TID },
41+
{ DESC(CLONE_NEWNS), K_SET_TID },
42+
{ DESC(CLONE_NEWUTS), K_SET_TID },
43+
44+
{ DESC(0), K_SET_TID },
45+
};
46+
47+
static void run(unsigned int n)
48+
{
49+
struct tcase *tc = &tcases[n];
50+
51+
args.flags = tc->flags;
52+
53+
if (tc->type == K_NAMESPACE_ONLY) {
54+
args.set_tid = 0;
55+
args.set_tid_size = 0;
56+
} else {
57+
args.set_tid = (uint64_t)(uintptr_t)tid_array;
58+
args.set_tid_size = 1;
59+
}
60+
61+
TST_EXP_FAIL(clone3(&args, sizeof(args)), EPERM,
62+
"clone3(%s) set_tid_size=%ld",
63+
tc->sflags, args.set_tid_size);
64+
}
65+
66+
static void setup(void)
67+
{
68+
clone3_supported_by_kernel();
69+
70+
memset(&args, 0, sizeof(args));
71+
SAFE_UNSHARE(CLONE_NEWUSER | CLONE_NEWNS);
72+
}
73+
74+
static struct tst_test test = {
75+
.tcnt = ARRAY_SIZE(tcases),
76+
.setup = setup,
77+
.test = run,
78+
.needs_root = 1,
79+
.caps = (struct tst_cap[]) {
80+
TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN),
81+
{},
82+
},
83+
.bufs = (struct tst_buffers[]) {
84+
{&args, .size = sizeof(struct clone_args)},
85+
{},
86+
},
87+
};

0 commit comments

Comments
 (0)