[LTP] [PATCH v6] Add EPERM test for clone and clone3

Stephen Bertram sbertram@redhat.com
Wed Nov 19 19:54:02 CET 2025


After rerunning it in another environment It came out looking slightly
different than expected, NEWNS was a tab shorter than before. So will
revert the changes and resubmit. Formatting can be a pain.

clone304.c:66: TPASS: clone3(CLONE_NEWPID)             set_tid_size=0 :
EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWCGROUP)   set_tid_size=0 : EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWIPC)             set_tid_size=0 :
EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWNET)            set_tid_size=0 :
EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWNS)    set_tid_size=0 : EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWUTS)            set_tid_size=0 :
EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWPID)             set_tid_size=1 :
EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWCGROUP)   set_tid_size=1 : EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWIPC)             set_tid_size=1 :
EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWNET)            set_tid_size=1 :
EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWNS)    set_tid_size=1 : EPERM (1)
clone304.c:66: TPASS: clone3(CLONE_NEWUTS)            set_tid_size=1 :
EPERM (1)
clone304.c:62: TPASS: clone3(0)
set_tid_size=1 : EPERM (1)

Thank you,

stephen
He/His/Him


On Wed, Nov 19, 2025 at 6:49 AM Stephen Bertram <sbertram@redhat.com> wrote:

> Hi Li,
>
> I did this for output formatting. Yes not needed but it looks nicer when
> the results are displayed.
>
> Let me know which you prefer.
>
> As is:
> clone304.c:66: TPASS: clone3(CLONE_NEWPID)             set_tid_size=0 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWCGROUP)   set_tid_size=0 : EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWIPC)             set_tid_size=0 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWNET)            set_tid_size=0 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWNS)              set_tid_size=0 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWUTS)            set_tid_size=0 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWPID)             set_tid_size=1 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWCGROUP)   set_tid_size=1 : EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWIPC)             set_tid_size=1 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWNET)            set_tid_size=1 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWNS)              set_tid_size=1 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWUTS)            set_tid_size=1 :
> EPERM (1)
> clone304.c:62: TPASS: clone3(0)
> set_tid_size=1 : EPERM (1)
>
> Without:
>
> clone304.c:66: TPASS: clone3(CLONE_NEWPID)             set_tid_size=0 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWCGROUP)   set_tid_size=0 : EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWIPC)             set_tid_size=0 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWNET)            set_tid_size=0 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWNS)              set_tid_size=0 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWUTS)            set_tid_size=0 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWPID)             set_tid_size=1 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWCGROUP)   set_tid_size=1 : EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWIPC)             set_tid_size=1 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWNET)            set_tid_size=1 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWNS)              set_tid_size=1 :
> EPERM (1)
> clone304.c:66: TPASS: clone3(CLONE_NEWUTS)            set_tid_size=1 :
> EPERM (1)
> clone304.c:62: TPASS: clone3(0)         set_tid_size=1 : EPERM (1)
>
> Obviously I think it's worth it to have a nicely reporting output.
>
> thanks,
>
> stephen
> He/His/Him
>
>
> On Wed, Nov 19, 2025 at 3:40 AM Li Wang <liwang@redhat.com> wrote:
>
>>
>>
>> On Wed, Nov 19, 2025 at 6:29 AM Stephen Bertram via ltp <
>> ltp@lists.linux.it> wrote:
>>
>>> 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 | 92 +++++++++++++++++++++
>>>  5 files changed, 170 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..34ce0cf7b
>>> --- /dev/null
>>> +++ b/testcases/kernel/syscalls/clone3/clone304.c
>>> @@ -0,0 +1,92 @@
>>> +// 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;
>>> +       }
>>> +
>>>
>>
>>
>>
>>> +       if (tc->flags == 0)
>>> +               TST_EXP_FAIL(clone3(&args, sizeof(args)), EPERM,
>>> +                       "clone3(%s)\t\t\t set_tid_size=%ld",
>>> +                       tc->sflags, args.set_tid_size);
>>> +       else
>>> +               TST_EXP_FAIL(clone3(&args, sizeof(args)), EPERM,
>>> +                       "clone3(%s)\t set_tid_size=%ld",
>>> +                       tc->sflags, args.set_tid_size);
>>>
>>
>> I don't think we need two syntaxes to print the same info.
>> The latter one should be good enough.
>>
>> Otherwise, it looks good to me:
>> Reviewed-by: Li Wang <liwang@redhat.com>
>>
>>
>> --
>> Regards,
>> Li Wang
>>
>


More information about the ltp mailing list