* [LTP] [PATCH v3 01/15] syscalls: add v7.3 syscall numbers
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH v3 02/15] syscalls: update outdated syscall entries Andrea Cervesato
` (13 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Add listns (470), rseq_slice_yield (471) and fchroot (472), which are
reserved for all architectures during the Linux v7.3 development cycle.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
include/lapi/syscalls/arc.in | 3 +++
include/lapi/syscalls/arm.in | 3 +++
include/lapi/syscalls/arm64.in | 3 +++
include/lapi/syscalls/i386.in | 3 +++
include/lapi/syscalls/loongarch64.in | 3 +++
include/lapi/syscalls/mips64.in | 3 +++
include/lapi/syscalls/mips64n32.in | 3 +++
include/lapi/syscalls/mipso32.in | 3 +++
include/lapi/syscalls/parisc.in | 3 +++
include/lapi/syscalls/powerpc.in | 3 +++
include/lapi/syscalls/powerpc64.in | 3 +++
include/lapi/syscalls/s390.in | 3 +++
include/lapi/syscalls/s390x.in | 3 +++
include/lapi/syscalls/sh.in | 3 +++
include/lapi/syscalls/sparc.in | 3 +++
include/lapi/syscalls/sparc64.in | 3 +++
include/lapi/syscalls/x86_64.in | 3 +++
17 files changed, 51 insertions(+)
diff --git a/include/lapi/syscalls/arc.in b/include/lapi/syscalls/arc.in
index 0f0fbef6b..96b14c1b9 100644
--- a/include/lapi/syscalls/arc.in
+++ b/include/lapi/syscalls/arc.in
@@ -347,3 +347,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/arm.in b/include/lapi/syscalls/arm.in
index d0238dec5..c4058e8de 100644
--- a/include/lapi/syscalls/arm.in
+++ b/include/lapi/syscalls/arm.in
@@ -420,3 +420,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/arm64.in b/include/lapi/syscalls/arm64.in
index c76930e20..26a61e830 100644
--- a/include/lapi/syscalls/arm64.in
+++ b/include/lapi/syscalls/arm64.in
@@ -323,3 +323,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in
index 38ea71fb2..21d5da053 100644
--- a/include/lapi/syscalls/i386.in
+++ b/include/lapi/syscalls/i386.in
@@ -454,3 +454,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/loongarch64.in b/include/lapi/syscalls/loongarch64.in
index a1dfce79e..88e77ef8a 100644
--- a/include/lapi/syscalls/loongarch64.in
+++ b/include/lapi/syscalls/loongarch64.in
@@ -320,3 +320,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/mips64.in b/include/lapi/syscalls/mips64.in
index 436d5c681..3c19066b8 100644
--- a/include/lapi/syscalls/mips64.in
+++ b/include/lapi/syscalls/mips64.in
@@ -369,3 +369,6 @@ removexattrat 5466
open_tree_attr 5467
file_getattr 5468
file_setattr 5469
+listns 5470
+rseq_slice_yield 5471
+fchroot 5472
diff --git a/include/lapi/syscalls/mips64n32.in b/include/lapi/syscalls/mips64n32.in
index 860a19c8b..0c539bd62 100644
--- a/include/lapi/syscalls/mips64n32.in
+++ b/include/lapi/syscalls/mips64n32.in
@@ -393,3 +393,6 @@ removexattrat 6466
open_tree_attr 6467
file_getattr 6468
file_setattr 6469
+listns 6470
+rseq_slice_yield 6471
+fchroot 6472
diff --git a/include/lapi/syscalls/mipso32.in b/include/lapi/syscalls/mipso32.in
index 5e53e46ce..ecbe4d4b9 100644
--- a/include/lapi/syscalls/mipso32.in
+++ b/include/lapi/syscalls/mipso32.in
@@ -433,3 +433,6 @@ removexattrat 4466
open_tree_attr 4467
file_getattr 4468
file_setattr 4469
+listns 4470
+rseq_slice_yield 4471
+fchroot 4472
diff --git a/include/lapi/syscalls/parisc.in b/include/lapi/syscalls/parisc.in
index 238756694..e84c3b344 100644
--- a/include/lapi/syscalls/parisc.in
+++ b/include/lapi/syscalls/parisc.in
@@ -402,3 +402,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/powerpc.in b/include/lapi/syscalls/powerpc.in
index 6911f9af9..9354dbe2b 100644
--- a/include/lapi/syscalls/powerpc.in
+++ b/include/lapi/syscalls/powerpc.in
@@ -444,3 +444,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in
index 98190ba26..e4bef6838 100644
--- a/include/lapi/syscalls/powerpc64.in
+++ b/include/lapi/syscalls/powerpc64.in
@@ -416,3 +416,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in
index a6cb85da8..4a11871b6 100644
--- a/include/lapi/syscalls/s390.in
+++ b/include/lapi/syscalls/s390.in
@@ -437,3 +437,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/s390x.in b/include/lapi/syscalls/s390x.in
index 31f3ec553..055a039fb 100644
--- a/include/lapi/syscalls/s390x.in
+++ b/include/lapi/syscalls/s390x.in
@@ -385,3 +385,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/sh.in b/include/lapi/syscalls/sh.in
index ac281acf8..29cd8f8df 100644
--- a/include/lapi/syscalls/sh.in
+++ b/include/lapi/syscalls/sh.in
@@ -431,3 +431,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in
index ffc0d9f7a..ea2bfc9c1 100644
--- a/include/lapi/syscalls/sparc.in
+++ b/include/lapi/syscalls/sparc.in
@@ -435,3 +435,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/sparc64.in b/include/lapi/syscalls/sparc64.in
index 992bd307d..692652c3b 100644
--- a/include/lapi/syscalls/sparc64.in
+++ b/include/lapi/syscalls/sparc64.in
@@ -398,3 +398,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in
index e9c0d0599..7d3d8163c 100644
--- a/include/lapi/syscalls/x86_64.in
+++ b/include/lapi/syscalls/x86_64.in
@@ -380,3 +380,6 @@ removexattrat 466
open_tree_attr 467
file_getattr 468
file_setattr 469
+listns 470
+rseq_slice_yield 471
+fchroot 472
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH v3 02/15] syscalls: update outdated syscall entries
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH v3 01/15] syscalls: add v7.3 syscall numbers Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 21:14 ` [LTP] syscalls: add v7.3 syscall numbers linuxtestproject.agent
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 03/15] lapi: fallback fchroot() parameters Andrea Cervesato
` (12 subsequent siblings)
14 siblings, 1 reply; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Add uprobe (336) on x86_64 and clone3 (435) on sparc, which were
missing from the architecture syscall tables.
Drop the _sysctl and timerfd entries because both are wired to
sys_ni_syscall in the kernel syscall tables and cannot be called.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
include/lapi/syscalls/arm.in | 1 -
include/lapi/syscalls/i386.in | 1 -
include/lapi/syscalls/mips64.in | 2 --
include/lapi/syscalls/mips64n32.in | 2 --
include/lapi/syscalls/mipso32.in | 2 --
include/lapi/syscalls/parisc.in | 1 -
include/lapi/syscalls/powerpc.in | 1 -
include/lapi/syscalls/powerpc64.in | 1 -
include/lapi/syscalls/s390.in | 2 --
include/lapi/syscalls/s390x.in | 2 --
include/lapi/syscalls/sh.in | 1 -
include/lapi/syscalls/sparc.in | 2 +-
include/lapi/syscalls/sparc64.in | 2 +-
include/lapi/syscalls/x86_64.in | 2 +-
14 files changed, 3 insertions(+), 19 deletions(-)
diff --git a/include/lapi/syscalls/arm.in b/include/lapi/syscalls/arm.in
index c4058e8de..158350976 100644
--- a/include/lapi/syscalls/arm.in
+++ b/include/lapi/syscalls/arm.in
@@ -109,7 +109,6 @@ readv 145
writev 146
getsid 147
fdatasync 148
-_sysctl 149
mlock 150
munlock 151
mlockall 152
diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in
index 21d5da053..ee229b567 100644
--- a/include/lapi/syscalls/i386.in
+++ b/include/lapi/syscalls/i386.in
@@ -145,7 +145,6 @@ readv 145
writev 146
getsid 147
fdatasync 148
-_sysctl 149
mlock 150
munlock 151
mlockall 152
diff --git a/include/lapi/syscalls/mips64.in b/include/lapi/syscalls/mips64.in
index 3c19066b8..d1087e049 100644
--- a/include/lapi/syscalls/mips64.in
+++ b/include/lapi/syscalls/mips64.in
@@ -150,7 +150,6 @@ mlockall 5148
munlockall 5149
vhangup 5150
pivot_root 5151
-_sysctl 5152
prctl 5153
adjtimex 5154
setrlimit 5155
@@ -272,7 +271,6 @@ ioprio_set 5273
ioprio_get 5274
utimensat 5275
signalfd 5276
-timerfd 5277
eventfd 5278
fallocate 5279
timerfd_create 5280
diff --git a/include/lapi/syscalls/mips64n32.in b/include/lapi/syscalls/mips64n32.in
index 0c539bd62..2a3883198 100644
--- a/include/lapi/syscalls/mips64n32.in
+++ b/include/lapi/syscalls/mips64n32.in
@@ -150,7 +150,6 @@ mlockall 6148
munlockall 6149
vhangup 6150
pivot_root 6151
-_sysctl 6152
prctl 6153
adjtimex 6154
setrlimit 6155
@@ -276,7 +275,6 @@ ioprio_set 6277
ioprio_get 6278
utimensat 6279
signalfd 6280
-timerfd 6281
eventfd 6282
fallocate 6283
timerfd_create 6284
diff --git a/include/lapi/syscalls/mipso32.in b/include/lapi/syscalls/mipso32.in
index ecbe4d4b9..0d682d072 100644
--- a/include/lapi/syscalls/mipso32.in
+++ b/include/lapi/syscalls/mipso32.in
@@ -144,7 +144,6 @@ cachectl 4148
sysmips 4149
getsid 4151
fdatasync 4152
-_sysctl 4153
mlock 4154
munlock 4155
mlockall 4156
@@ -307,7 +306,6 @@ ioprio_set 4314
ioprio_get 4315
utimensat 4316
signalfd 4317
-timerfd 4318
eventfd 4319
fallocate 4320
timerfd_create 4321
diff --git a/include/lapi/syscalls/parisc.in b/include/lapi/syscalls/parisc.in
index e84c3b344..71d40f7b2 100644
--- a/include/lapi/syscalls/parisc.in
+++ b/include/lapi/syscalls/parisc.in
@@ -142,7 +142,6 @@ readv 145
writev 146
getsid 147
fdatasync 148
-_sysctl 149
mlock 150
munlock 151
mlockall 152
diff --git a/include/lapi/syscalls/powerpc.in b/include/lapi/syscalls/powerpc.in
index 9354dbe2b..85d7aec9a 100644
--- a/include/lapi/syscalls/powerpc.in
+++ b/include/lapi/syscalls/powerpc.in
@@ -145,7 +145,6 @@ readv 145
writev 146
getsid 147
fdatasync 148
-_sysctl 149
mlock 150
munlock 151
mlockall 152
diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in
index e4bef6838..def01478d 100644
--- a/include/lapi/syscalls/powerpc64.in
+++ b/include/lapi/syscalls/powerpc64.in
@@ -145,7 +145,6 @@ readv 145
writev 146
getsid 147
fdatasync 148
-_sysctl 149
mlock 150
munlock 151
mlockall 152
diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in
index 4a11871b6..5024313a5 100644
--- a/include/lapi/syscalls/s390.in
+++ b/include/lapi/syscalls/s390.in
@@ -126,7 +126,6 @@ readv 145
writev 146
getsid 147
fdatasync 148
-_sysctl 149
mlock 150
munlock 151
mlockall 152
@@ -291,7 +290,6 @@ utimes 313
fallocate 314
utimensat 315
signalfd 316
-timerfd 317
eventfd 318
timerfd_create 319
timerfd_settime 320
diff --git a/include/lapi/syscalls/s390x.in b/include/lapi/syscalls/s390x.in
index 055a039fb..357b04ceb 100644
--- a/include/lapi/syscalls/s390x.in
+++ b/include/lapi/syscalls/s390x.in
@@ -107,7 +107,6 @@ readv 145
writev 146
getsid 147
fdatasync 148
-_sysctl 149
mlock 150
munlock 151
mlockall 152
@@ -258,7 +257,6 @@ utimes 313
fallocate 314
utimensat 315
signalfd 316
-timerfd 317
eventfd 318
timerfd_create 319
timerfd_settime 320
diff --git a/include/lapi/syscalls/sh.in b/include/lapi/syscalls/sh.in
index 29cd8f8df..584d36a4e 100644
--- a/include/lapi/syscalls/sh.in
+++ b/include/lapi/syscalls/sh.in
@@ -128,7 +128,6 @@ readv 145
writev 146
getsid 147
fdatasync 148
-_sysctl 149
mlock 150
munlock 151
mlockall 152
diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in
index ea2bfc9c1..a48c5b365 100644
--- a/include/lapi/syscalls/sparc.in
+++ b/include/lapi/syscalls/sparc.in
@@ -246,7 +246,6 @@ sched_get_priority_min 247
sched_rr_get_interval 248
nanosleep 249
mremap 250
-_sysctl 251
getsid 252
fdatasync 253
nfsservctl 254
@@ -402,6 +401,7 @@ fsconfig 431
fsmount 432
fspick 433
pidfd_open 434
+clone3 435
close_range 436
openat2 437
pidfd_getfd 438
diff --git a/include/lapi/syscalls/sparc64.in b/include/lapi/syscalls/sparc64.in
index 692652c3b..9f3e825a9 100644
--- a/include/lapi/syscalls/sparc64.in
+++ b/include/lapi/syscalls/sparc64.in
@@ -228,7 +228,6 @@ sched_get_priority_min 247
sched_rr_get_interval 248
nanosleep 249
mremap 250
-_sysctl 251
getsid 252
fdatasync 253
nfsservctl 254
@@ -365,6 +364,7 @@ fsconfig 431
fsmount 432
fspick 433
pidfd_open 434
+clone3 435
close_range 436
openat2 437
pidfd_getfd 438
diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in
index 7d3d8163c..1996c26b8 100644
--- a/include/lapi/syscalls/x86_64.in
+++ b/include/lapi/syscalls/x86_64.in
@@ -154,7 +154,6 @@ munlockall 152
vhangup 153
modify_ldt 154
pivot_root 155
-_sysctl 156
prctl 157
arch_prctl 158
adjtimex 159
@@ -334,6 +333,7 @@ statx 332
io_pgetevents 333
rseq 334
uretprobe 335
+uprobe 336
pidfd_send_signal 424
io_uring_setup 425
io_uring_enter 426
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [LTP] syscalls: add v7.3 syscall numbers
2026-08-28 14:11 ` [LTP] [PATCH v3 02/15] syscalls: update outdated syscall entries Andrea Cervesato
@ 2026-08-28 21:14 ` linuxtestproject.agent
0 siblings, 0 replies; 17+ messages in thread
From: linuxtestproject.agent @ 2026-08-28 21:14 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: ltp
Hi Andrea,
On Fri, 28 Aug 2026, Andrea Cervesato wrote:
> syscalls: add v7.3 syscall numbers
--- [PATCH 4/15] ---
> fchroot01: test fchroot() with a directory fd
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
--- [PATCH 5/15] ---
> fchroot02: test fchroot() invalid arguments
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
--- [PATCH 6/15] ---
> fchroot03: test fchroot() permission checks
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
--- [PATCH 7/15] ---
> fchroot04: test fchroot() into failfs as root
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
--- [PATCH 8/15] ---
> fchroot05: test failfs root can not be referenced
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
--- [PATCH 9/15] ---
> fchroot06: test path walks under failfs root
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
--- [PATCH 10/15] ---
> fchroot07: test execve blocked by failfs root
Since 7.2 is the latest stable kernel and these tests target a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
> +fchroot07 fchroot07
> +fchroot08 fchroot08
The subject and body describe only the fchroot07 exec test. Could fchroot08,
which tests inheritance across fork(), be split into its own patch or
documented in a subject and body that cover both tests?
> The exec runs in a
> grandchild so a wrongly successful exec is still detected through
> the exit code.
Could this explanation be corrected to match the implementation?
fchroot07_child reports TFAIL and returns 0, while SAFE_WAIT(NULL) does not
inspect an exit status. The failure is propagated through the reinitialized
LTP result channel rather than through the exit code.
--- [PATCH 11/15] ---
> fchroot09: test setns escape from failfs root
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
> * Entering failfs with :manpage:`fchroot(2)` is hard to undo: a process
> * inside counts as chrooted, so :manpage:`chroot(2)` and fchroot() back
> * out require ``CAP_SYS_CHROOT``. The remaining way out is a pre-opened mount
> * namespace file descriptor: setns() into it resets both the root and the
Could the raw fchroot() and setns() references use
:manpage:`fchroot(2)` and :manpage:`setns(2)`? Test documentation requires
the man-page role for raw syscall references.
--- [PATCH 12/15] ---
> fchroot10: test failfs entry without no_new_privs
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
> + SAFE_SETRESUID(ltpuser->pw_uid, ltpuser->pw_uid,
> + ltpuser->pw_uid);
> +
> + TST_EXP_FAIL(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
> + EPERM, "unprivileged fchroot() without no_new_privs");
Could setup first verify that PR_GET_NO_NEW_PRIVS is zero and report TCONF
when it is already set? The bit is inherited and cannot be cleared. If LTP
is launched under a no-new-privileges policy, this child retains the bit,
the kernel permits this fchroot() case, and the test reports a false failure
without exercising the documented precondition.
--- [PATCH 13/15] ---
> fchroot11: test failfs entry with no_new_privs
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
> + TST_EXP_FAIL(unshare(CLONE_NEWUSER), EPERM,
> + "user namespace creation blocked by the failfs root");
Could a separate unprivileged child establish that user namespace creation
succeeds before entering failfs? CONFIG_USER_NS=y only proves kernel support.
Runtime policy such as kernel.unprivileged_userns_clone=0, an LSM, or seccomp
can already return EPERM for nobody. In that case this assertion reports
TPASS without exercising the claimed chroot restriction.
--- [PATCH 14/15] ---
> fchroot12: test failfs entry with shared fs_struct
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
--- [PATCH 15/15] ---
> fchroot13: test failfs entry when chrooted
Since 7.2 is the latest stable kernel and this test targets a 7.3 feature,
could the subject start with "[STAGING]" as required for unreleased kernel
features?
> * of a chrooted task into failfs would allow it to escape its chroot via
> * ``openat(fd, "..")`` with a pre-opened directory fd, so the kernel refuses
Could the raw openat() reference use :manpage:`openat(2)` and describe the
arguments separately? Test documentation requires the man-page role for raw
syscall references.
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 17+ messages in thread
* [LTP] [PATCH STAGING v3 03/15] lapi: fallback fchroot() parameters
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH v3 01/15] syscalls: add v7.3 syscall numbers Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH v3 02/15] syscalls: update outdated syscall entries Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 04/15] fchroot01: test fchroot() with a directory fd Andrea Cervesato
` (11 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Add to fcntl.h fallback definitions:
- FD_PIDFS_ROOT
- FD_NSFS_ROOT
- FD_FAILFS_ROOT
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
include/lapi/fcntl.h | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/include/lapi/fcntl.h b/include/lapi/fcntl.h
index 6a9ef11ce..d70954ea7 100644
--- a/include/lapi/fcntl.h
+++ b/include/lapi/fcntl.h
@@ -144,6 +144,19 @@
# endif
#endif
+/* Roots of kernel internal pseudo filesystems, usable as fd sentinels */
+#ifndef FD_PIDFS_ROOT
+# define FD_PIDFS_ROOT -10002
+#endif
+
+#ifndef FD_NSFS_ROOT
+# define FD_NSFS_ROOT -10003
+#endif
+
+#ifndef FD_FAILFS_ROOT
+# define FD_FAILFS_ROOT -10004
+#endif
+
#ifndef FALLOC_FL_KEEP_SIZE
# define FALLOC_FL_KEEP_SIZE 1
#endif
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 04/15] fchroot01: test fchroot() with a directory fd
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (2 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 03/15] lapi: fallback fchroot() parameters Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 05/15] fchroot02: test fchroot() invalid arguments Andrea Cervesato
` (10 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that fchroot() with a directory fd moves the process root to
the directory referenced by the fd.
fchroot() was introduced in Linux v7.3, so the test is added to the
staging runtest file.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 2 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/Makefile | 7 ++++
testcases/kernel/syscalls/fchroot/fchroot01.c | 58 +++++++++++++++++++++++++++
4 files changed, 68 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index ef1cdea15..733d5609a 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -1 +1,3 @@
# Tests for features that are not yet in the stable kernel ABI
+
+fchroot01 fchroot01
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
new file mode 100644
index 000000000..03ebdbe7a
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -0,0 +1 @@
+fchroot01
diff --git a/testcases/kernel/syscalls/fchroot/Makefile b/testcases/kernel/syscalls/fchroot/Makefile
new file mode 100644
index 000000000..137550149
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+
+top_srcdir ?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/fchroot/fchroot01.c b/testcases/kernel/syscalls/fchroot/fchroot01.c
new file mode 100644
index 000000000..1914b4c31
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot01.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test that :manpage:`fchroot(2)` with a regular directory fd moves the
+ * process root to the directory referenced by the fd.
+ *
+ * This is the fd-based counterpart of :manpage:`chroot(2)`, introduced in
+ * Linux v7.3. Root is required because :manpage:`fchroot(2)` with a regular
+ * directory fd requires ``CAP_SYS_CHROOT``.
+ *
+ * The test runs in a forked child so the root of the parent process is
+ * left untouched.
+ */
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+
+#define JAILDIR "jail"
+#define CANARY "/canary"
+#define CANARYDIR (JAILDIR CANARY)
+
+static void run(void)
+{
+ struct stat st;
+
+ if (SAFE_FORK())
+ return;
+
+ int dfd = SAFE_OPEN(JAILDIR, O_PATH | O_DIRECTORY);
+
+ TST_EXP_PASS(tst_syscall(__NR_fchroot, dfd, 0),
+ "fchroot() with a directory fd");
+
+ TST_EXP_PASS(stat(CANARY, &st),
+ "canary file visible under the new root");
+
+ exit(0);
+}
+
+static void setup(void)
+{
+ SAFE_MKDIR(JAILDIR, 0755);
+ SAFE_TOUCH(CANARYDIR, 0644, NULL);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .test_all = run,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 05/15] fchroot02: test fchroot() invalid arguments
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (3 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 04/15] fchroot01: test fchroot() with a directory fd Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 06/15] fchroot03: test fchroot() permission checks Andrea Cervesato
` (9 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify the fchroot() error paths: a non-zero flags argument fails with
EINVAL before anything else, an invalid fd fails with EBADF, including
the FD_PIDFS_ROOT and FD_NSFS_ROOT sentinels, and a fd referring to a
regular file fails with ENOTDIR. All these checks happen before the
CAP_SYS_CHROOT check, so no privileges are needed.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot02.c | 75 +++++++++++++++++++++++++++
3 files changed, 77 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 733d5609a..e12230218 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -1,3 +1,4 @@
# Tests for features that are not yet in the stable kernel ABI
fchroot01 fchroot01
+fchroot02 fchroot02
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index 03ebdbe7a..fb3287612 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -1 +1,2 @@
fchroot01
+fchroot02
diff --git a/testcases/kernel/syscalls/fchroot/fchroot02.c b/testcases/kernel/syscalls/fchroot/fchroot02.c
new file mode 100644
index 000000000..cf5bca874
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot02.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test the :manpage:`fchroot(2)` error paths for invalid arguments:
+ *
+ * - a non-zero flags argument fails with ``EINVAL``
+ * - an invalid fd fails with ``EBADF``, including the ``FD_PIDFS_ROOT`` and
+ * ``FD_NSFS_ROOT`` sentinels which :manpage:`fchroot(2)` does not accept
+ * - a fd referring to a regular file fails with ``ENOTDIR``
+ *
+ * All these checks happen before the ``CAP_SYS_CHROOT`` check, so the test
+ * needs no privileges.
+ */
+
+#include <fcntl.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+
+#define FILENAME "file.txt"
+
+static int dir_fd = -1;
+static int file_fd = -1;
+static int bad_fd = -1;
+static int failfs_root = FD_FAILFS_ROOT;
+static int pidfs_root = FD_PIDFS_ROOT;
+static int nsfs_root = FD_NSFS_ROOT;
+
+static struct tcase {
+ int *fd;
+ unsigned int flags;
+ int exp_errno;
+ const char *desc;
+} tcases[] = {
+ {&dir_fd, 1, EINVAL, "non-zero flags with a directory fd"},
+ {&failfs_root, 1, EINVAL, "non-zero flags with FD_FAILFS_ROOT"},
+ {&bad_fd, 0, EBADF, "invalid fd"},
+ {&pidfs_root, 0, EBADF, "FD_PIDFS_ROOT sentinel"},
+ {&nsfs_root, 0, EBADF, "FD_NSFS_ROOT sentinel"},
+ {&file_fd, 0, ENOTDIR, "fd referring to a regular file"},
+};
+
+static void run(unsigned int i)
+{
+ struct tcase *tc = &tcases[i];
+
+ TST_EXP_FAIL(tst_syscall(__NR_fchroot, *tc->fd, tc->flags),
+ tc->exp_errno, "fchroot() with %s", tc->desc);
+}
+
+static void setup(void)
+{
+ dir_fd = SAFE_OPEN(".", O_PATH | O_DIRECTORY);
+ file_fd = SAFE_OPEN(FILENAME, O_CREAT | O_EXCL | O_WRONLY, 0644);
+}
+
+static void cleanup(void)
+{
+ if (dir_fd != -1)
+ SAFE_CLOSE(dir_fd);
+
+ if (file_fd != -1)
+ SAFE_CLOSE(file_fd);
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = ARRAY_SIZE(tcases),
+ .setup = setup,
+ .cleanup = cleanup,
+ .needs_tmpdir = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 06/15] fchroot03: test fchroot() permission checks
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (4 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 05/15] fchroot02: test fchroot() invalid arguments Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 07/15] fchroot04: test fchroot() into failfs as root Andrea Cervesato
` (8 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that with a regular directory fd the kernel first checks the
execute permission on the directory and then CAP_SYS_CHROOT: an
unprivileged process with an accessible directory fails with EPERM and
a process without execute permission fails with EACCES.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot03.c | 72 +++++++++++++++++++++++++++
3 files changed, 74 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index e12230218..13635037b 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -2,3 +2,4 @@
fchroot01 fchroot01
fchroot02 fchroot02
+fchroot03 fchroot03
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index fb3287612..235befd99 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -1,2 +1,3 @@
fchroot01
fchroot02
+fchroot03
diff --git a/testcases/kernel/syscalls/fchroot/fchroot03.c b/testcases/kernel/syscalls/fchroot/fchroot03.c
new file mode 100644
index 000000000..5ec5c9241
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot03.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test the :manpage:`fchroot(2)` permission checks with a regular directory
+ * fd:
+ *
+ * - an unprivileged process with an accessible directory fails with ``EPERM``
+ * - a process without execute permission on the directory fails with ``EACCES``
+ *
+ * Root is required to open the directory file descriptors before dropping
+ * to an unprivileged user in forked children.
+ */
+
+#include <fcntl.h>
+#include <pwd.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+
+static struct tcase {
+ const char *dir;
+ mode_t mode;
+ int exp_errno;
+ const char *desc;
+} tcases[] = {
+ {"pubdir", 0755, EPERM, "no CAP_SYS_CHROOT"},
+ {"privdir", 0600, EACCES, "no execute permission"},
+};
+
+static struct passwd *ltpuser;
+
+static void run(unsigned int i)
+{
+ struct tcase *tc = &tcases[i];
+
+ if (SAFE_FORK())
+ return;
+
+ int dfd = SAFE_OPEN(tc->dir, O_PATH | O_DIRECTORY);
+
+ SAFE_SETRESUID(ltpuser->pw_uid, ltpuser->pw_uid,
+ ltpuser->pw_uid);
+
+ TST_EXP_FAIL(tst_syscall(__NR_fchroot, dfd, 0),
+ tc->exp_errno, "fchroot() with %s", tc->desc);
+
+ exit(0);
+}
+
+static void setup(void)
+{
+ unsigned int i;
+
+ ltpuser = SAFE_GETPWNAM("nobody");
+
+ for (i = 0; i < ARRAY_SIZE(tcases); i++) {
+ SAFE_MKDIR(tcases[i].dir, tcases[i].mode);
+ SAFE_CHMOD(tcases[i].dir, tcases[i].mode);
+ }
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = ARRAY_SIZE(tcases),
+ .setup = setup,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 07/15] fchroot04: test fchroot() into failfs as root
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (5 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 06/15] fchroot03: test fchroot() permission checks Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 08/15] fchroot05: test failfs root can not be referenced Andrea Cervesato
` (7 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that entering failfs with the FD_FAILFS_ROOT sentinel succeeds
with CAP_SYS_CHROOT and that every absolute path lookup then fails
with EOPNOTSUPP, while the working directory is reported as
unreachable by getcwd().
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot04.c | 70 +++++++++++++++++++++++++++
3 files changed, 72 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 13635037b..91dfdba08 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -3,3 +3,4 @@
fchroot01 fchroot01
fchroot02 fchroot02
fchroot03 fchroot03
+fchroot04 fchroot04
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index 235befd99..9270c1408 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -1,3 +1,4 @@
fchroot01
fchroot02
fchroot03
+fchroot04
diff --git a/testcases/kernel/syscalls/fchroot/fchroot04.c b/testcases/kernel/syscalls/fchroot/fchroot04.c
new file mode 100644
index 000000000..33097d8fd
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot04.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test :manpage:`fchroot(2)` with the ``FD_FAILFS_ROOT`` sentinel as a
+ * privileged process.
+ *
+ * :manpage:`fchroot(2)` was introduced in Linux v7.3 together with failfs,
+ * a kernel internal filesystem where every operation fails with
+ * ``EOPNOTSUPP``. The ``FD_FAILFS_ROOT`` sentinel moves the process root
+ * there without needing a file descriptor: it is the ``fs_struct`` equivalent
+ * of ``RESOLVE_BENEATH``.
+ *
+ * The test verifies that entering failfs succeeds with ``CAP_SYS_CHROOT`` and
+ * that every absolute path lookup then fails with ``EOPNOTSUPP``. The working
+ * directory, left behind in the real filesystem, is consequently reported
+ * as unreachable by :manpage:`getcwd(2)`.
+ *
+ * The syscall runs in a forked child because leaving failfs requires a
+ * mount namespace file descriptor and the parent needs its root for the
+ * test framework cleanup.
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+
+#define UNR_TAG "(unreachable)/"
+
+static void run(void)
+{
+ if (SAFE_FORK())
+ return;
+
+ char buf[PATH_MAX];
+
+ TST_EXP_PASS(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
+ "fchroot() with the FD_FAILFS_ROOT sentinel");
+
+ TST_EXP_FAIL2(open("/etc/passwd", O_RDONLY), EOPNOTSUPP,
+ "absolute file open");
+
+ TST_EXP_FAIL(mkdir("/foo", 0700), EOPNOTSUPP,
+ "absolute directory creation");
+
+ /*
+ * The libc getcwd() wrapper rejects the "(unreachable)"
+ * prefix produced by the kernel, so call the raw syscall.
+ */
+ TEST(tst_syscall(__NR_getcwd, buf, sizeof(buf)));
+ if (TST_RET > 0)
+ TST_EXP_EQ_STRN(buf, UNR_TAG, sizeof(UNR_TAG) - 1);
+ else
+ tst_res(TFAIL | TTERRNO, "getcwd() failed");
+
+ exit(0);
+}
+
+static struct tst_test test = {
+ .test_all = run,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 08/15] fchroot05: test failfs root can not be referenced
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (6 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 07/15] fchroot04: test fchroot() into failfs as root Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 09/15] fchroot06: test path walks under failfs root Andrea Cervesato
` (6 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that once fchroot() moved the root into failfs, the root
directory can not be opened anymore, not even with O_PATH, nor pinned
by following the /proc/self/root magic link, although readlink()
still names it as "failfs:/" since it does not follow the link.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot05.c | 75 +++++++++++++++++++++++++++
3 files changed, 77 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 91dfdba08..49f51d637 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -4,3 +4,4 @@ fchroot01 fchroot01
fchroot02 fchroot02
fchroot03 fchroot03
fchroot04 fchroot04
+fchroot05 fchroot05
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index 9270c1408..0697f10eb 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -2,3 +2,4 @@ fchroot01
fchroot02
fchroot03
fchroot04
+fchroot05
diff --git a/testcases/kernel/syscalls/fchroot/fchroot05.c b/testcases/kernel/syscalls/fchroot/fchroot05.c
new file mode 100644
index 000000000..f183d749c
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot05.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test that the failfs root can not be referenced once it is the process
+ * root.
+ *
+ * After :manpage:`fchroot(2)` moved the root into failfs, the root
+ * directory can not be opened anymore, not even with ``O_PATH``, because the
+ * walk lands on the failfs root as its terminal. The root also can not
+ * be pinned by following the /proc/self/root magic link into it, although
+ * :manpage:`readlink(2)` still names it as "failfs:/" since it does not
+ * follow the link.
+ *
+ * Root is required because entering failfs with the ``FD_FAILFS_ROOT``
+ * sentinel requires ``CAP_SYS_CHROOT``.
+ *
+ * /proc must be opened before entering failfs because every absolute path
+ * lookup fails once the root is unreachable. The test runs in a forked
+ * child so the root of the parent process is left untouched.
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+
+static void run(void)
+{
+ if (SAFE_FORK())
+ return;
+
+ char buf[PATH_MAX];
+ struct stat st;
+ int procfd, len;
+
+ procfd = SAFE_OPEN("/proc", O_PATH | O_DIRECTORY);
+
+ TST_EXP_PASS(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
+ "fchroot() with the FD_FAILFS_ROOT sentinel");
+
+ TST_EXP_FAIL2(open("/", O_RDONLY | O_DIRECTORY), EOPNOTSUPP,
+ "open() of the failfs root");
+
+ TST_EXP_FAIL2(open("/", O_PATH), EOPNOTSUPP,
+ "O_PATH open() of the failfs root");
+
+ TST_EXP_FAIL2(openat(procfd, "self/root", O_PATH), EOPNOTSUPP,
+ "pin of the root via /proc/self/root");
+
+ TST_EXP_FAIL(fstatat(procfd, "self/root", &st, 0), EOPNOTSUPP,
+ "stat of the root via /proc/self/root");
+
+ len = readlinkat(procfd, "self/root", buf, sizeof(buf) - 1);
+ if (len < 0) {
+ tst_res(TFAIL | TTERRNO, "readlinkat() of /proc/self/root");
+ } else {
+ buf[len] = '\0';
+ TST_EXP_EQ_STR(buf, "failfs:/");
+ }
+
+ exit(0);
+}
+
+static struct tst_test test = {
+ .test_all = run,
+ .needs_root = 1,
+ .forks_child = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 09/15] fchroot06: test path walks under failfs root
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (7 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 08/15] fchroot05: test failfs root can not be referenced Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 10/15] fchroot07: test execve blocked by " Andrea Cervesato
` (5 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that once the root is in failfs only lookups anchored at a
file descriptor keep working: relative lookups from the working
directory and from a pre-opened directory fd succeed, absolute
symlinks fail with EOPNOTSUPP and ".." walks clamp at the top of the
mount tree, landing on the real root.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot06.c | 126 ++++++++++++++++++++++++++
3 files changed, 128 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 49f51d637..8b6b1ecd9 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -5,3 +5,4 @@ fchroot02 fchroot02
fchroot03 fchroot03
fchroot04 fchroot04
fchroot05 fchroot05
+fchroot06 fchroot06
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index 0697f10eb..12151270a 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -3,3 +3,4 @@ fchroot02
fchroot03
fchroot04
fchroot05
+fchroot06
diff --git a/testcases/kernel/syscalls/fchroot/fchroot06.c b/testcases/kernel/syscalls/fchroot/fchroot06.c
new file mode 100644
index 000000000..8f678344f
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot06.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test path walks under the failfs root.
+ *
+ * Once :manpage:`fchroot(2)` moved the process root into failfs, only
+ * lookups anchored at a file descriptor keep working:
+ *
+ * - lookups relative to the working directory, which stays in the real
+ * filesystem, keep working
+ * - lookups anchored at a pre-opened directory fd keep working, including
+ * resolution of relative symlinks
+ * - absolute symlinks restart the walk at the failfs root and fail with
+ * ``EOPNOTSUPP``
+ * - ".." walks clamp at the top of the mount tree, not at the failfs
+ * root, so walking up from the working directory lands on the real
+ * root
+ *
+ * Root is required because entering failfs with the ``FD_FAILFS_ROOT``
+ * sentinel requires ``CAP_SYS_CHROOT``.
+ *
+ * The test runs in a forked child so the root of the parent process is
+ * left untouched.
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <sys/stat.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+#include "tst_safe_file_at.h"
+
+#define RELDIR "rel"
+#define ABSDIR "abs"
+
+static char upwards[PATH_MAX];
+
+static void run(void)
+{
+ if (SAFE_FORK())
+ return;
+
+ struct stat realroot, st;
+ int dfd, fd;
+
+ SAFE_STAT("/", &realroot);
+ dfd = SAFE_OPEN(".", O_RDONLY | O_DIRECTORY);
+
+ TST_EXP_PASS(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
+ "fchroot() with the FD_FAILFS_ROOT sentinel");
+
+ fd = TST_EXP_FD(openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY));
+ if (fd != -1)
+ SAFE_CLOSE(fd);
+
+ fd = TST_EXP_FD(openat(dfd, "canary", O_WRONLY | O_CREAT, 0600));
+ if (fd != -1) {
+ SAFE_WRITE(SAFE_WRITE_ALL, fd, "x", 1);
+ SAFE_CLOSE(fd);
+ }
+
+ fd = TST_EXP_FD(openat(dfd, RELDIR, O_RDONLY));
+ if (fd != -1)
+ SAFE_CLOSE(fd);
+
+ TST_EXP_FAIL2(openat(dfd, ABSDIR, O_RDONLY), EOPNOTSUPP,
+ "resolution of an absolute symlink");
+
+ fd = TST_EXP_FD(openat(AT_FDCWD, upwards, O_PATH));
+ if (fd != -1) {
+ SAFE_FSTAT(fd, &st);
+ SAFE_CLOSE(fd);
+
+ TST_EXP_EXPR(st.st_dev == realroot.st_dev &&
+ st.st_ino == realroot.st_ino,
+ "'..' walk clamps at the top of the mount tree");
+ }
+
+ SAFE_CLOSE(dfd);
+
+ exit(0);
+}
+
+static void setup(void)
+{
+ char *tmpdir;
+ char abs_path[PATH_MAX];
+ struct stat root_st, st;
+ int fd, off;
+
+ tmpdir = tst_tmpdir_path();
+ snprintf(abs_path, sizeof(abs_path), "%s/%s", tmpdir, "target");
+
+ SAFE_TOUCH("target", 0644, NULL);
+ SAFE_SYMLINK("target", RELDIR);
+ SAFE_SYMLINK(abs_path, ABSDIR);
+
+ SAFE_STAT("/", &root_st);
+
+ off = snprintf(upwards, sizeof(upwards), "..");
+ while (1) {
+ fd = SAFE_OPENAT(AT_FDCWD, upwards, O_PATH);
+ SAFE_FSTAT(fd, &st);
+ SAFE_CLOSE(fd);
+
+ if (st.st_dev == root_st.st_dev && st.st_ino == root_st.st_ino)
+ break;
+
+ if ((size_t)off + sizeof("/..") > sizeof(upwards))
+ tst_brk(TBROK, "Path to root too long");
+
+ off += snprintf(upwards + off, sizeof(upwards) - off, "/..");
+ }
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .test_all = run,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 10/15] fchroot07: test execve blocked by failfs root
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (8 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 09/15] fchroot06: test path walks under failfs root Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 11/15] fchroot09: test setns escape from " Andrea Cervesato
` (4 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that after fchroot() moved the root into failfs, loading a
binary by absolute path fails with EOPNOTSUPP. The exec runs in a
grandchild so a wrongly successful exec is still detected through
the exit code.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 2 +
testcases/kernel/syscalls/fchroot/.gitignore | 3 +
testcases/kernel/syscalls/fchroot/fchroot07.c | 56 ++++++++++++++++++
.../kernel/syscalls/fchroot/fchroot07_child.c | 16 +++++
testcases/kernel/syscalls/fchroot/fchroot08.c | 69 ++++++++++++++++++++++
5 files changed, 146 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 8b6b1ecd9..8dfe95c4a 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -6,3 +6,5 @@ fchroot03 fchroot03
fchroot04 fchroot04
fchroot05 fchroot05
fchroot06 fchroot06
+fchroot07 fchroot07
+fchroot08 fchroot08
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index 12151270a..0a2510d8a 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -4,3 +4,6 @@ fchroot03
fchroot04
fchroot05
fchroot06
+fchroot07
+fchroot07_child
+fchroot08
diff --git a/testcases/kernel/syscalls/fchroot/fchroot07.c b/testcases/kernel/syscalls/fchroot/fchroot07.c
new file mode 100644
index 000000000..a57d3e6ce
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot07.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test that :manpage:`execve(2)` is blocked under the failfs root.
+ *
+ * After :manpage:`fchroot(2)` moved the process root into failfs, loading
+ * a binary by absolute path fails with ``EOPNOTSUPP``.
+ *
+ * Root is required because entering failfs with the ``FD_FAILFS_ROOT``
+ * sentinel requires ``CAP_SYS_CHROOT``.
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+
+#define CHILD_EXEC "fchroot07_child"
+
+static char child_path[PATH_MAX];
+
+static void run(void)
+{
+ if (SAFE_FORK())
+ return;
+
+ TST_EXP_PASS(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
+ "fchroot() with the FD_FAILFS_ROOT sentinel");
+
+ if (!SAFE_FORK()) {
+ TST_EXP_FAIL(execl(child_path, CHILD_EXEC, NULL), EOPNOTSUPP,
+ "absolute exec blocked by the failfs root");
+ exit(0);
+ }
+
+ SAFE_WAIT(NULL);
+ exit(0);
+}
+
+static void setup(void)
+{
+ if (tst_get_path(CHILD_EXEC, child_path, sizeof(child_path)))
+ tst_brk(TCONF, "Couldn't find %s in $PATH", CHILD_EXEC);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .test_all = run,
+ .needs_root = 1,
+ .forks_child = 1,
+ .child_needs_reinit = 1,
+};
diff --git a/testcases/kernel/syscalls/fchroot/fchroot07_child.c b/testcases/kernel/syscalls/fchroot/fchroot07_child.c
new file mode 100644
index 000000000..3d731781c
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot07_child.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+int main(void)
+{
+ tst_reinit();
+
+ tst_res(TFAIL, "child executed");
+
+ return 0;
+}
diff --git a/testcases/kernel/syscalls/fchroot/fchroot08.c b/testcases/kernel/syscalls/fchroot/fchroot08.c
new file mode 100644
index 000000000..3efe8d85f
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot08.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test that the failfs root is inherited across :manpage:`fork(2)`.
+ *
+ * The root moved into failfs by :manpage:`fchroot(2)` lives in the
+ * fs_struct which is duplicated on fork, so a child of a process with the
+ * failfs root also fails every absolute path lookup with ``EOPNOTSUPP``.
+ *
+ * Root is required because entering failfs with the ``FD_FAILFS_ROOT``
+ * sentinel requires ``CAP_SYS_CHROOT``.
+ *
+ * The test runs in a forked child so the root of the parent process is
+ * left untouched.
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <sys/wait.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+
+#define ABSDIR "abs"
+
+static void run(void)
+{
+ if (SAFE_FORK())
+ return;
+
+ pid_t pid;
+
+ TST_EXP_PASS(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
+ "fchroot() with the FD_FAILFS_ROOT sentinel");
+
+ pid = SAFE_FORK();
+ if (!pid) {
+ TST_EXP_FAIL2(open(ABSDIR, O_PATH), EOPNOTSUPP,
+ "absolute lookup in a forked child");
+ exit(0);
+ }
+
+ SAFE_WAITPID(pid, NULL, 0);
+
+ exit(0);
+}
+
+static void setup(void)
+{
+ char *tmpdir;
+ char abs_path[PATH_MAX];
+
+ tmpdir = tst_tmpdir_path();
+ snprintf(abs_path, sizeof(abs_path), "%s/%s", tmpdir, "target");
+
+ SAFE_TOUCH("target", 0644, NULL);
+ SAFE_SYMLINK(abs_path, ABSDIR);
+}
+
+static struct tst_test test = {
+ .test_all = run,
+ .setup = setup,
+ .needs_root = 1,
+ .forks_child = 1,
+ .needs_tmpdir = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 11/15] fchroot09: test setns escape from failfs root
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (9 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 10/15] fchroot07: test execve blocked by " Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 12/15] fchroot10: test failfs entry without no_new_privs Andrea Cervesato
` (3 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that entering failfs with fchroot() is hard to undo: a process
inside counts as chrooted, so the remaining way out is a pre-opened
mount namespace fd. setns() into it resets both the root and the
working directory.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot09.c | 86 +++++++++++++++++++++++++++
3 files changed, 88 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 8dfe95c4a..23f6c6a20 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -8,3 +8,4 @@ fchroot05 fchroot05
fchroot06 fchroot06
fchroot07 fchroot07
fchroot08 fchroot08
+fchroot09 fchroot09
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index 0a2510d8a..b577da61f 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -7,3 +7,4 @@ fchroot06
fchroot07
fchroot07_child
fchroot08
+fchroot09
diff --git a/testcases/kernel/syscalls/fchroot/fchroot09.c b/testcases/kernel/syscalls/fchroot/fchroot09.c
new file mode 100644
index 000000000..a6bca5085
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot09.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test that :manpage:`setns(2)` escapes the failfs root.
+ *
+ * Entering failfs with :manpage:`fchroot(2)` is hard to undo: a process
+ * inside counts as chrooted, so :manpage:`chroot(2)` and fchroot() back
+ * out require ``CAP_SYS_CHROOT``. The remaining way out is a pre-opened mount
+ * namespace file descriptor: setns() into it resets both the root and the
+ * working directory.
+ *
+ * Root is required because entering failfs requires ``CAP_SYS_CHROOT`` and
+ * :manpage:`setns(2)` into the mount namespace requires ``CAP_SYS_ADMIN``.
+ *
+ * The test runs in a forked child so the root of the parent process is
+ * left untouched.
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <sys/stat.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/sched.h"
+#include "lapi/setns.h"
+#include "lapi/syscalls.h"
+
+#define ABSDIR "abs"
+
+static void run(void)
+{
+ if (SAFE_FORK())
+ return;
+
+ struct stat realroot, st;
+ int nsfd;
+
+ SAFE_STAT("/", &realroot);
+ nsfd = SAFE_OPEN("/proc/self/ns/mnt", O_RDONLY);
+
+ TST_EXP_PASS(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
+ "fchroot() with the FD_FAILFS_ROOT sentinel");
+
+ TST_EXP_FAIL2(open(ABSDIR, O_PATH), EOPNOTSUPP,
+ "absolute lookup after entering failfs");
+
+ TST_EXP_PASS(setns(nsfd, CLONE_NEWNS),
+ "setns() back into the mount namespace");
+
+ SAFE_CLOSE(nsfd);
+
+ SAFE_STAT("/", &st);
+ TST_EXP_EXPR(st.st_dev == realroot.st_dev &&
+ st.st_ino == realroot.st_ino,
+ "root restored after setns()");
+
+ SAFE_STAT(".", &st);
+ TST_EXP_EXPR(st.st_dev == realroot.st_dev &&
+ st.st_ino == realroot.st_ino,
+ "working directory restored after setns()");
+
+ exit(0);
+}
+
+static void setup(void)
+{
+ char *tmpdir;
+ char abs_path[PATH_MAX];
+
+ tmpdir = tst_tmpdir_path();
+ snprintf(abs_path, sizeof(abs_path), "%s/%s", tmpdir, "target");
+
+ SAFE_TOUCH("target", 0644, NULL);
+ SAFE_SYMLINK(abs_path, ABSDIR);
+}
+
+static struct tst_test test = {
+ .test_all = run,
+ .setup = setup,
+ .needs_root = 1,
+ .forks_child = 1,
+ .needs_tmpdir = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 12/15] fchroot10: test failfs entry without no_new_privs
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (10 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 11/15] fchroot09: test setns escape from " Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 13/15] fchroot11: test failfs entry with no_new_privs Andrea Cervesato
` (2 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that unprivileged fchroot() into failfs is refused without
no_new_privs: without it a setuid binary on a regular mount is still
reachable via an inherited directory fd, and executing it with an
unusable root directory is the classic confused deputy, so the kernel
refuses the syscall with EPERM.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot10.c | 50 +++++++++++++++++++++++++++
3 files changed, 52 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 23f6c6a20..9ec2a7897 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -9,3 +9,4 @@ fchroot06 fchroot06
fchroot07 fchroot07
fchroot08 fchroot08
fchroot09 fchroot09
+fchroot10 fchroot10
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index b577da61f..53a1fa1d0 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -8,3 +8,4 @@ fchroot07
fchroot07_child
fchroot08
fchroot09
+fchroot10
diff --git a/testcases/kernel/syscalls/fchroot/fchroot10.c b/testcases/kernel/syscalls/fchroot/fchroot10.c
new file mode 100644
index 000000000..0cce3e40a
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot10.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test that unprivileged :manpage:`fchroot(2)` into failfs is refused
+ * without no_new_privs.
+ *
+ * Without no_new_privs a setuid binary on a regular mount is still
+ * reachable via an inherited directory file descriptor, and executing it
+ * with an unusable root directory is the classic confused deputy, so the
+ * kernel refuses the syscall with ``EPERM``.
+ *
+ * Root is required to drop to an unprivileged user in the forked child.
+ */
+
+#define _GNU_SOURCE
+#include <pwd.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+
+static struct passwd *ltpuser;
+
+static void run(void)
+{
+ if (SAFE_FORK())
+ return;
+
+ SAFE_SETRESUID(ltpuser->pw_uid, ltpuser->pw_uid,
+ ltpuser->pw_uid);
+
+ TST_EXP_FAIL(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
+ EPERM, "unprivileged fchroot() without no_new_privs");
+
+ exit(0);
+}
+
+static void setup(void)
+{
+ ltpuser = SAFE_GETPWNAM("nobody");
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .test_all = run,
+ .needs_root = 1,
+ .forks_child = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 13/15] fchroot11: test failfs entry with no_new_privs
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (11 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 12/15] fchroot10: test failfs entry without no_new_privs Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 14/15] fchroot12: test failfs entry with shared fs_struct Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 15/15] fchroot13: test failfs entry when chrooted Andrea Cervesato
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that an unprivileged process may enter failfs when it
committed to no_new_privs, since setuid binaries then pose no
confused deputy risk anymore. The test also verifies that a process
which entered failfs counts as chrooted: it can no longer create a
user namespace with unshare() to regain CAP_SYS_CHROOT.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot11.c | 70 +++++++++++++++++++++++++++
3 files changed, 72 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 9ec2a7897..137e3f99a 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -10,3 +10,4 @@ fchroot07 fchroot07
fchroot08 fchroot08
fchroot09 fchroot09
fchroot10 fchroot10
+fchroot11 fchroot11
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index 53a1fa1d0..650ef2690 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -9,3 +9,4 @@ fchroot07_child
fchroot08
fchroot09
fchroot10
+fchroot11
diff --git a/testcases/kernel/syscalls/fchroot/fchroot11.c b/testcases/kernel/syscalls/fchroot/fchroot11.c
new file mode 100644
index 000000000..85401e5fe
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot11.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test unprivileged :manpage:`fchroot(2)` into failfs with no_new_privs
+ * set.
+ *
+ * An unprivileged process may enter failfs when it committed to
+ * no_new_privs, since setuid binaries then pose no confused deputy risk
+ * anymore. The test also verifies that a process which entered failfs
+ * counts as chrooted: it can no longer create a user namespace with
+ * :manpage:`unshare(2)` to regain ``CAP_SYS_CHROOT``.
+ *
+ * The user namespace check requires ``CONFIG_USER_NS``, which is enforced
+ * with ``.needs_kconfigs``.
+ *
+ * Root is required to drop to an unprivileged user in the forked child.
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <pwd.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/prctl.h"
+#include "lapi/sched.h"
+#include "lapi/syscalls.h"
+
+static struct passwd *ltpuser;
+
+static void run(void)
+{
+ if (SAFE_FORK())
+ return;
+
+ SAFE_SETRESUID(ltpuser->pw_uid, ltpuser->pw_uid,
+ ltpuser->pw_uid);
+
+ SAFE_PRCTL(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+
+ TST_EXP_PASS(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
+ "unprivileged fchroot() with no_new_privs");
+
+ TST_EXP_FAIL2(open("/etc/passwd", O_RDONLY), EOPNOTSUPP,
+ "absolute lookup after entering failfs");
+
+ TST_EXP_FAIL(unshare(CLONE_NEWUSER), EPERM,
+ "user namespace creation blocked by the failfs root");
+
+ exit(0);
+}
+
+static void setup(void)
+{
+ ltpuser = SAFE_GETPWNAM("nobody");
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .test_all = run,
+ .needs_root = 1,
+ .forks_child = 1,
+ .needs_kconfigs = (const char *[]) {
+ "CONFIG_USER_NS=y",
+ NULL,
+ }
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 14/15] fchroot12: test failfs entry with shared fs_struct
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (12 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 13/15] fchroot11: test failfs entry with no_new_privs Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 15/15] fchroot13: test failfs entry when chrooted Andrea Cervesato
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that unprivileged fchroot() into failfs is refused with a
shared fs_struct: a CLONE_FS sibling without no_new_privs could
execute a setuid binary with the failfs root, so entry requires
fs->users == 1, the same restriction setns() applies for the mount
namespace. The sibling bumps fs->users to 2, making the syscall fail
with EINVAL.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot12.c | 85 +++++++++++++++++++++++++++
3 files changed, 87 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 137e3f99a..1655b6813 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -11,3 +11,4 @@ fchroot08 fchroot08
fchroot09 fchroot09
fchroot10 fchroot10
fchroot11 fchroot11
+fchroot12 fchroot12
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index 650ef2690..e8a6730ee 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -10,3 +10,4 @@ fchroot08
fchroot09
fchroot10
fchroot11
+fchroot12
diff --git a/testcases/kernel/syscalls/fchroot/fchroot12.c b/testcases/kernel/syscalls/fchroot/fchroot12.c
new file mode 100644
index 000000000..c08144ecc
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot12.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test that unprivileged :manpage:`fchroot(2)` into failfs is refused
+ * with a shared ``fs_struct``.
+ *
+ * ``no_new_privs`` is checked on the calling thread, but the root lives in
+ * the fs_struct shared with a :manpage:`clone(2)` ``CLONE_FS`` sibling. A
+ * sibling without no_new_privs could execute a setuid binary with the
+ * failfs root, so entry requires ``fs->users == 1``, the same restriction
+ * :manpage:`setns(2)` applies for the mount namespace. The sibling bumps
+ * ``fs->users`` to 2, making the syscall fail with ``EINVAL``.
+ *
+ * Root is required to drop to an unprivileged user in the forked child.
+ */
+
+#define _GNU_SOURCE
+#include <sys/wait.h>
+#include <pwd.h>
+#include <sched.h>
+#include <signal.h>
+#include <unistd.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/prctl.h"
+#include "lapi/sched.h"
+#include "lapi/syscalls.h"
+
+static struct passwd *ltpuser;
+
+static void run(void)
+{
+ if (SAFE_FORK())
+ return;
+
+ struct tst_clone_args args = {
+ .flags = CLONE_FS,
+ .exit_signal = SIGCHLD,
+ };
+ pid_t parent = getpid();
+ pid_t sib;
+
+ SAFE_SETRESUID(ltpuser->pw_uid, ltpuser->pw_uid,
+ ltpuser->pw_uid);
+
+ sib = SAFE_CLONE(&args);
+ if (!sib) {
+ /*
+ * Parked sibling sharing the fs_struct with the
+ * caller. It must die with the parent, otherwise it
+ * would outlive the test.
+ */
+ SAFE_PRCTL(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ if (getppid() == parent)
+ pause();
+ exit(0);
+ }
+
+ SAFE_PRCTL(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+
+ TST_EXP_FAIL(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
+ EINVAL, "fchroot() with a shared fs_struct");
+
+ SAFE_KILL(sib, SIGKILL);
+ SAFE_WAITPID(sib, NULL, 0);
+
+ exit(0);
+}
+
+static void setup(void)
+{
+ clone3_supported_by_kernel();
+
+ ltpuser = SAFE_GETPWNAM("nobody");
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .test_all = run,
+ .needs_root = 1,
+ .forks_child = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread* [LTP] [PATCH STAGING v3 15/15] fchroot13: test failfs entry when chrooted
2026-08-28 14:11 [LTP] [PATCH v3 00/15] fchroot: add fchroot() testing suite Andrea Cervesato
` (13 preceding siblings ...)
2026-08-28 14:11 ` [LTP] [PATCH STAGING v3 14/15] fchroot12: test failfs entry with shared fs_struct Andrea Cervesato
@ 2026-08-28 14:11 ` Andrea Cervesato
14 siblings, 0 replies; 17+ messages in thread
From: Andrea Cervesato @ 2026-08-28 14:11 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that unprivileged fchroot() into failfs is refused when the
process is already chrooted: moving the root of a chrooted task into
failfs would allow it to escape its chroot via openat(fd, "..") with
a pre-opened directory fd, so the kernel refuses the syscall with
EPERM.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot13.c | 63 +++++++++++++++++++++++++++
3 files changed, 65 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 1655b6813..95e777ffb 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -12,3 +12,4 @@ fchroot09 fchroot09
fchroot10 fchroot10
fchroot11 fchroot11
fchroot12 fchroot12
+fchroot13 fchroot13
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index e8a6730ee..3e77e3762 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -11,3 +11,4 @@ fchroot09
fchroot10
fchroot11
fchroot12
+fchroot13
diff --git a/testcases/kernel/syscalls/fchroot/fchroot13.c b/testcases/kernel/syscalls/fchroot/fchroot13.c
new file mode 100644
index 000000000..e90e6f663
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot13.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Test that unprivileged :manpage:`fchroot(2)` into failfs is refused
+ * when the process is already chrooted.
+ *
+ * The root directory is what confines ".." resolution and the failfs root
+ * can never be reached by walking up a real mount tree. Moving the root
+ * of a chrooted task into failfs would allow it to escape its chroot via
+ * ``openat(fd, "..")`` with a pre-opened directory fd, so the kernel refuses
+ * the syscall with ``EPERM``.
+ *
+ * Root is required to create the chroot jail before dropping to an
+ * unprivileged user in the forked child.
+ */
+
+#define _GNU_SOURCE
+#include <pwd.h>
+#include <unistd.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/prctl.h"
+#include "lapi/syscalls.h"
+
+#define JAILDIR "jail"
+
+static struct passwd *ltpuser;
+
+static void run(void)
+{
+ if (SAFE_FORK())
+ return;
+
+ SAFE_CHROOT(JAILDIR);
+ SAFE_CHDIR("/");
+
+ SAFE_SETRESUID(ltpuser->pw_uid, ltpuser->pw_uid,
+ ltpuser->pw_uid);
+
+ SAFE_PRCTL(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+
+ TST_EXP_FAIL(tst_syscall(__NR_fchroot, FD_FAILFS_ROOT, 0),
+ EPERM, "fchroot() from a chrooted process");
+
+ exit(0);
+}
+
+static void setup(void)
+{
+ ltpuser = SAFE_GETPWNAM("nobody");
+ SAFE_MKDIR(JAILDIR, 0755);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .test_all = run,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 17+ messages in thread