Re: [LTP] [PATCH v12 3/3] open16: allow restricted O_CREAT of FIFOs and regular files
Andrea Cervesato via ltp <[email protected]> Thu, 23 Jul 2026 12:46:50 +0000
| Newsgroups | it.linux.lists.ltp |
|---|---|
| Message-ID | <[email protected]> |
Hi Wei, > Add LTP coverage for kernel commit 30aba6656f61 (Linux 4.19), which > introduced protection against spoofing attacks via O_CREAT of FIFOs > and regular files in world-writable or group-writable sticky > directories. > > This commit adds test cases to verify these security restrictions > (Level 1 and Level 2 protections) for opening FIFOs and regular > files in world-writable or group-writable sticky directories when the > file is not owned by the opener. > > Signed-off-by: Wei Gao <[email protected]> > --- > runtest/syscalls | 1 + > testcases/kernel/syscalls/open/.gitignore | 1 + > testcases/kernel/syscalls/open/open16.c | 135 ++++++++++++++++++++++ > 3 files changed, 137 insertions(+) > create mode 100644 testcases/kernel/syscalls/open/open16.c > > diff --git a/runtest/syscalls b/runtest/syscalls > index a021c79da..4fd62efa8 100644 > --- a/runtest/syscalls > +++ b/runtest/syscalls > @@ -1008,6 +1008,7 @@ open12 open12 > open13 open13 > open14 open14 > open15 open15 > +open16 open16 > > openat01 openat01 > openat02 openat02 > diff --git a/testcases/kernel/syscalls/open/.gitignore b/testcases/kernel/syscalls/open/.gitignore > index af5997572..d2cacc02e 100644 > --- a/testcases/kernel/syscalls/open/.gitignore > +++ b/testcases/kernel/syscalls/open/.gitignore > @@ -13,3 +13,4 @@ > /open13 > /open14 > /open15 > +/open16 > diff --git a/testcases/kernel/syscalls/open/open16.c b/testcases/kernel/syscalls/open/open16.c > new file mode 100644 > index 000000000..c74601032 > --- /dev/null > +++ b/testcases/kernel/syscalls/open/open16.c > @@ -0,0 +1,135 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (c) 2026 Wei Gao <[email protected]> > + */ > + > +/*\ > + * Verify restricted opening (:manpage:`open(2)` and :manpage:`openat(2)`) of > + * FIFOs and regular files in sticky directories. This test covers the positive > + * case where access is allowed when protection is disabled (level 0), and the > + * negative cases where access is disallowed (EACCES) in world-writable (level > + * 1) or group-writable (level 2) sticky directories when the file is not owned > + * by the opener. > + * > + * This test requires root to modify /proc/sys/fs/protected_* sysctls and > + * to manage file ownership and permissions in sticky directories. > + */ > + > +#include <pwd.h> > +#include <stdlib.h> > +#include "tst_test.h" > +#include "tst_safe_file_at.h" > +#include "tst_uid.h" > + > +#define DIR "ltp_tmp_check1" > +#define TEST_FILE "test_file_1" > +#define TEST_FIFO "test_fifo_1" > +#define PROTECTED_REGULAR "/proc/sys/fs/protected_regular" > +#define PROTECTED_FIFOS "/proc/sys/fs/protected_fifos" > +#define TEST_FIFO_PATH DIR "/" TEST_FIFO > + > +static int dir_fd = -1; > +static uid_t uid1, uid2; > +static gid_t gid1; > + > +static struct tcase { > + char *level; > + int exp_errno; > + uid_t owner_uid; > + int use_nobody_gid; > + mode_t dir_mode; > +} tcases[] = { > + {"0", 0, 0, 0, 0777 | S_ISVTX}, > + {"1", EACCES, 0, 0, 0777 | S_ISVTX}, > + {"2", EACCES, -1, 1, 0030 | S_ISVTX}, > +}; > + > +static void verify_open(unsigned int n) > +{ > + struct tcase *tc = &tcases[n]; > + pid_t pid; > + > + SAFE_FILE_PRINTF(PROTECTED_REGULAR, "%s", tc->level); > + SAFE_FILE_PRINTF(PROTECTED_FIFOS, "%s", tc->level); > + > + if (tc->owner_uid != (uid_t)-1 || tc->use_nobody_gid) { > + gid_t gid = tc->use_nobody_gid ? gid1 : 0; > + > + SAFE_CHOWN(DIR, tc->owner_uid, gid); > + } > + > + if (tc->dir_mode) > + SAFE_CHMOD(DIR, tc->dir_mode); > + > + pid = SAFE_FORK(); > + if (!pid) { > + SAFE_SETGID(gid1); > + SAFE_SETUID(uid2); > + > + if (tc->exp_errno) { > + TST_EXP_FAIL2(openat(dir_fd, TEST_FILE, O_RDWR | O_CREAT, 0777), > + tc->exp_errno, "openat %s (Level %s)", TEST_FILE, tc->level); > + TST_EXP_FAIL2(open(TEST_FIFO_PATH, O_RDWR | O_CREAT, 0777), > + tc->exp_errno, "open %s (Level %s)", TEST_FIFO, tc->level); > + } else { > + int fd = TST_EXP_FD(openat(dir_fd, TEST_FILE, O_CREAT | O_RDWR, 0777)); > + > + if (TST_PASS) > + SAFE_CLOSE(fd); > + > + fd = TST_EXP_FD(open(TEST_FIFO_PATH, O_RDWR | O_CREAT, 0777)); > + if (TST_PASS) > + SAFE_CLOSE(fd); > + } > + > + exit(0); > + } > + > + SAFE_WAITPID(pid, NULL, 0); not needed, we have tst_reap_children(). > +} > + > +static void setup(void) > +{ > + struct passwd *pw; > + > + pw = SAFE_GETPWNAM("nobody"); > + uid1 = pw->pw_uid; > + gid1 = pw->pw_gid; > + uid2 = tst_get_free_uid(uid1); > + > + umask(0); > + SAFE_MKDIR(DIR, 0777 | S_ISVTX); > + dir_fd = SAFE_OPEN(DIR, O_DIRECTORY); > + > + int fd = SAFE_OPENAT(dir_fd, TEST_FILE, O_CREAT | O_RDWR, 0777); > + > + SAFE_CLOSE(fd); > + SAFE_MKFIFO(TEST_FIFO_PATH, 0777); > + SAFE_CHOWN(TEST_FIFO_PATH, uid1, gid1); > + SAFE_CHOWN(DIR "/" TEST_FILE, uid1, gid1); > +} > + > +static void cleanup(void) > +{ > + if (dir_fd != -1) > + SAFE_CLOSE(dir_fd); > +} > + > +static struct tst_test test = { > + .setup = setup, > + .cleanup = cleanup, > + .needs_root = 1, > + .tcnt = ARRAY_SIZE(tcases), > + .test = verify_open, > + .needs_tmpdir = 1, > + .forks_child = 1, > + .save_restore = (const struct tst_path_val[]) { > + {PROTECTED_REGULAR, NULL, TST_SR_TCONF}, > + {PROTECTED_FIFOS, NULL, TST_SR_TCONF}, > + {} > + }, > + .tags = (const struct tst_tag[]) { > + {"linux-git", "30aba6656f61"}, > + {} > + } > +}; > -- > 2.54.0 > -- Andrea Cervesato SUSE QE Automation Engineer Linux [email protected] -- Mailing list info: https://lists.linux.it/listinfo/ltp