* [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite
@ 2026-08-20 7:44 Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH v2 01/16] syscalls: add v7.3 syscall numbers Andrea Cervesato
` (15 more replies)
0 siblings, 16 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 UTC (permalink / raw)
To: Linux Test Project
fchroot() is a new syscall introduced in the Linux v7.3 development
cycle together with failfs, a kernel internal filesystem where every
operation fails with EOPNOTSUPP. The syscall is the fd-based
counterpart of chroot(2): it moves the process root to the directory
referenced by a file descriptor, or to the failfs root via the
FD_FAILFS_ROOT sentinel.
The series first updates the architecture syscall number tables and
adds lapi fallback definitions for the new fd sentinels, then adds 13
tests covering:
- the basic directory fd use case and the argument error paths
(EINVAL, EBADF, ENOTDIR)
- the permission checks, both execute permission and CAP_SYS_CHROOT
- entering failfs as root: EOPNOTSUPP on every absolute lookup,
unreachable working directory, root that can not be referenced or
pinned, path walks anchored at file descriptors, execve blocked,
fork inheritance and the setns() escape
- the unprivileged entry rules: no_new_privs, shared fs_struct and
the already chrooted case
fchroot() is not part of any released kernel yet, so the tests are
added to runtest/staging and each patch carries the [STAGING] prefix
as required by the LTP ground rules.
The testing suite creation has been assisted by GLM 5.3.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Changes in v2:
- make description more readable
- invert fork() logic for the main test process
- fix the issues found by the agent
- Link to v1: https://lore.kernel.org/20260819-fchroot-v1-0-2dc2c3c3cf29@suse.com
To: Linux Test Project <ltp@lists.linux.it>
---
Andrea Cervesato (16):
syscalls: add v7.3 syscall numbers
syscalls: update outdated syscall entries
[STAGING] lapi: fallback fchroot() parameters
[STAGING] fchroot01: test fchroot() with a directory fd
[STAGING] fchroot02: test fchroot() invalid arguments
[STAGING] fchroot03: test fchroot() permission checks
[STAGING] fchroot04: test fchroot() into failfs as root
[STAGING] fchroot05: test failfs root can not be referenced
[STAGING] fchroot06: test path walks under failfs root
[STAGING] fchroot07: test execve blocked by failfs root
[STAGING] fchroot08: test failfs root fork inheritance
[STAGING] fchroot09: test setns escape from failfs root
[STAGING] fchroot10: test failfs entry without no_new_privs
[STAGING] fchroot11: test failfs entry with no_new_privs
[STAGING] fchroot12: test failfs entry with shared fs_struct
[STAGING] fchroot13: test failfs entry when chrooted
include/lapi/fcntl.h | 13 +++
include/lapi/syscalls/arc.in | 3 +
include/lapi/syscalls/arm.in | 4 +-
include/lapi/syscalls/arm64.in | 3 +
include/lapi/syscalls/i386.in | 4 +-
include/lapi/syscalls/loongarch64.in | 3 +
include/lapi/syscalls/mips64.in | 5 +-
include/lapi/syscalls/mips64n32.in | 5 +-
include/lapi/syscalls/mipso32.in | 5 +-
include/lapi/syscalls/parisc.in | 4 +-
include/lapi/syscalls/powerpc.in | 4 +-
include/lapi/syscalls/powerpc64.in | 4 +-
include/lapi/syscalls/s390.in | 5 +-
include/lapi/syscalls/s390x.in | 5 +-
include/lapi/syscalls/sh.in | 4 +-
include/lapi/syscalls/sparc.in | 5 +-
include/lapi/syscalls/sparc64.in | 5 +-
include/lapi/syscalls/x86_64.in | 5 +-
runtest/staging | 14 +++
testcases/kernel/syscalls/fchroot/.gitignore | 13 +++
testcases/kernel/syscalls/fchroot/Makefile | 7 ++
testcases/kernel/syscalls/fchroot/fchroot01.c | 59 +++++++++++++
testcases/kernel/syscalls/fchroot/fchroot02.c | 80 ++++++++++++++++++
testcases/kernel/syscalls/fchroot/fchroot03.c | 78 +++++++++++++++++
testcases/kernel/syscalls/fchroot/fchroot04.c | 70 +++++++++++++++
testcases/kernel/syscalls/fchroot/fchroot05.c | 75 +++++++++++++++++
testcases/kernel/syscalls/fchroot/fchroot06.c | 117 ++++++++++++++++++++++++++
testcases/kernel/syscalls/fchroot/fchroot07.c | 72 ++++++++++++++++
testcases/kernel/syscalls/fchroot/fchroot08.c | 69 +++++++++++++++
testcases/kernel/syscalls/fchroot/fchroot09.c | 87 +++++++++++++++++++
testcases/kernel/syscalls/fchroot/fchroot10.c | 50 +++++++++++
testcases/kernel/syscalls/fchroot/fchroot11.c | 70 +++++++++++++++
testcases/kernel/syscalls/fchroot/fchroot12.c | 85 +++++++++++++++++++
testcases/kernel/syscalls/fchroot/fchroot13.c | 63 ++++++++++++++
34 files changed, 1076 insertions(+), 19 deletions(-)
---
base-commit: 567528e2f809c1309802433703c083bd15ab81a8
change-id: 20260819-fchroot-66115fd0d497
Best regards,
--
Andrea Cervesato <andrea.cervesato@suse.com>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 26+ messages in thread
* [LTP] [PATCH v2 01/16] syscalls: add v7.3 syscall numbers
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 8:34 ` [LTP] " linuxtestproject.agent
2026-08-20 7:44 ` [LTP] [PATCH v2 02/16] syscalls: update outdated syscall entries Andrea Cervesato
` (14 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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] 26+ messages in thread
* [LTP] [PATCH v2 02/16] syscalls: update outdated syscall entries
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH v2 01/16] syscalls: add v7.3 syscall numbers Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 03/16] lapi: fallback fchroot() parameters Andrea Cervesato
` (13 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 03/16] lapi: fallback fchroot() parameters
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH v2 01/16] syscalls: add v7.3 syscall numbers Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH v2 02/16] syscalls: update outdated syscall entries Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 04/16] fchroot01: test fchroot() with a directory fd Andrea Cervesato
` (12 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 04/16] fchroot01: test fchroot() with a directory fd
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (2 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 03/16] lapi: fallback fchroot() parameters Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 14:13 ` Cyril Hrubis
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 05/16] fchroot02: test fchroot() invalid arguments Andrea Cervesato
` (11 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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 | 59 +++++++++++++++++++++++++++
4 files changed, 69 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..dc83c5b0d
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot01.c
@@ -0,0 +1,59 @@
+// 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 syscall runs in a forked child so that the root of the parent
+ * process, which the test framework needs for its cleanup, 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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 05/16] fchroot02: test fchroot() invalid arguments
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (3 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 04/16] fchroot01: test fchroot() with a directory fd Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 14:10 ` Cyril Hrubis
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 06/16] fchroot03: test fchroot() permission checks Andrea Cervesato
` (10 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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 | 80 +++++++++++++++++++++++++++
3 files changed, 82 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..96be00d70
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot02.c
@@ -0,0 +1,80 @@
+// 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.
+ *
+ * :manpage:`fchroot(2)` was introduced in Linux v7.3. The syscall checks its
+ * arguments in this order:
+ *
+ * - a non-zero flags argument fails with ``EINVAL`` before anything else,
+ * including with the ``FD_FAILFS_ROOT`` sentinel and with an invalid fd
+ * - 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, 1, EINVAL, "non-zero flags with an invalid fd"},
+ {&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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 06/16] fchroot03: test fchroot() permission checks
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (4 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 05/16] fchroot02: test fchroot() invalid arguments Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 14:19 ` Cyril Hrubis
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 07/16] fchroot04: test fchroot() into failfs as root Andrea Cervesato
` (9 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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 | 78 +++++++++++++++++++++++++++
3 files changed, 80 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..79d3daf7d
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot03.c
@@ -0,0 +1,78 @@
+// 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.
+ *
+ * :manpage:`fchroot(2) `was introduced in Linux v7.3. With a regular directory
+ * fd the kernel first checks that the caller has execute permission on the
+ * directory, then that it holds ``CAP_SYS_CHROOT``:
+ *
+ * - an unprivileged process with an accessible directory fails with ``EPERM``
+ * - a process without execute permission on the directory fails with
+ * ``EACCES``, proving the permission check comes before the capability
+ * check
+ *
+ * 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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 07/16] fchroot04: test fchroot() into failfs as root
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (5 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 06/16] fchroot03: test fchroot() permission checks Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 14:24 ` Cyril Hrubis
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 08/16] fchroot05: test failfs root can not be referenced Andrea Cervesato
` (8 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 08/16] fchroot05: test failfs root can not be referenced
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (6 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 07/16] fchroot04: test fchroot() into failfs as root Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 14:37 ` Cyril Hrubis
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 09/16] fchroot06: test path walks under failfs root Andrea Cervesato
` (7 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 09/16] fchroot06: test path walks under failfs root
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (7 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 08/16] fchroot05: test failfs root can not be referenced Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 10/16] fchroot07: test execve blocked by " Andrea Cervesato
` (6 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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 | 117 ++++++++++++++++++++++++++
3 files changed, 119 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..bf6c4fea4
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot06.c
@@ -0,0 +1,117 @@
+// 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 = SAFE_OPENAT(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY);
+ SAFE_CLOSE(fd);
+
+ fd = SAFE_OPENAT(dfd, "canary", O_WRONLY | O_CREAT, 0600);
+ SAFE_WRITE(SAFE_WRITE_ALL, fd, "x", 1);
+ SAFE_CLOSE(fd);
+
+ fd = SAFE_OPENAT(dfd, RELDIR, O_RDONLY);
+ SAFE_CLOSE(fd);
+
+ TST_EXP_FAIL2(openat(dfd, ABSDIR, O_RDONLY), EOPNOTSUPP,
+ "resolution of an absolute symlink");
+
+ fd = SAFE_OPENAT(AT_FDCWD, upwards, O_PATH);
+ 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;
+
+ 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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 10/16] fchroot07: test execve blocked by failfs root
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (8 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 09/16] fchroot06: test path walks under failfs root Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 11/16] fchroot08: test failfs root fork inheritance Andrea Cervesato
` (5 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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 | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot07.c | 72 +++++++++++++++++++++++++++
3 files changed, 74 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index 8b6b1ecd9..b8954bb5a 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -6,3 +6,4 @@ fchroot03 fchroot03
fchroot04 fchroot04
fchroot05 fchroot05
fchroot06 fchroot06
+fchroot07 fchroot07
diff --git a/testcases/kernel/syscalls/fchroot/.gitignore b/testcases/kernel/syscalls/fchroot/.gitignore
index 12151270a..b68069d9a 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -4,3 +4,4 @@ fchroot03
fchroot04
fchroot05
fchroot06
+fchroot07
diff --git a/testcases/kernel/syscalls/fchroot/fchroot07.c b/testcases/kernel/syscalls/fchroot/fchroot07.c
new file mode 100644
index 000000000..d5ebfc576
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot07.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 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``.
+ *
+ * The exec runs in a grandchild: a wrongly successful exec would replace
+ * the test image, so the outcome can only be reported when the exec call
+ * returns, and the grandchild exit code tells the parent whether the
+ * image was replaced.
+ */
+
+#define _GNU_SOURCE
+#include <sys/wait.h>
+#include <unistd.h>
+#include "tst_test.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+
+/* Marker exit code proving the grandchild image was not replaced. */
+#define EXEC_NOT_REPLACED 42
+
+static void check_exec_blocked(void)
+{
+ pid_t pid = SAFE_FORK();
+ int status;
+
+ if (!pid) {
+ TST_EXP_FAIL(execl("/bin/true", "true", NULL), EOPNOTSUPP,
+ "absolute exec blocked by the failfs root");
+
+ exit(EXEC_NOT_REPLACED);
+ }
+
+ SAFE_WAITPID(pid, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != EXEC_NOT_REPLACED)
+ tst_res(TFAIL, "exec replaced the test image");
+}
+
+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");
+
+ check_exec_blocked();
+
+ exit(0);
+}
+
+static void setup(void)
+{
+ if (access("/bin/true", X_OK))
+ tst_brk(TCONF | TERRNO, "/bin/true is not available");
+}
+
+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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 11/16] fchroot08: test failfs root fork inheritance
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (9 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 10/16] fchroot07: test execve blocked by " Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 12/16] fchroot09: test setns escape from failfs root Andrea Cervesato
` (4 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Verify that the root moved into failfs by fchroot() 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.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/staging | 1 +
testcases/kernel/syscalls/fchroot/.gitignore | 1 +
testcases/kernel/syscalls/fchroot/fchroot08.c | 69 +++++++++++++++++++++++++++
3 files changed, 71 insertions(+)
diff --git a/runtest/staging b/runtest/staging
index b8954bb5a..8dfe95c4a 100644
--- a/runtest/staging
+++ b/runtest/staging
@@ -7,3 +7,4 @@ 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 b68069d9a..c099b4b3a 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -5,3 +5,4 @@ fchroot04
fchroot05
fchroot06
fchroot07
+fchroot08
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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 12/16] fchroot09: test setns escape from failfs root
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (10 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 11/16] fchroot08: test failfs root fork inheritance Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 13/16] fchroot10: test failfs entry without no_new_privs Andrea Cervesato
` (3 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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 | 87 +++++++++++++++++++++++++++
3 files changed, 89 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 c099b4b3a..e803fa2b7 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -6,3 +6,4 @@ fchroot05
fchroot06
fchroot07
fchroot08
+fchroot09
diff --git a/testcases/kernel/syscalls/fchroot/fchroot09.c b/testcases/kernel/syscalls/fchroot/fchroot09.c
new file mode 100644
index 000000000..adcc47352
--- /dev/null
+++ b/testcases/kernel/syscalls/fchroot/fchroot09.c
@@ -0,0 +1,87 @@
+// 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, realcwd, st;
+ int nsfd;
+
+ SAFE_STAT("/", &realroot);
+ SAFE_STAT(".", &realcwd);
+ 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(tst_tmpdir_path(), &st);
+ TST_EXP_EXPR(st.st_dev == realcwd.st_dev &&
+ st.st_ino == realcwd.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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 13/16] fchroot10: test failfs entry without no_new_privs
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (11 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 12/16] fchroot09: test setns escape from failfs root Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 14/16] fchroot11: test failfs entry with no_new_privs Andrea Cervesato
` (2 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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 e803fa2b7..570da2b98 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -7,3 +7,4 @@ fchroot06
fchroot07
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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 14/16] fchroot11: test failfs entry with no_new_privs
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (12 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 13/16] fchroot10: test failfs entry without no_new_privs Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 15/16] fchroot12: test failfs entry with shared fs_struct Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 16/16] fchroot13: test failfs entry when chrooted Andrea Cervesato
15 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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 570da2b98..0eca20548 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -8,3 +8,4 @@ fchroot07
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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 15/16] fchroot12: test failfs entry with shared fs_struct
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (13 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 14/16] fchroot11: test failfs entry with no_new_privs Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 16/16] fchroot13: test failfs entry when chrooted Andrea Cervesato
15 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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 0eca20548..de8ca0688 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -9,3 +9,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] 26+ messages in thread
* [LTP] [PATCH STAGING v2 16/16] fchroot13: test failfs entry when chrooted
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
` (14 preceding siblings ...)
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 15/16] fchroot12: test failfs entry with shared fs_struct Andrea Cervesato
@ 2026-08-20 7:44 ` Andrea Cervesato
15 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato @ 2026-08-20 7:44 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 de8ca0688..0c4461611 100644
--- a/testcases/kernel/syscalls/fchroot/.gitignore
+++ b/testcases/kernel/syscalls/fchroot/.gitignore
@@ -10,3 +10,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] 26+ messages in thread
* Re: [LTP] syscalls: add v7.3 syscall numbers
2026-08-20 7:44 ` [LTP] [PATCH v2 01/16] syscalls: add v7.3 syscall numbers Andrea Cervesato
@ 2026-08-20 8:34 ` linuxtestproject.agent
2026-08-20 8:37 ` Andrea Cervesato via ltp
0 siblings, 1 reply; 26+ messages in thread
From: linuxtestproject.agent @ 2026-08-20 8:34 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: ltp
Hi Andrea,
On Aug 20, 2026, Andrea Cervesato wrote:
> syscalls: add v7.3 syscall numbers
--- [PATCH 4/16] ---
> fchroot01: test fchroot() with a directory fd
Could this subject be prefixed with [STAGING]? Linux 7.2 is the latest
stable release, while this test targets fchroot() from Linux 7.3.
--- [PATCH 5/16] ---
> fchroot02: test fchroot() invalid arguments
Could this subject be prefixed with [STAGING] because the tested syscall is
not present in Linux 7.2?
--- [PATCH 6/16] ---
> fchroot03: test fchroot() permission checks
Could this subject be prefixed with [STAGING] because the tested syscall is
not present in Linux 7.2?
> * :manpage:`fchroot(2) `was introduced in Linux v7.3.
Could the space be moved after the closing backtick? As written, it becomes
part of the man-page role target.
--- [PATCH 7/16] ---
> fchroot04: test fchroot() into failfs as root
Could this subject be prefixed with [STAGING] because fchroot() and failfs
are not present in Linux 7.2?
--- [PATCH 8/16] ---
> fchroot05: test failfs root can not be referenced
Could this subject be prefixed with [STAGING] because fchroot() and failfs
are not present in Linux 7.2?
--- [PATCH 9/16] ---
> fchroot06: test path walks under failfs root
Could this subject be prefixed with [STAGING] because fchroot() and failfs
are not present in Linux 7.2?
> off += snprintf(upwards + off, sizeof(upwards) - off, "/..");
Could truncation be handled here? LTP accepts an arbitrary absolute TMPDIR.
With a sufficiently deep path, off grows past sizeof(upwards), the size
subtraction underflows, and the next iteration passes an out-of-bounds
pointer and a huge size to snprintf().
--- [PATCH 10/16] ---
> fchroot07: test execve blocked by failfs root
Could this subject be prefixed with [STAGING] because fchroot() and failfs
are not present in Linux 7.2?
--- [PATCH 11/16] ---
> fchroot08: test failfs root fork inheritance
Could this subject be prefixed with [STAGING] because fchroot() and failfs
are not present in Linux 7.2?
--- [PATCH 12/16] ---
> fchroot09: test setns escape from failfs root
Could this subject be prefixed with [STAGING] because fchroot() and failfs
are not present in Linux 7.2?
> SAFE_STAT(tst_tmpdir_path(), &st);
> TST_EXP_EXPR(st.st_dev == realcwd.st_dev &&
> st.st_ino == realcwd.st_ino,
> "working directory restored after setns()");
Could this stat "." and compare it with realroot instead? mntns_install()
sets both fs->pwd and fs->root to the mount namespace root. Calling stat on
an absolute tmpdir path succeeds regardless of the current working directory,
so a regression that leaves pwd unchanged would pass this check.
--- [PATCH 13/16] ---
> fchroot10: test failfs entry without no_new_privs
Could this subject be prefixed with [STAGING] because fchroot() and failfs
are not present in Linux 7.2?
--- [PATCH 14/16] ---
> fchroot11: test failfs entry with no_new_privs
Could this subject be prefixed with [STAGING] because fchroot() and failfs
are not present in Linux 7.2?
--- [PATCH 15/16] ---
> fchroot12: test failfs entry with shared fs_struct
Could this subject be prefixed with [STAGING] because fchroot() and failfs
are not present in Linux 7.2?
--- [PATCH 16/16] ---
> fchroot13: test failfs entry when chrooted
Could this subject be prefixed with [STAGING] because fchroot() and failfs
are not present in Linux 7.2?
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] 26+ messages in thread
* Re: [LTP] syscalls: add v7.3 syscall numbers
2026-08-20 8:34 ` [LTP] " linuxtestproject.agent
@ 2026-08-20 8:37 ` Andrea Cervesato via ltp
0 siblings, 0 replies; 26+ messages in thread
From: Andrea Cervesato via ltp @ 2026-08-20 8:37 UTC (permalink / raw)
To: linuxtestproject.agent; +Cc: ltp
> Could this subject be prefixed with [STAGING]? Linux 7.2 is the latest
> stable release, while this test targets fchroot() from Linux 7.3.
Please ignore this, it's handled by patchwork and there's no way to obtain it.
> > * :manpage:`fchroot(2) `was introduced in Linux v7.3.
>
> Could the space be moved after the closing backtick? As written, it becomes
> part of the man-page role target.
will fix before merge.
> > off += snprintf(upwards + off, sizeof(upwards) - off, "/..");
>
> Could truncation be handled here? LTP accepts an arbitrary absolute TMPDIR.
> With a sufficiently deep path, off grows past sizeof(upwards), the size
> subtraction underflows, and the next iteration passes an out-of-bounds
> pointer and a huge size to snprintf().
this can be fixed indeed.
> > SAFE_STAT(tst_tmpdir_path(), &st);
> > TST_EXP_EXPR(st.st_dev == realcwd.st_dev &&
> > st.st_ino == realcwd.st_ino,
> > "working directory restored after setns()");
>
> Could this stat "." and compare it with realroot instead? mntns_install()
> sets both fs->pwd and fs->root to the mount namespace root. Calling stat on
> an absolute tmpdir path succeeds regardless of the current working directory,
> so a regression that leaves pwd unchanged would pass this check.
this is funny, it was "." before and it was complaining. I will use "." before
merge.
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [LTP] [PATCH STAGING v2 05/16] fchroot02: test fchroot() invalid arguments
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 05/16] fchroot02: test fchroot() invalid arguments Andrea Cervesato
@ 2026-08-20 14:10 ` Cyril Hrubis
0 siblings, 0 replies; 26+ messages in thread
From: Cyril Hrubis @ 2026-08-20 14:10 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: Linux Test Project
Hi!
> +/*\
> + * Test the :manpage:`fchroot(2)` error paths for invalid arguments.
> + *
> + * :manpage:`fchroot(2)` was introduced in Linux v7.3. The syscall checks its
> + * arguments in this order:
> + *
> + * - a non-zero flags argument fails with ``EINVAL`` before anything else,
> + * including with the ``FD_FAILFS_ROOT`` sentinel and with an invalid fd
> + * - 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.
The order of check in kernel is never guaranteed and subject to change
at any time. We shouldn't rely on particular check being done first.
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [LTP] [PATCH STAGING v2 04/16] fchroot01: test fchroot() with a directory fd
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 04/16] fchroot01: test fchroot() with a directory fd Andrea Cervesato
@ 2026-08-20 14:13 ` Cyril Hrubis
2026-08-20 14:23 ` Andrea Cervesato via ltp
0 siblings, 1 reply; 26+ messages in thread
From: Cyril Hrubis @ 2026-08-20 14:13 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: Linux Test Project
Hi!
> +/*\
> + * 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 syscall runs in a forked child so that the root of the parent
> + * process, which the test framework needs for its cleanup, is left
> + * untouched.
I do not think that we need this. The process that runs the run()
function is forked from the library process in order for the test to be
isolated from the library.
As long as we do not have a custom cleanup() function that needs to run
outside of the jail we do not have to fork in the run().
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [LTP] [PATCH STAGING v2 06/16] fchroot03: test fchroot() permission checks
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 06/16] fchroot03: test fchroot() permission checks Andrea Cervesato
@ 2026-08-20 14:19 ` Cyril Hrubis
0 siblings, 0 replies; 26+ messages in thread
From: Cyril Hrubis @ 2026-08-20 14:19 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: Linux Test Project
Hi!
> 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.
Here as well, the order of the checks is subject to change.
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [LTP] [PATCH STAGING v2 04/16] fchroot01: test fchroot() with a directory fd
2026-08-20 14:13 ` Cyril Hrubis
@ 2026-08-20 14:23 ` Andrea Cervesato via ltp
2026-08-20 14:58 ` Cyril Hrubis
0 siblings, 1 reply; 26+ messages in thread
From: Andrea Cervesato via ltp @ 2026-08-20 14:23 UTC (permalink / raw)
To: Cyril Hrubis; +Cc: Linux Test Project
Hi Cyril,
> > + * The syscall runs in a forked child so that the root of the parent
> > + * process, which the test framework needs for its cleanup, is left
> > + * untouched.
>
> I do not think that we need this. The process that runs the run()
> function is forked from the library process in order for the test to be
> isolated from the library.
>
> As long as we do not have a custom cleanup() function that needs to run
> outside of the jail we do not have to fork in the run().
the fork() ensures that if fchroot() passes (instead of failing) at the next
iterations we don't have a dirty environment. This is done for all tests,
so iterations always starts from scratch.
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [LTP] [PATCH STAGING v2 07/16] fchroot04: test fchroot() into failfs as root
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 07/16] fchroot04: test fchroot() into failfs as root Andrea Cervesato
@ 2026-08-20 14:24 ` Cyril Hrubis
0 siblings, 0 replies; 26+ messages in thread
From: Cyril Hrubis @ 2026-08-20 14:24 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: Linux Test Project
Hi!
> +/*\
> + * 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.
Here as well no need for the fork().
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [LTP] [PATCH STAGING v2 08/16] fchroot05: test failfs root can not be referenced
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 08/16] fchroot05: test failfs root can not be referenced Andrea Cervesato
@ 2026-08-20 14:37 ` Cyril Hrubis
0 siblings, 0 replies; 26+ messages in thread
From: Cyril Hrubis @ 2026-08-20 14:37 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: Linux Test Project
Hi!
> +static void run(void)
> +{
> + if (SAFE_FORK())
> + return;
Here as well, this shouldn't be needed.
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [LTP] [PATCH STAGING v2 04/16] fchroot01: test fchroot() with a directory fd
2026-08-20 14:23 ` Andrea Cervesato via ltp
@ 2026-08-20 14:58 ` Cyril Hrubis
0 siblings, 0 replies; 26+ messages in thread
From: Cyril Hrubis @ 2026-08-20 14:58 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: Linux Test Project
Hi!
> > > + * The syscall runs in a forked child so that the root of the parent
> > > + * process, which the test framework needs for its cleanup, is left
> > > + * untouched.
> >
> > I do not think that we need this. The process that runs the run()
> > function is forked from the library process in order for the test to be
> > isolated from the library.
> >
> > As long as we do not have a custom cleanup() function that needs to run
> > outside of the jail we do not have to fork in the run().
>
> the fork() ensures that if fchroot() passes (instead of failing) at the next
> iterations we don't have a dirty environment. This is done for all tests,
> so iterations always starts from scratch.
Ah, right, that makes sense with -i 10. But then all the comments about
library cleanup are wrong.
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2026-08-20 14:58 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-20 7:44 [LTP] [PATCH v2 00/16] fchroot: add fchroot() testing suite Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH v2 01/16] syscalls: add v7.3 syscall numbers Andrea Cervesato
2026-08-20 8:34 ` [LTP] " linuxtestproject.agent
2026-08-20 8:37 ` Andrea Cervesato via ltp
2026-08-20 7:44 ` [LTP] [PATCH v2 02/16] syscalls: update outdated syscall entries Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 03/16] lapi: fallback fchroot() parameters Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 04/16] fchroot01: test fchroot() with a directory fd Andrea Cervesato
2026-08-20 14:13 ` Cyril Hrubis
2026-08-20 14:23 ` Andrea Cervesato via ltp
2026-08-20 14:58 ` Cyril Hrubis
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 05/16] fchroot02: test fchroot() invalid arguments Andrea Cervesato
2026-08-20 14:10 ` Cyril Hrubis
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 06/16] fchroot03: test fchroot() permission checks Andrea Cervesato
2026-08-20 14:19 ` Cyril Hrubis
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 07/16] fchroot04: test fchroot() into failfs as root Andrea Cervesato
2026-08-20 14:24 ` Cyril Hrubis
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 08/16] fchroot05: test failfs root can not be referenced Andrea Cervesato
2026-08-20 14:37 ` Cyril Hrubis
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 09/16] fchroot06: test path walks under failfs root Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 10/16] fchroot07: test execve blocked by " Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 11/16] fchroot08: test failfs root fork inheritance Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 12/16] fchroot09: test setns escape from failfs root Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 13/16] fchroot10: test failfs entry without no_new_privs Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 14/16] fchroot11: test failfs entry with no_new_privs Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 15/16] fchroot12: test failfs entry with shared fs_struct Andrea Cervesato
2026-08-20 7:44 ` [LTP] [PATCH STAGING v2 16/16] fchroot13: test failfs entry when chrooted Andrea Cervesato
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox