[LTP] [PATCH v3] Add new tests for clone and clone3
Petr Vorel
pvorel@suse.cz
Wed Nov 12 21:11:24 CET 2025
Hi Ben,
> 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.
> runtest/syscalls | 2 +
> testcases/kernel/syscalls/clone/.gitignore | 1 +
> testcases/kernel/syscalls/clone/clone11.c | 72 +++++++++++++++++++++
> testcases/kernel/syscalls/clone3/.gitignore | 1 +
> testcases/kernel/syscalls/clone3/clone304.c | 63 ++++++++++++++++++
> 5 files changed, 139 insertions(+)
This looks better then v2. Generally LGTM, few notes below.
Reviewed-by: Petr Vorel <pvorel@suse.cz>
I see adding the test for both clone() and clone3() is because Li asked
[1] for it.
[1] https://lore.kernel.org/ltp/CAEemH2cQam9tOeQj_4SdvoYG5ZNmar6Quc5M6mtr==2-HQR9yQ@mail.gmail.com/
nit: I would phrase the subject as "Add EPERM test for clone and clone3" to
have at least a bit of information in the subject.
...
> +/*\
> + * This test verifies that clone() fals with EPERM when CAP_SYS_ADMIN
s/fals/fails/
If new version is needed, could you please use :man2:`clone` ?
This will link man clone(2) [2] in our test catalog [3].
[2] https://man7.org/linux/man-pages/man2/clone.2.html
[3] https://linux-test-project.readthedocs.io/en/latest/users/test_catalog.html
> + * has been dropped.
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include "tst_test.h"
> +#include "clone_platform.h"
NOTE: we need to add
#include "lapi/sched.h"
otherwise old systems fail to compile due missing CLONE_NEWCGROUP.
This should really be fixed in a new version or before merge.
FYI we support kernel from 4.4 and glibc 2.22 [4].
[4] https://linux-test-project.readthedocs.io/en/latest/users/supported_systems.html
> +
> +static void *child_stack;
> +static int *child_pid;
> +
> +static struct tcase {
> + uint64_t flags;
> + char *sflags;
> +} tcases[] = {
> + {CLONE_NEWPID, "CLONE_NEWPID"},
nit: If new version needed using macro is more elegant than copy pasting
definition as a string:
#define DESC(x) .flags = x, .sflags = #x
{ DESC(CLONE_NEWPID) },
{ DESC(CLONE_NEWCGROUP) },
...
> + {CLONE_NEWCGROUP, "CLONE_NEWCGROUP"},
> + {CLONE_NEWIPC, "CLONE_NEWIPC"},
> + {CLONE_NEWNET, "CLONE_NEWNET"},
> + {CLONE_NEWNS, "CLONE_NEWNS"},
> + {CLONE_NEWUTS, "CLONE_NEWUTS"},
> +};
> +
> +static int child_fn(void *arg LTP_ATTRIBUTE_UNUSED)
> +{
> + *child_pid = getpid();
> + exit(0);
nit: there are 2 tabs.
> +}
> +
> +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);
very nit: ',' is usually on a previous line.
> +}
> +
> +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..e47ab313e
> --- /dev/null
> +++ b/testcases/kernel/syscalls/clone3/clone304.c
> @@ -0,0 +1,63 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2025 Stephen Bertram <sbertram@redhat.com>
> + */
> +
> +/*\
> + * This test verifies that clone3() fals with EPERM when CAP_SYS_ADMIN
> + * has been dropped and ``clone_args.set_tid_size`` is greater than zero.
> + */
> +
> +#define _GNU_SOURCE
> +#include "tst_test.h"
> +#include "lapi/sched.h"
> +
> +static struct clone_args args = {0};
> +static pid_t tid_array[4] = {0, 0, 0, 0};
> +
> +static struct tcase {
> + uint64_t flags;
> + char *sflags;
> +} tcases[] = {
> + {CLONE_NEWPID, "CLONE_NEWPID"},
> + {CLONE_NEWCGROUP, "CLONE_NEWCGROUP"},
> + {CLONE_NEWIPC, "CLONE_NEWIPC"},
> + {CLONE_NEWNET, "CLONE_NEWNET"},
> + {CLONE_NEWNS, "CLONE_NEWNS"},
> + {CLONE_NEWUTS, "CLONE_NEWUTS"},
> +};
> +
> +static void run(unsigned int n)
> +{
> + struct tcase *tc = &tcases[n];
> +
> + args.flags = tc->flags;
> +
> + TST_EXP_FAIL(clone3(&args, sizeof(args)), EPERM, "clone3(%s) should fail with EPERM"
> + , tc->sflags);
> +}
> +
> +static void setup(void)
> +{
> + clone3_supported_by_kernel();
> +
> + memset(&args, 0, sizeof(args));
> + args.set_tid = (uintptr_t)tid_array;
> + /* set_tid_size greater than zero - requires CAP_SYS_ADMIN */
> + args.set_tid_size = 4;
> +}
> +
> +static struct tst_test test = {
NOTE: man clone(2) claims set_tid_size is "since Linux 5.5".
But fortunately test TCONF correctly:
../../../../include/lapi/sched.h:88: TCONF: syscall(435) __NR_clone3 not supported on your arch
Therefore we don't need to add .min_kver = "5.5".
> + .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)},
> + {},
> + },
> +};
More information about the ltp
mailing list