Skip to content

Commit b065c43

Browse files
authored
Merge pull request #46 from Max042004/fix-clone-namespace-flags
Reject CLONE_NEW* namespace flags in legacy clone(2)
2 parents 828e9ca + 64ea4e3 commit b065c43

2 files changed

Lines changed: 56 additions & 14 deletions

File tree

src/runtime/forkipc.c

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,23 @@ int fork_child_main(int ipc_fd,
360360
#define LINUX_CLONE_CHILD_SETTID 0x01000000
361361
/* LINUX_SIGCHLD defined in syscall_signal.h (included above) */
362362

363+
/* Namespace flags. elfuse implements no namespace isolation. Both
364+
* sys_clone and sys_clone3 reject them.
365+
*/
366+
#define LINUX_CLONE_NEWTIME 0x00000080
367+
#define LINUX_CLONE_NEWNS 0x00020000
368+
#define LINUX_CLONE_NEWCGROUP 0x02000000
369+
#define LINUX_CLONE_NEWUTS 0x04000000
370+
#define LINUX_CLONE_NEWIPC 0x08000000
371+
#define LINUX_CLONE_NEWUSER 0x10000000
372+
#define LINUX_CLONE_NEWPID 0x20000000
373+
#define LINUX_CLONE_NEWNET 0x40000000
374+
375+
#define LINUX_CLONE3_NS_FLAGS \
376+
(LINUX_CLONE_NEWNS | LINUX_CLONE_NEWCGROUP | LINUX_CLONE_NEWUTS | \
377+
LINUX_CLONE_NEWIPC | LINUX_CLONE_NEWUSER | LINUX_CLONE_NEWPID | \
378+
LINUX_CLONE_NEWNET | LINUX_CLONE_NEWTIME)
379+
363380
/* CLONE_THREAD: create a new guest thread in the same VM. */
364381

365382
/* Arguments passed to the worker pthread. Allocated by sys_clone_thread, freed
@@ -1069,6 +1086,14 @@ int64_t sys_clone(hv_vcpu_t vcpu,
10691086
uint64_t ctid_gva,
10701087
bool verbose)
10711088
{
1089+
/* Namespaces are not implemented. CLONE_NEWTIME (0x80) lives in the CSIGNAL
1090+
* low byte and, like CLONE_INTO_CGROUP (bit 33) and set_tid, cannot be
1091+
* conveyed through clone(2) at all, so only the higher namespace bits are
1092+
* reachable here.
1093+
*/
1094+
if ((flags & ~(uint64_t) 0xff) & LINUX_CLONE3_NS_FLAGS)
1095+
return -LINUX_EINVAL;
1096+
10721097
/* CLONE_THREAD: create a new thread in the same VM (not a new process) */
10731098
if (flags & LINUX_CLONE_THREAD) {
10741099
return sys_clone_thread(vcpu, g, flags, child_stack, stack_map_start,
@@ -1507,22 +1532,9 @@ struct linux_clone_args {
15071532

15081533
#define CLONE_ARGS_SIZE_VER0 64 /* v5.3: first 8 fields (flags..tls) */
15091534

1510-
/* Unsupported clone3 flags: reject early rather than silently ignoring. */
1535+
/* Unsupported clone3-only flags: reject early rather than silently ignoring. */
15111536
#define LINUX_CLONE_PIDFD 0x00001000
15121537
#define LINUX_CLONE_INTO_CGROUP 0x200000000ULL
1513-
#define LINUX_CLONE_NEWNS 0x00020000
1514-
#define LINUX_CLONE_NEWCGROUP 0x02000000
1515-
#define LINUX_CLONE_NEWUTS 0x04000000
1516-
#define LINUX_CLONE_NEWIPC 0x08000000
1517-
#define LINUX_CLONE_NEWUSER 0x10000000
1518-
#define LINUX_CLONE_NEWPID 0x20000000
1519-
#define LINUX_CLONE_NEWNET 0x40000000
1520-
#define LINUX_CLONE_NEWTIME 0x00000080
1521-
1522-
#define LINUX_CLONE3_NS_FLAGS \
1523-
(LINUX_CLONE_NEWNS | LINUX_CLONE_NEWCGROUP | LINUX_CLONE_NEWUTS | \
1524-
LINUX_CLONE_NEWIPC | LINUX_CLONE_NEWUSER | LINUX_CLONE_NEWPID | \
1525-
LINUX_CLONE_NEWNET | LINUX_CLONE_NEWTIME)
15261538

15271539
int64_t sys_clone3(hv_vcpu_t vcpu,
15281540
guest_t *g,

tests/test-clone3.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,35 @@ static void test_partial_deferred_stack_munmap(void)
658658
munmap(reuse_stack, stack_size);
659659
}
660660

661+
/* Test 15: legacy clone(2) rejects CLONE_NEW* namespace flags with EINVAL,
662+
* matching clone3 (issue #44). Before the fix these flags fell through to a
663+
* plain fork that falsely appeared to succeed. CLONE_NEWTIME is omitted: it
664+
* lives in the CSIGNAL low byte and is not reachable through clone(2).
665+
*/
666+
static void test_legacy_clone_namespaces(void)
667+
{
668+
static const struct {
669+
unsigned long flag;
670+
const char *name;
671+
} ns_flags[] = {
672+
{0x00020000, "CLONE_NEWNS"}, {0x02000000, "CLONE_NEWCGROUP"},
673+
{0x04000000, "CLONE_NEWUTS"}, {0x08000000, "CLONE_NEWIPC"},
674+
{0x10000000, "CLONE_NEWUSER"}, {0x20000000, "CLONE_NEWPID"},
675+
{0x40000000, "CLONE_NEWNET"},
676+
};
677+
for (size_t i = 0; i < sizeof(ns_flags) / sizeof(ns_flags[0]); i++) {
678+
/* SIGCHLD (17) in the low byte makes this a fork-like clone. */
679+
long ret = raw_clone(ns_flags[i].flag | 17, NULL, NULL, 0, NULL);
680+
CHECK(ret == -22 /* EINVAL */,
681+
"clone(%s) returned %ld (expected -EINVAL)", ns_flags[i].name,
682+
ret);
683+
if (ret == 0) /* defensive: a leaked child must not run the suite */
684+
raw_syscall1(__NR_exit, 0);
685+
else if (ret > 0)
686+
raw_syscall4(__NR_wait4, ret, 0, 0, 0);
687+
}
688+
}
689+
661690
int main(int argc, char **argv)
662691
{
663692
if (argc > 1 && !strcmp(argv[1], "--clone3-vfork-child"))
@@ -687,6 +716,7 @@ int main(int argc, char **argv)
687716
test_vfork_exec_unblocks_parent();
688717
test_deferred_stack_munmap();
689718
test_partial_deferred_stack_munmap();
719+
test_legacy_clone_namespaces();
690720

691721
SUMMARY("test-clone3");
692722
return fails > 0 ? 1 : 0;

0 commit comments

Comments
 (0)