13ac7ea91SChristian Brauner // SPDX-License-Identifier: GPL-2.0 23ac7ea91SChristian Brauner /* 33ac7ea91SChristian Brauner * Copyright (C) 2026 Christian Brauner <brauner@kernel.org> 43ac7ea91SChristian Brauner * 53ac7ea91SChristian Brauner * Test for FSMOUNT_NAMESPACE flag. 63ac7ea91SChristian Brauner * 73ac7ea91SChristian Brauner * Test that fsmount() with FSMOUNT_NAMESPACE creates a new mount 83ac7ea91SChristian Brauner * namespace containing the specified mount. 93ac7ea91SChristian Brauner */ 103ac7ea91SChristian Brauner #define _GNU_SOURCE 113ac7ea91SChristian Brauner 123ac7ea91SChristian Brauner #include <errno.h> 133ac7ea91SChristian Brauner #include <fcntl.h> 143ac7ea91SChristian Brauner #include <limits.h> 153ac7ea91SChristian Brauner #include <linux/nsfs.h> 163ac7ea91SChristian Brauner #include <sched.h> 173ac7ea91SChristian Brauner #include <stdio.h> 183ac7ea91SChristian Brauner #include <stdlib.h> 193ac7ea91SChristian Brauner #include <string.h> 203ac7ea91SChristian Brauner #include <sys/ioctl.h> 213ac7ea91SChristian Brauner #include <sys/mount.h> 223ac7ea91SChristian Brauner #include <sys/stat.h> 233ac7ea91SChristian Brauner #include <sys/wait.h> 243ac7ea91SChristian Brauner #include <unistd.h> 253ac7ea91SChristian Brauner 263ac7ea91SChristian Brauner #include "../wrappers.h" 273ac7ea91SChristian Brauner #include "../statmount/statmount.h" 283ac7ea91SChristian Brauner #include "../utils.h" 293ac7ea91SChristian Brauner #include "../../kselftest_harness.h" 303ac7ea91SChristian Brauner 313ac7ea91SChristian Brauner #ifndef FSMOUNT_NAMESPACE 323ac7ea91SChristian Brauner #define FSMOUNT_NAMESPACE 0x00000002 333ac7ea91SChristian Brauner #endif 343ac7ea91SChristian Brauner 353ac7ea91SChristian Brauner #ifndef FSMOUNT_CLOEXEC 363ac7ea91SChristian Brauner #define FSMOUNT_CLOEXEC 0x00000001 373ac7ea91SChristian Brauner #endif 383ac7ea91SChristian Brauner 393ac7ea91SChristian Brauner #ifndef FSCONFIG_CMD_CREATE 403ac7ea91SChristian Brauner #define FSCONFIG_CMD_CREATE 6 413ac7ea91SChristian Brauner #endif 423ac7ea91SChristian Brauner 433ac7ea91SChristian Brauner static int get_mnt_ns_id(int fd, uint64_t *mnt_ns_id) 443ac7ea91SChristian Brauner { 453ac7ea91SChristian Brauner if (ioctl(fd, NS_GET_MNTNS_ID, mnt_ns_id) < 0) 463ac7ea91SChristian Brauner return -errno; 473ac7ea91SChristian Brauner return 0; 483ac7ea91SChristian Brauner } 493ac7ea91SChristian Brauner 503ac7ea91SChristian Brauner static int get_mnt_ns_id_from_path(const char *path, uint64_t *mnt_ns_id) 513ac7ea91SChristian Brauner { 523ac7ea91SChristian Brauner int fd, ret; 533ac7ea91SChristian Brauner 543ac7ea91SChristian Brauner fd = open(path, O_RDONLY); 553ac7ea91SChristian Brauner if (fd < 0) 563ac7ea91SChristian Brauner return -errno; 573ac7ea91SChristian Brauner 583ac7ea91SChristian Brauner ret = get_mnt_ns_id(fd, mnt_ns_id); 593ac7ea91SChristian Brauner close(fd); 603ac7ea91SChristian Brauner return ret; 613ac7ea91SChristian Brauner } 623ac7ea91SChristian Brauner 633ac7ea91SChristian Brauner static void log_mount(struct __test_metadata *_metadata, struct statmount *sm) 643ac7ea91SChristian Brauner { 653ac7ea91SChristian Brauner const char *fs_type = ""; 663ac7ea91SChristian Brauner const char *mnt_root = ""; 673ac7ea91SChristian Brauner const char *mnt_point = ""; 683ac7ea91SChristian Brauner 693ac7ea91SChristian Brauner if (sm->mask & STATMOUNT_FS_TYPE) 703ac7ea91SChristian Brauner fs_type = sm->str + sm->fs_type; 713ac7ea91SChristian Brauner if (sm->mask & STATMOUNT_MNT_ROOT) 723ac7ea91SChristian Brauner mnt_root = sm->str + sm->mnt_root; 733ac7ea91SChristian Brauner if (sm->mask & STATMOUNT_MNT_POINT) 743ac7ea91SChristian Brauner mnt_point = sm->str + sm->mnt_point; 753ac7ea91SChristian Brauner 763ac7ea91SChristian Brauner TH_LOG(" mnt_id: %llu, parent_id: %llu, fs_type: %s, root: %s, point: %s", 773ac7ea91SChristian Brauner (unsigned long long)sm->mnt_id, 783ac7ea91SChristian Brauner (unsigned long long)sm->mnt_parent_id, 793ac7ea91SChristian Brauner fs_type, mnt_root, mnt_point); 803ac7ea91SChristian Brauner } 813ac7ea91SChristian Brauner 823ac7ea91SChristian Brauner static void dump_mounts(struct __test_metadata *_metadata, uint64_t mnt_ns_id) 833ac7ea91SChristian Brauner { 843ac7ea91SChristian Brauner uint64_t list[256]; 853ac7ea91SChristian Brauner ssize_t nr_mounts; 863ac7ea91SChristian Brauner 873ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, mnt_ns_id, 0, list, 256, 0); 883ac7ea91SChristian Brauner if (nr_mounts < 0) { 893ac7ea91SChristian Brauner TH_LOG("listmount failed: %s", strerror(errno)); 903ac7ea91SChristian Brauner return; 913ac7ea91SChristian Brauner } 923ac7ea91SChristian Brauner 933ac7ea91SChristian Brauner TH_LOG("Mount namespace %llu contains %zd mount(s):", 943ac7ea91SChristian Brauner (unsigned long long)mnt_ns_id, nr_mounts); 953ac7ea91SChristian Brauner 963ac7ea91SChristian Brauner for (ssize_t i = 0; i < nr_mounts; i++) { 973ac7ea91SChristian Brauner struct statmount *sm; 983ac7ea91SChristian Brauner 993ac7ea91SChristian Brauner sm = statmount_alloc(list[i], mnt_ns_id, 1003ac7ea91SChristian Brauner STATMOUNT_MNT_BASIC | 1013ac7ea91SChristian Brauner STATMOUNT_FS_TYPE | 1023ac7ea91SChristian Brauner STATMOUNT_MNT_ROOT | 1033ac7ea91SChristian Brauner STATMOUNT_MNT_POINT, 0); 1043ac7ea91SChristian Brauner if (!sm) { 1053ac7ea91SChristian Brauner TH_LOG(" [%zd] mnt_id %llu: statmount failed: %s", 1063ac7ea91SChristian Brauner i, (unsigned long long)list[i], strerror(errno)); 1073ac7ea91SChristian Brauner continue; 1083ac7ea91SChristian Brauner } 1093ac7ea91SChristian Brauner 1103ac7ea91SChristian Brauner log_mount(_metadata, sm); 1113ac7ea91SChristian Brauner free(sm); 1123ac7ea91SChristian Brauner } 1133ac7ea91SChristian Brauner } 1143ac7ea91SChristian Brauner 1153ac7ea91SChristian Brauner static int create_tmpfs_fd(void) 1163ac7ea91SChristian Brauner { 1173ac7ea91SChristian Brauner int fs_fd, ret; 1183ac7ea91SChristian Brauner 1193ac7ea91SChristian Brauner fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 1203ac7ea91SChristian Brauner if (fs_fd < 0) 1213ac7ea91SChristian Brauner return -errno; 1223ac7ea91SChristian Brauner 1233ac7ea91SChristian Brauner ret = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); 1243ac7ea91SChristian Brauner if (ret < 0) { 1253ac7ea91SChristian Brauner close(fs_fd); 1263ac7ea91SChristian Brauner return -errno; 1273ac7ea91SChristian Brauner } 1283ac7ea91SChristian Brauner 1293ac7ea91SChristian Brauner return fs_fd; 1303ac7ea91SChristian Brauner } 1313ac7ea91SChristian Brauner 1323ac7ea91SChristian Brauner FIXTURE(fsmount_ns) 1333ac7ea91SChristian Brauner { 1343ac7ea91SChristian Brauner int fd; 1353ac7ea91SChristian Brauner int fs_fd; 1363ac7ea91SChristian Brauner uint64_t current_ns_id; 1373ac7ea91SChristian Brauner }; 1383ac7ea91SChristian Brauner 1393ac7ea91SChristian Brauner FIXTURE_VARIANT(fsmount_ns) 1403ac7ea91SChristian Brauner { 1413ac7ea91SChristian Brauner const char *fstype; 1423ac7ea91SChristian Brauner unsigned int flags; 1433ac7ea91SChristian Brauner bool expect_success; 1443ac7ea91SChristian Brauner bool expect_different_ns; 1453ac7ea91SChristian Brauner int min_mounts; 1463ac7ea91SChristian Brauner }; 1473ac7ea91SChristian Brauner 1483ac7ea91SChristian Brauner FIXTURE_VARIANT_ADD(fsmount_ns, basic_tmpfs) 1493ac7ea91SChristian Brauner { 1503ac7ea91SChristian Brauner .fstype = "tmpfs", 1513ac7ea91SChristian Brauner .flags = FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 1523ac7ea91SChristian Brauner .expect_success = true, 1533ac7ea91SChristian Brauner .expect_different_ns = true, 1543ac7ea91SChristian Brauner .min_mounts = 1, 1553ac7ea91SChristian Brauner }; 1563ac7ea91SChristian Brauner 1573ac7ea91SChristian Brauner FIXTURE_VARIANT_ADD(fsmount_ns, cloexec_only) 1583ac7ea91SChristian Brauner { 1593ac7ea91SChristian Brauner .fstype = "tmpfs", 1603ac7ea91SChristian Brauner .flags = FSMOUNT_CLOEXEC, 1613ac7ea91SChristian Brauner .expect_success = true, 1623ac7ea91SChristian Brauner .expect_different_ns = false, 1633ac7ea91SChristian Brauner .min_mounts = 1, 1643ac7ea91SChristian Brauner }; 1653ac7ea91SChristian Brauner 1663ac7ea91SChristian Brauner FIXTURE_VARIANT_ADD(fsmount_ns, namespace_only) 1673ac7ea91SChristian Brauner { 1683ac7ea91SChristian Brauner .fstype = "tmpfs", 1693ac7ea91SChristian Brauner .flags = FSMOUNT_NAMESPACE, 1703ac7ea91SChristian Brauner .expect_success = true, 1713ac7ea91SChristian Brauner .expect_different_ns = true, 1723ac7ea91SChristian Brauner .min_mounts = 1, 1733ac7ea91SChristian Brauner }; 1743ac7ea91SChristian Brauner 1753ac7ea91SChristian Brauner FIXTURE_SETUP(fsmount_ns) 1763ac7ea91SChristian Brauner { 1773ac7ea91SChristian Brauner int ret; 1783ac7ea91SChristian Brauner 1793ac7ea91SChristian Brauner self->fd = -1; 1803ac7ea91SChristian Brauner self->fs_fd = -1; 1813ac7ea91SChristian Brauner 1823ac7ea91SChristian Brauner /* Check if fsopen syscall is supported */ 1833ac7ea91SChristian Brauner ret = sys_fsopen("tmpfs", 0); 1843ac7ea91SChristian Brauner if (ret == -1 && errno == ENOSYS) 1853ac7ea91SChristian Brauner SKIP(return, "fsopen() syscall not supported"); 1863ac7ea91SChristian Brauner if (ret >= 0) 1873ac7ea91SChristian Brauner close(ret); 1883ac7ea91SChristian Brauner 1893ac7ea91SChristian Brauner /* Check if statmount/listmount are supported */ 1903ac7ea91SChristian Brauner ret = statmount(0, 0, 0, 0, NULL, 0, 0); 1913ac7ea91SChristian Brauner if (ret == -1 && errno == ENOSYS) 1923ac7ea91SChristian Brauner SKIP(return, "statmount() syscall not supported"); 1933ac7ea91SChristian Brauner 1943ac7ea91SChristian Brauner /* Get current mount namespace ID for comparison */ 1953ac7ea91SChristian Brauner ret = get_mnt_ns_id_from_path("/proc/self/ns/mnt", &self->current_ns_id); 1963ac7ea91SChristian Brauner if (ret < 0) 1973ac7ea91SChristian Brauner SKIP(return, "Failed to get current mount namespace ID"); 1983ac7ea91SChristian Brauner } 1993ac7ea91SChristian Brauner 2003ac7ea91SChristian Brauner FIXTURE_TEARDOWN(fsmount_ns) 2013ac7ea91SChristian Brauner { 2023ac7ea91SChristian Brauner if (self->fd >= 0) 2033ac7ea91SChristian Brauner close(self->fd); 2043ac7ea91SChristian Brauner if (self->fs_fd >= 0) 2053ac7ea91SChristian Brauner close(self->fs_fd); 2063ac7ea91SChristian Brauner } 2073ac7ea91SChristian Brauner 2083ac7ea91SChristian Brauner TEST_F(fsmount_ns, create_namespace) 2093ac7ea91SChristian Brauner { 2103ac7ea91SChristian Brauner uint64_t new_ns_id; 2113ac7ea91SChristian Brauner uint64_t list[256]; 2123ac7ea91SChristian Brauner ssize_t nr_mounts; 2133ac7ea91SChristian Brauner int ret; 2143ac7ea91SChristian Brauner 2153ac7ea91SChristian Brauner self->fs_fd = create_tmpfs_fd(); 2163ac7ea91SChristian Brauner ASSERT_GE(self->fs_fd, 0); 2173ac7ea91SChristian Brauner 2183ac7ea91SChristian Brauner self->fd = sys_fsmount(self->fs_fd, variant->flags, 0); 2193ac7ea91SChristian Brauner 2203ac7ea91SChristian Brauner if (!variant->expect_success) { 2213ac7ea91SChristian Brauner ASSERT_LT(self->fd, 0); 2223ac7ea91SChristian Brauner return; 2233ac7ea91SChristian Brauner } 2243ac7ea91SChristian Brauner 2253ac7ea91SChristian Brauner if (self->fd < 0 && errno == EINVAL) 2263ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 2273ac7ea91SChristian Brauner 2283ac7ea91SChristian Brauner ASSERT_GE(self->fd, 0); 2293ac7ea91SChristian Brauner 2303ac7ea91SChristian Brauner if (variant->expect_different_ns) { 2313ac7ea91SChristian Brauner /* Verify we can get the namespace ID from the fd */ 2323ac7ea91SChristian Brauner ret = get_mnt_ns_id(self->fd, &new_ns_id); 2333ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 2343ac7ea91SChristian Brauner 2353ac7ea91SChristian Brauner /* Verify it's a different namespace */ 2363ac7ea91SChristian Brauner ASSERT_NE(new_ns_id, self->current_ns_id); 2373ac7ea91SChristian Brauner 2383ac7ea91SChristian Brauner /* List mounts in the new namespace */ 2393ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 2403ac7ea91SChristian Brauner ASSERT_GE(nr_mounts, 0) { 2413ac7ea91SChristian Brauner TH_LOG("%m - listmount failed"); 2423ac7ea91SChristian Brauner } 2433ac7ea91SChristian Brauner 2443ac7ea91SChristian Brauner /* Verify minimum expected mounts */ 2453ac7ea91SChristian Brauner ASSERT_GE(nr_mounts, variant->min_mounts); 2463ac7ea91SChristian Brauner TH_LOG("Namespace contains %zd mounts", nr_mounts); 2473ac7ea91SChristian Brauner } 2483ac7ea91SChristian Brauner } 2493ac7ea91SChristian Brauner 2503ac7ea91SChristian Brauner TEST_F(fsmount_ns, setns_into_namespace) 2513ac7ea91SChristian Brauner { 2523ac7ea91SChristian Brauner uint64_t new_ns_id; 2533ac7ea91SChristian Brauner pid_t pid; 2543ac7ea91SChristian Brauner int status; 2553ac7ea91SChristian Brauner int ret; 2563ac7ea91SChristian Brauner 2573ac7ea91SChristian Brauner /* Only test with FSMOUNT_NAMESPACE flag */ 2583ac7ea91SChristian Brauner if (!(variant->flags & FSMOUNT_NAMESPACE)) 2593ac7ea91SChristian Brauner SKIP(return, "setns test only for FSMOUNT_NAMESPACE case"); 2603ac7ea91SChristian Brauner 2613ac7ea91SChristian Brauner self->fs_fd = create_tmpfs_fd(); 2623ac7ea91SChristian Brauner ASSERT_GE(self->fs_fd, 0); 2633ac7ea91SChristian Brauner 2643ac7ea91SChristian Brauner self->fd = sys_fsmount(self->fs_fd, variant->flags, 0); 2653ac7ea91SChristian Brauner if (self->fd < 0 && errno == EINVAL) 2663ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 2673ac7ea91SChristian Brauner 2683ac7ea91SChristian Brauner ASSERT_GE(self->fd, 0); 2693ac7ea91SChristian Brauner 2703ac7ea91SChristian Brauner /* Get namespace ID and dump all mounts */ 2713ac7ea91SChristian Brauner ret = get_mnt_ns_id(self->fd, &new_ns_id); 2723ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 2733ac7ea91SChristian Brauner 2743ac7ea91SChristian Brauner dump_mounts(_metadata, new_ns_id); 2753ac7ea91SChristian Brauner 2763ac7ea91SChristian Brauner pid = fork(); 2773ac7ea91SChristian Brauner ASSERT_GE(pid, 0); 2783ac7ea91SChristian Brauner 2793ac7ea91SChristian Brauner if (pid == 0) { 2803ac7ea91SChristian Brauner /* Child: try to enter the namespace */ 2813ac7ea91SChristian Brauner if (setns(self->fd, CLONE_NEWNS) < 0) 2823ac7ea91SChristian Brauner _exit(1); 2833ac7ea91SChristian Brauner _exit(0); 2843ac7ea91SChristian Brauner } 2853ac7ea91SChristian Brauner 2863ac7ea91SChristian Brauner ASSERT_EQ(waitpid(pid, &status, 0), pid); 2873ac7ea91SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 2883ac7ea91SChristian Brauner ASSERT_EQ(WEXITSTATUS(status), 0); 2893ac7ea91SChristian Brauner } 2903ac7ea91SChristian Brauner 2913ac7ea91SChristian Brauner TEST_F(fsmount_ns, verify_mount_properties) 2923ac7ea91SChristian Brauner { 2933ac7ea91SChristian Brauner struct statmount sm; 2943ac7ea91SChristian Brauner uint64_t new_ns_id; 2953ac7ea91SChristian Brauner uint64_t list[256]; 2963ac7ea91SChristian Brauner ssize_t nr_mounts; 2973ac7ea91SChristian Brauner int ret; 2983ac7ea91SChristian Brauner 2993ac7ea91SChristian Brauner /* Only test with basic FSMOUNT_NAMESPACE flags */ 3003ac7ea91SChristian Brauner if (variant->flags != (FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC)) 3013ac7ea91SChristian Brauner SKIP(return, "mount properties test only for basic case"); 3023ac7ea91SChristian Brauner 3033ac7ea91SChristian Brauner self->fs_fd = create_tmpfs_fd(); 3043ac7ea91SChristian Brauner ASSERT_GE(self->fs_fd, 0); 3053ac7ea91SChristian Brauner 3063ac7ea91SChristian Brauner self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 3073ac7ea91SChristian Brauner if (self->fd < 0 && errno == EINVAL) 3083ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 3093ac7ea91SChristian Brauner 3103ac7ea91SChristian Brauner ASSERT_GE(self->fd, 0); 3113ac7ea91SChristian Brauner 3123ac7ea91SChristian Brauner ret = get_mnt_ns_id(self->fd, &new_ns_id); 3133ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 3143ac7ea91SChristian Brauner 3153ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 3163ac7ea91SChristian Brauner ASSERT_GE(nr_mounts, 1); 3173ac7ea91SChristian Brauner 3183ac7ea91SChristian Brauner /* Get info about the root mount */ 3193ac7ea91SChristian Brauner ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 3203ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 3213ac7ea91SChristian Brauner 3223ac7ea91SChristian Brauner TH_LOG("Root mount id: %llu, parent: %llu", 3233ac7ea91SChristian Brauner (unsigned long long)sm.mnt_id, 3243ac7ea91SChristian Brauner (unsigned long long)sm.mnt_parent_id); 3253ac7ea91SChristian Brauner } 3263ac7ea91SChristian Brauner 3273ac7ea91SChristian Brauner TEST_F(fsmount_ns, verify_tmpfs_type) 3283ac7ea91SChristian Brauner { 3293ac7ea91SChristian Brauner struct statmount *sm; 3303ac7ea91SChristian Brauner uint64_t new_ns_id; 3313ac7ea91SChristian Brauner uint64_t list[256]; 3323ac7ea91SChristian Brauner ssize_t nr_mounts; 3333ac7ea91SChristian Brauner const char *fs_type; 3343ac7ea91SChristian Brauner int ret; 3353ac7ea91SChristian Brauner 3363ac7ea91SChristian Brauner /* Only test with basic FSMOUNT_NAMESPACE flags */ 3373ac7ea91SChristian Brauner if (variant->flags != (FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC)) 3383ac7ea91SChristian Brauner SKIP(return, "fs type test only for basic case"); 3393ac7ea91SChristian Brauner 3403ac7ea91SChristian Brauner self->fs_fd = create_tmpfs_fd(); 3413ac7ea91SChristian Brauner ASSERT_GE(self->fs_fd, 0); 3423ac7ea91SChristian Brauner 3433ac7ea91SChristian Brauner self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 3443ac7ea91SChristian Brauner if (self->fd < 0 && errno == EINVAL) 3453ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 3463ac7ea91SChristian Brauner 3473ac7ea91SChristian Brauner ASSERT_GE(self->fd, 0); 3483ac7ea91SChristian Brauner 3493ac7ea91SChristian Brauner ret = get_mnt_ns_id(self->fd, &new_ns_id); 3503ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 3513ac7ea91SChristian Brauner 3523ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 3533ac7ea91SChristian Brauner ASSERT_GE(nr_mounts, 1); 3543ac7ea91SChristian Brauner 3553ac7ea91SChristian Brauner sm = statmount_alloc(list[0], new_ns_id, STATMOUNT_FS_TYPE, 0); 3563ac7ea91SChristian Brauner ASSERT_NE(sm, NULL); 3573ac7ea91SChristian Brauner 3583ac7ea91SChristian Brauner fs_type = sm->str + sm->fs_type; 3593ac7ea91SChristian Brauner ASSERT_STREQ(fs_type, "tmpfs"); 3603ac7ea91SChristian Brauner 3613ac7ea91SChristian Brauner free(sm); 3623ac7ea91SChristian Brauner } 3633ac7ea91SChristian Brauner 3643ac7ea91SChristian Brauner FIXTURE(fsmount_ns_caps) 3653ac7ea91SChristian Brauner { 3663ac7ea91SChristian Brauner bool has_caps; 3673ac7ea91SChristian Brauner }; 3683ac7ea91SChristian Brauner 3693ac7ea91SChristian Brauner FIXTURE_SETUP(fsmount_ns_caps) 3703ac7ea91SChristian Brauner { 3713ac7ea91SChristian Brauner int ret; 3723ac7ea91SChristian Brauner 3733ac7ea91SChristian Brauner /* Check if fsopen syscall is supported */ 3743ac7ea91SChristian Brauner ret = sys_fsopen("tmpfs", 0); 3753ac7ea91SChristian Brauner if (ret == -1 && errno == ENOSYS) 3763ac7ea91SChristian Brauner SKIP(return, "fsopen() syscall not supported"); 3773ac7ea91SChristian Brauner if (ret >= 0) 3783ac7ea91SChristian Brauner close(ret); 3793ac7ea91SChristian Brauner 3803ac7ea91SChristian Brauner self->has_caps = (geteuid() == 0); 3813ac7ea91SChristian Brauner } 3823ac7ea91SChristian Brauner 3833ac7ea91SChristian Brauner FIXTURE_TEARDOWN(fsmount_ns_caps) 3843ac7ea91SChristian Brauner { 3853ac7ea91SChristian Brauner } 3863ac7ea91SChristian Brauner 3873ac7ea91SChristian Brauner TEST_F(fsmount_ns_caps, requires_cap_sys_admin) 3883ac7ea91SChristian Brauner { 3893ac7ea91SChristian Brauner pid_t pid; 3903ac7ea91SChristian Brauner int status; 391*660c0940SChristian Brauner int fs_fd; 392*660c0940SChristian Brauner 393*660c0940SChristian Brauner /* 394*660c0940SChristian Brauner * Prepare the configured filesystem fd as root before forking. 395*660c0940SChristian Brauner * fsopen() requires CAP_SYS_ADMIN in the mount namespace's 396*660c0940SChristian Brauner * user_ns, which won't be available after enter_userns(). 397*660c0940SChristian Brauner */ 398*660c0940SChristian Brauner fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 399*660c0940SChristian Brauner ASSERT_GE(fs_fd, 0); 400*660c0940SChristian Brauner 401*660c0940SChristian Brauner ASSERT_EQ(sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0); 4023ac7ea91SChristian Brauner 4033ac7ea91SChristian Brauner pid = fork(); 4043ac7ea91SChristian Brauner ASSERT_GE(pid, 0); 4053ac7ea91SChristian Brauner 4063ac7ea91SChristian Brauner if (pid == 0) { 407*660c0940SChristian Brauner int fd; 4083ac7ea91SChristian Brauner 4093ac7ea91SChristian Brauner /* Child: drop privileges using utils.h helper */ 4103ac7ea91SChristian Brauner if (enter_userns() != 0) 4113ac7ea91SChristian Brauner _exit(2); 4123ac7ea91SChristian Brauner 4133ac7ea91SChristian Brauner /* Drop all caps using utils.h helper */ 4143ac7ea91SChristian Brauner if (caps_down() == 0) 4153ac7ea91SChristian Brauner _exit(3); 4163ac7ea91SChristian Brauner 4173ac7ea91SChristian Brauner fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 4183ac7ea91SChristian Brauner close(fs_fd); 4193ac7ea91SChristian Brauner 4203ac7ea91SChristian Brauner if (fd >= 0) { 4213ac7ea91SChristian Brauner close(fd); 4223ac7ea91SChristian Brauner /* Should have failed without caps */ 4233ac7ea91SChristian Brauner _exit(1); 4243ac7ea91SChristian Brauner } 4253ac7ea91SChristian Brauner 4263ac7ea91SChristian Brauner if (errno == EPERM) 4273ac7ea91SChristian Brauner _exit(0); 4283ac7ea91SChristian Brauner 4293ac7ea91SChristian Brauner /* EINVAL means FSMOUNT_NAMESPACE not supported */ 4303ac7ea91SChristian Brauner if (errno == EINVAL) 4313ac7ea91SChristian Brauner _exit(6); 4323ac7ea91SChristian Brauner 4333ac7ea91SChristian Brauner /* Unexpected error */ 4343ac7ea91SChristian Brauner _exit(7); 4353ac7ea91SChristian Brauner } 4363ac7ea91SChristian Brauner 437*660c0940SChristian Brauner close(fs_fd); 4383ac7ea91SChristian Brauner ASSERT_EQ(waitpid(pid, &status, 0), pid); 4393ac7ea91SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 4403ac7ea91SChristian Brauner 4413ac7ea91SChristian Brauner switch (WEXITSTATUS(status)) { 4423ac7ea91SChristian Brauner case 0: 4433ac7ea91SChristian Brauner /* Expected: EPERM without caps */ 4443ac7ea91SChristian Brauner break; 4453ac7ea91SChristian Brauner case 1: 4463ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("FSMOUNT_NAMESPACE succeeded without caps"); 4473ac7ea91SChristian Brauner break; 4483ac7ea91SChristian Brauner case 2: 4493ac7ea91SChristian Brauner SKIP(return, "enter_userns failed"); 4503ac7ea91SChristian Brauner break; 4513ac7ea91SChristian Brauner case 3: 4523ac7ea91SChristian Brauner SKIP(return, "caps_down failed"); 4533ac7ea91SChristian Brauner break; 4543ac7ea91SChristian Brauner case 6: 4553ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 4563ac7ea91SChristian Brauner break; 4573ac7ea91SChristian Brauner default: 4583ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)", 4593ac7ea91SChristian Brauner WEXITSTATUS(status)); 4603ac7ea91SChristian Brauner break; 4613ac7ea91SChristian Brauner } 4623ac7ea91SChristian Brauner } 4633ac7ea91SChristian Brauner 4643ac7ea91SChristian Brauner FIXTURE(fsmount_ns_userns) 4653ac7ea91SChristian Brauner { 4663ac7ea91SChristian Brauner int fd; 4673ac7ea91SChristian Brauner int fs_fd; 4683ac7ea91SChristian Brauner }; 4693ac7ea91SChristian Brauner 4703ac7ea91SChristian Brauner FIXTURE_SETUP(fsmount_ns_userns) 4713ac7ea91SChristian Brauner { 4723ac7ea91SChristian Brauner int ret; 4733ac7ea91SChristian Brauner 4743ac7ea91SChristian Brauner self->fd = -1; 4753ac7ea91SChristian Brauner self->fs_fd = -1; 4763ac7ea91SChristian Brauner 4773ac7ea91SChristian Brauner /* Check if fsopen syscall is supported */ 4783ac7ea91SChristian Brauner ret = sys_fsopen("tmpfs", 0); 4793ac7ea91SChristian Brauner if (ret == -1 && errno == ENOSYS) 4803ac7ea91SChristian Brauner SKIP(return, "fsopen() syscall not supported"); 4813ac7ea91SChristian Brauner if (ret >= 0) 4823ac7ea91SChristian Brauner close(ret); 4833ac7ea91SChristian Brauner 4843ac7ea91SChristian Brauner /* Check if statmount/listmount are supported */ 4853ac7ea91SChristian Brauner ret = statmount(0, 0, 0, 0, NULL, 0, 0); 4863ac7ea91SChristian Brauner if (ret == -1 && errno == ENOSYS) 4873ac7ea91SChristian Brauner SKIP(return, "statmount() syscall not supported"); 4883ac7ea91SChristian Brauner } 4893ac7ea91SChristian Brauner 4903ac7ea91SChristian Brauner FIXTURE_TEARDOWN(fsmount_ns_userns) 4913ac7ea91SChristian Brauner { 4923ac7ea91SChristian Brauner if (self->fd >= 0) 4933ac7ea91SChristian Brauner close(self->fd); 4943ac7ea91SChristian Brauner if (self->fs_fd >= 0) 4953ac7ea91SChristian Brauner close(self->fs_fd); 4963ac7ea91SChristian Brauner } 4973ac7ea91SChristian Brauner 4983ac7ea91SChristian Brauner TEST_F(fsmount_ns_userns, create_in_userns) 4993ac7ea91SChristian Brauner { 5003ac7ea91SChristian Brauner pid_t pid; 5013ac7ea91SChristian Brauner int status; 5023ac7ea91SChristian Brauner 5033ac7ea91SChristian Brauner pid = fork(); 5043ac7ea91SChristian Brauner ASSERT_GE(pid, 0); 5053ac7ea91SChristian Brauner 5063ac7ea91SChristian Brauner if (pid == 0) { 5073ac7ea91SChristian Brauner uint64_t new_ns_id; 5083ac7ea91SChristian Brauner uint64_t list[256]; 5093ac7ea91SChristian Brauner ssize_t nr_mounts; 5103ac7ea91SChristian Brauner int fs_fd, fd; 5113ac7ea91SChristian Brauner 5123ac7ea91SChristian Brauner /* Create new user namespace (also creates mount namespace) */ 5133ac7ea91SChristian Brauner if (setup_userns() != 0) 5143ac7ea91SChristian Brauner _exit(2); 5153ac7ea91SChristian Brauner 5163ac7ea91SChristian Brauner /* Now we have CAP_SYS_ADMIN in the user namespace */ 5173ac7ea91SChristian Brauner fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 5183ac7ea91SChristian Brauner if (fs_fd < 0) 5193ac7ea91SChristian Brauner _exit(3); 5203ac7ea91SChristian Brauner 5213ac7ea91SChristian Brauner if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) { 5223ac7ea91SChristian Brauner close(fs_fd); 5233ac7ea91SChristian Brauner _exit(4); 5243ac7ea91SChristian Brauner } 5253ac7ea91SChristian Brauner 5263ac7ea91SChristian Brauner fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 5273ac7ea91SChristian Brauner close(fs_fd); 5283ac7ea91SChristian Brauner 5293ac7ea91SChristian Brauner if (fd < 0) { 5303ac7ea91SChristian Brauner if (errno == EINVAL) 5313ac7ea91SChristian Brauner _exit(6); /* FSMOUNT_NAMESPACE not supported */ 5323ac7ea91SChristian Brauner _exit(1); 5333ac7ea91SChristian Brauner } 5343ac7ea91SChristian Brauner 5353ac7ea91SChristian Brauner /* Verify we can get the namespace ID */ 5363ac7ea91SChristian Brauner if (get_mnt_ns_id(fd, &new_ns_id) != 0) 5373ac7ea91SChristian Brauner _exit(7); 5383ac7ea91SChristian Brauner 5393ac7ea91SChristian Brauner /* Verify we can list mounts in the new namespace */ 5403ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 5413ac7ea91SChristian Brauner if (nr_mounts < 0) 5423ac7ea91SChristian Brauner _exit(8); 5433ac7ea91SChristian Brauner 5443ac7ea91SChristian Brauner /* Should have at least 1 mount (the tmpfs) */ 5453ac7ea91SChristian Brauner if (nr_mounts < 1) 5463ac7ea91SChristian Brauner _exit(9); 5473ac7ea91SChristian Brauner 5483ac7ea91SChristian Brauner close(fd); 5493ac7ea91SChristian Brauner _exit(0); 5503ac7ea91SChristian Brauner } 5513ac7ea91SChristian Brauner 5523ac7ea91SChristian Brauner ASSERT_EQ(waitpid(pid, &status, 0), pid); 5533ac7ea91SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 5543ac7ea91SChristian Brauner 5553ac7ea91SChristian Brauner switch (WEXITSTATUS(status)) { 5563ac7ea91SChristian Brauner case 0: 5573ac7ea91SChristian Brauner /* Success */ 5583ac7ea91SChristian Brauner break; 5593ac7ea91SChristian Brauner case 1: 5603ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("fsmount(FSMOUNT_NAMESPACE) failed in userns"); 5613ac7ea91SChristian Brauner break; 5623ac7ea91SChristian Brauner case 2: 5633ac7ea91SChristian Brauner SKIP(return, "setup_userns failed"); 5643ac7ea91SChristian Brauner break; 5653ac7ea91SChristian Brauner case 3: 5663ac7ea91SChristian Brauner SKIP(return, "fsopen failed in userns"); 5673ac7ea91SChristian Brauner break; 5683ac7ea91SChristian Brauner case 4: 5693ac7ea91SChristian Brauner SKIP(return, "fsconfig CMD_CREATE failed in userns"); 5703ac7ea91SChristian Brauner break; 5713ac7ea91SChristian Brauner case 6: 5723ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 5733ac7ea91SChristian Brauner break; 5743ac7ea91SChristian Brauner case 7: 5753ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID"); 5763ac7ea91SChristian Brauner break; 5773ac7ea91SChristian Brauner case 8: 5783ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("listmount failed in new namespace"); 5793ac7ea91SChristian Brauner break; 5803ac7ea91SChristian Brauner case 9: 5813ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("New namespace has no mounts"); 5823ac7ea91SChristian Brauner break; 5833ac7ea91SChristian Brauner default: 5843ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)", 5853ac7ea91SChristian Brauner WEXITSTATUS(status)); 5863ac7ea91SChristian Brauner break; 5873ac7ea91SChristian Brauner } 5883ac7ea91SChristian Brauner } 5893ac7ea91SChristian Brauner 5903ac7ea91SChristian Brauner TEST_F(fsmount_ns_userns, setns_in_userns) 5913ac7ea91SChristian Brauner { 5923ac7ea91SChristian Brauner pid_t pid; 5933ac7ea91SChristian Brauner int status; 5943ac7ea91SChristian Brauner 5953ac7ea91SChristian Brauner pid = fork(); 5963ac7ea91SChristian Brauner ASSERT_GE(pid, 0); 5973ac7ea91SChristian Brauner 5983ac7ea91SChristian Brauner if (pid == 0) { 5993ac7ea91SChristian Brauner uint64_t new_ns_id; 6003ac7ea91SChristian Brauner int fs_fd, fd; 6013ac7ea91SChristian Brauner pid_t inner_pid; 6023ac7ea91SChristian Brauner int inner_status; 6033ac7ea91SChristian Brauner 6043ac7ea91SChristian Brauner /* Create new user namespace */ 6053ac7ea91SChristian Brauner if (setup_userns() != 0) 6063ac7ea91SChristian Brauner _exit(2); 6073ac7ea91SChristian Brauner 6083ac7ea91SChristian Brauner fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 6093ac7ea91SChristian Brauner if (fs_fd < 0) 6103ac7ea91SChristian Brauner _exit(3); 6113ac7ea91SChristian Brauner 6123ac7ea91SChristian Brauner if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) { 6133ac7ea91SChristian Brauner close(fs_fd); 6143ac7ea91SChristian Brauner _exit(4); 6153ac7ea91SChristian Brauner } 6163ac7ea91SChristian Brauner 6173ac7ea91SChristian Brauner fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 6183ac7ea91SChristian Brauner close(fs_fd); 6193ac7ea91SChristian Brauner 6203ac7ea91SChristian Brauner if (fd < 0) { 6213ac7ea91SChristian Brauner if (errno == EINVAL) 6223ac7ea91SChristian Brauner _exit(6); 6233ac7ea91SChristian Brauner _exit(1); 6243ac7ea91SChristian Brauner } 6253ac7ea91SChristian Brauner 6263ac7ea91SChristian Brauner if (get_mnt_ns_id(fd, &new_ns_id) != 0) 6273ac7ea91SChristian Brauner _exit(7); 6283ac7ea91SChristian Brauner 6293ac7ea91SChristian Brauner /* Fork again to test setns into the new namespace */ 6303ac7ea91SChristian Brauner inner_pid = fork(); 6313ac7ea91SChristian Brauner if (inner_pid < 0) 6323ac7ea91SChristian Brauner _exit(10); 6333ac7ea91SChristian Brauner 6343ac7ea91SChristian Brauner if (inner_pid == 0) { 6353ac7ea91SChristian Brauner /* Inner child: enter the new namespace */ 6363ac7ea91SChristian Brauner if (setns(fd, CLONE_NEWNS) < 0) 6373ac7ea91SChristian Brauner _exit(1); 6383ac7ea91SChristian Brauner _exit(0); 6393ac7ea91SChristian Brauner } 6403ac7ea91SChristian Brauner 6413ac7ea91SChristian Brauner if (waitpid(inner_pid, &inner_status, 0) != inner_pid) 6423ac7ea91SChristian Brauner _exit(11); 6433ac7ea91SChristian Brauner 6443ac7ea91SChristian Brauner if (!WIFEXITED(inner_status) || WEXITSTATUS(inner_status) != 0) 6453ac7ea91SChristian Brauner _exit(12); 6463ac7ea91SChristian Brauner 6473ac7ea91SChristian Brauner close(fd); 6483ac7ea91SChristian Brauner _exit(0); 6493ac7ea91SChristian Brauner } 6503ac7ea91SChristian Brauner 6513ac7ea91SChristian Brauner ASSERT_EQ(waitpid(pid, &status, 0), pid); 6523ac7ea91SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 6533ac7ea91SChristian Brauner 6543ac7ea91SChristian Brauner switch (WEXITSTATUS(status)) { 6553ac7ea91SChristian Brauner case 0: 6563ac7ea91SChristian Brauner /* Success */ 6573ac7ea91SChristian Brauner break; 6583ac7ea91SChristian Brauner case 1: 6593ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("fsmount or setns failed in userns"); 6603ac7ea91SChristian Brauner break; 6613ac7ea91SChristian Brauner case 2: 6623ac7ea91SChristian Brauner SKIP(return, "setup_userns failed"); 6633ac7ea91SChristian Brauner break; 6643ac7ea91SChristian Brauner case 3: 6653ac7ea91SChristian Brauner SKIP(return, "fsopen failed in userns"); 6663ac7ea91SChristian Brauner break; 6673ac7ea91SChristian Brauner case 4: 6683ac7ea91SChristian Brauner SKIP(return, "fsconfig CMD_CREATE failed in userns"); 6693ac7ea91SChristian Brauner break; 6703ac7ea91SChristian Brauner case 6: 6713ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 6723ac7ea91SChristian Brauner break; 6733ac7ea91SChristian Brauner case 7: 6743ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID"); 6753ac7ea91SChristian Brauner break; 6763ac7ea91SChristian Brauner case 10: 6773ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Inner fork failed"); 6783ac7ea91SChristian Brauner break; 6793ac7ea91SChristian Brauner case 11: 6803ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Inner waitpid failed"); 6813ac7ea91SChristian Brauner break; 6823ac7ea91SChristian Brauner case 12: 6833ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("setns into new namespace failed"); 6843ac7ea91SChristian Brauner break; 6853ac7ea91SChristian Brauner default: 6863ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)", 6873ac7ea91SChristian Brauner WEXITSTATUS(status)); 6883ac7ea91SChristian Brauner break; 6893ac7ea91SChristian Brauner } 6903ac7ea91SChristian Brauner } 6913ac7ea91SChristian Brauner 6923ac7ea91SChristian Brauner TEST_F(fsmount_ns_userns, umount_fails_einval) 6933ac7ea91SChristian Brauner { 6943ac7ea91SChristian Brauner pid_t pid; 6953ac7ea91SChristian Brauner int status; 6963ac7ea91SChristian Brauner 6973ac7ea91SChristian Brauner pid = fork(); 6983ac7ea91SChristian Brauner ASSERT_GE(pid, 0); 6993ac7ea91SChristian Brauner 7003ac7ea91SChristian Brauner if (pid == 0) { 7013ac7ea91SChristian Brauner uint64_t new_ns_id; 7023ac7ea91SChristian Brauner uint64_t list[256]; 7033ac7ea91SChristian Brauner ssize_t nr_mounts; 7043ac7ea91SChristian Brauner int fs_fd, fd; 7053ac7ea91SChristian Brauner ssize_t i; 7063ac7ea91SChristian Brauner 7073ac7ea91SChristian Brauner /* Create new user namespace */ 7083ac7ea91SChristian Brauner if (setup_userns() != 0) 7093ac7ea91SChristian Brauner _exit(2); 7103ac7ea91SChristian Brauner 7113ac7ea91SChristian Brauner fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 7123ac7ea91SChristian Brauner if (fs_fd < 0) 7133ac7ea91SChristian Brauner _exit(3); 7143ac7ea91SChristian Brauner 7153ac7ea91SChristian Brauner if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) { 7163ac7ea91SChristian Brauner close(fs_fd); 7173ac7ea91SChristian Brauner _exit(4); 7183ac7ea91SChristian Brauner } 7193ac7ea91SChristian Brauner 7203ac7ea91SChristian Brauner fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 7213ac7ea91SChristian Brauner close(fs_fd); 7223ac7ea91SChristian Brauner 7233ac7ea91SChristian Brauner if (fd < 0) { 7243ac7ea91SChristian Brauner if (errno == EINVAL) 7253ac7ea91SChristian Brauner _exit(6); 7263ac7ea91SChristian Brauner _exit(1); 7273ac7ea91SChristian Brauner } 7283ac7ea91SChristian Brauner 7293ac7ea91SChristian Brauner if (get_mnt_ns_id(fd, &new_ns_id) != 0) 7303ac7ea91SChristian Brauner _exit(7); 7313ac7ea91SChristian Brauner 7323ac7ea91SChristian Brauner /* Get all mounts in the new namespace */ 7333ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, LISTMOUNT_REVERSE); 7343ac7ea91SChristian Brauner if (nr_mounts < 0) 7353ac7ea91SChristian Brauner _exit(13); 7363ac7ea91SChristian Brauner 7373ac7ea91SChristian Brauner if (nr_mounts < 1) 7383ac7ea91SChristian Brauner _exit(14); 7393ac7ea91SChristian Brauner 7403ac7ea91SChristian Brauner /* Enter the new namespace */ 7413ac7ea91SChristian Brauner if (setns(fd, CLONE_NEWNS) < 0) 7423ac7ea91SChristian Brauner _exit(8); 7433ac7ea91SChristian Brauner 7443ac7ea91SChristian Brauner for (i = 0; i < nr_mounts; i++) { 7453ac7ea91SChristian Brauner struct statmount *sm; 7463ac7ea91SChristian Brauner const char *mnt_point; 7473ac7ea91SChristian Brauner 7483ac7ea91SChristian Brauner sm = statmount_alloc(list[i], new_ns_id, 7493ac7ea91SChristian Brauner STATMOUNT_MNT_POINT, 0); 7503ac7ea91SChristian Brauner if (!sm) 7513ac7ea91SChristian Brauner _exit(15); 7523ac7ea91SChristian Brauner 7533ac7ea91SChristian Brauner mnt_point = sm->str + sm->mnt_point; 7543ac7ea91SChristian Brauner 7553ac7ea91SChristian Brauner if (umount2(mnt_point, MNT_DETACH) == 0) { 7563ac7ea91SChristian Brauner free(sm); 7573ac7ea91SChristian Brauner _exit(9); 7583ac7ea91SChristian Brauner } 7593ac7ea91SChristian Brauner 7603ac7ea91SChristian Brauner if (errno != EINVAL) { 7613ac7ea91SChristian Brauner /* Wrong error */ 7623ac7ea91SChristian Brauner free(sm); 7633ac7ea91SChristian Brauner _exit(10); 7643ac7ea91SChristian Brauner } 7653ac7ea91SChristian Brauner 7663ac7ea91SChristian Brauner free(sm); 7673ac7ea91SChristian Brauner } 7683ac7ea91SChristian Brauner 7693ac7ea91SChristian Brauner close(fd); 7703ac7ea91SChristian Brauner _exit(0); 7713ac7ea91SChristian Brauner } 7723ac7ea91SChristian Brauner 7733ac7ea91SChristian Brauner ASSERT_EQ(waitpid(pid, &status, 0), pid); 7743ac7ea91SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 7753ac7ea91SChristian Brauner 7763ac7ea91SChristian Brauner switch (WEXITSTATUS(status)) { 7773ac7ea91SChristian Brauner case 0: 7783ac7ea91SChristian Brauner break; 7793ac7ea91SChristian Brauner case 1: 7803ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("fsmount(FSMOUNT_NAMESPACE) failed"); 7813ac7ea91SChristian Brauner break; 7823ac7ea91SChristian Brauner case 2: 7833ac7ea91SChristian Brauner SKIP(return, "setup_userns failed"); 7843ac7ea91SChristian Brauner break; 7853ac7ea91SChristian Brauner case 3: 7863ac7ea91SChristian Brauner SKIP(return, "fsopen failed in userns"); 7873ac7ea91SChristian Brauner break; 7883ac7ea91SChristian Brauner case 4: 7893ac7ea91SChristian Brauner SKIP(return, "fsconfig CMD_CREATE failed in userns"); 7903ac7ea91SChristian Brauner break; 7913ac7ea91SChristian Brauner case 6: 7923ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 7933ac7ea91SChristian Brauner break; 7943ac7ea91SChristian Brauner case 7: 7953ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID"); 7963ac7ea91SChristian Brauner break; 7973ac7ea91SChristian Brauner case 8: 7983ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("setns into new namespace failed"); 7993ac7ea91SChristian Brauner break; 8003ac7ea91SChristian Brauner case 9: 8013ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("umount succeeded but should have failed with EINVAL"); 8023ac7ea91SChristian Brauner break; 8033ac7ea91SChristian Brauner case 10: 8043ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("umount failed with wrong error (expected EINVAL)"); 8053ac7ea91SChristian Brauner break; 8063ac7ea91SChristian Brauner case 13: 8073ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("listmount failed"); 8083ac7ea91SChristian Brauner break; 8093ac7ea91SChristian Brauner case 14: 8103ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("No mounts in new namespace"); 8113ac7ea91SChristian Brauner break; 8123ac7ea91SChristian Brauner case 15: 8133ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("statmount_alloc failed"); 8143ac7ea91SChristian Brauner break; 8153ac7ea91SChristian Brauner default: 8163ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)", 8173ac7ea91SChristian Brauner WEXITSTATUS(status)); 8183ac7ea91SChristian Brauner break; 8193ac7ea91SChristian Brauner } 8203ac7ea91SChristian Brauner } 8213ac7ea91SChristian Brauner 8223ac7ea91SChristian Brauner TEST_F(fsmount_ns_userns, umount_succeeds) 8233ac7ea91SChristian Brauner { 8243ac7ea91SChristian Brauner pid_t pid; 8253ac7ea91SChristian Brauner int status; 8263ac7ea91SChristian Brauner 8273ac7ea91SChristian Brauner pid = fork(); 8283ac7ea91SChristian Brauner ASSERT_GE(pid, 0); 8293ac7ea91SChristian Brauner 8303ac7ea91SChristian Brauner if (pid == 0) { 8313ac7ea91SChristian Brauner uint64_t new_ns_id; 8323ac7ea91SChristian Brauner uint64_t list[256]; 8333ac7ea91SChristian Brauner ssize_t nr_mounts; 8343ac7ea91SChristian Brauner int fs_fd, fd; 8353ac7ea91SChristian Brauner ssize_t i; 8363ac7ea91SChristian Brauner 8373ac7ea91SChristian Brauner if (unshare(CLONE_NEWNS)) 8383ac7ea91SChristian Brauner _exit(1); 8393ac7ea91SChristian Brauner 8403ac7ea91SChristian Brauner if (sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) != 0) 8413ac7ea91SChristian Brauner _exit(1); 8423ac7ea91SChristian Brauner 8433ac7ea91SChristian Brauner fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 8443ac7ea91SChristian Brauner if (fs_fd < 0) 8453ac7ea91SChristian Brauner _exit(3); 8463ac7ea91SChristian Brauner 8473ac7ea91SChristian Brauner if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) { 8483ac7ea91SChristian Brauner close(fs_fd); 8493ac7ea91SChristian Brauner _exit(4); 8503ac7ea91SChristian Brauner } 8513ac7ea91SChristian Brauner 8523ac7ea91SChristian Brauner fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 8533ac7ea91SChristian Brauner close(fs_fd); 8543ac7ea91SChristian Brauner 8553ac7ea91SChristian Brauner if (fd < 0) { 8563ac7ea91SChristian Brauner if (errno == EINVAL) 8573ac7ea91SChristian Brauner _exit(6); 8583ac7ea91SChristian Brauner _exit(1); 8593ac7ea91SChristian Brauner } 8603ac7ea91SChristian Brauner 8613ac7ea91SChristian Brauner if (get_mnt_ns_id(fd, &new_ns_id) != 0) 8623ac7ea91SChristian Brauner _exit(7); 8633ac7ea91SChristian Brauner 8643ac7ea91SChristian Brauner /* Get all mounts in the new namespace */ 8653ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, LISTMOUNT_REVERSE); 8663ac7ea91SChristian Brauner if (nr_mounts < 0) 8673ac7ea91SChristian Brauner _exit(13); 8683ac7ea91SChristian Brauner 8693ac7ea91SChristian Brauner if (nr_mounts < 1) 8703ac7ea91SChristian Brauner _exit(14); 8713ac7ea91SChristian Brauner 8723ac7ea91SChristian Brauner /* Enter the new namespace */ 8733ac7ea91SChristian Brauner if (setns(fd, CLONE_NEWNS) < 0) 8743ac7ea91SChristian Brauner _exit(8); 8753ac7ea91SChristian Brauner 8763ac7ea91SChristian Brauner for (i = 0; i < nr_mounts; i++) { 8773ac7ea91SChristian Brauner struct statmount *sm; 8783ac7ea91SChristian Brauner const char *mnt_point; 8793ac7ea91SChristian Brauner 8803ac7ea91SChristian Brauner sm = statmount_alloc(list[i], new_ns_id, 8813ac7ea91SChristian Brauner STATMOUNT_MNT_POINT, 0); 8823ac7ea91SChristian Brauner if (!sm) 8833ac7ea91SChristian Brauner _exit(15); 8843ac7ea91SChristian Brauner 8853ac7ea91SChristian Brauner mnt_point = sm->str + sm->mnt_point; 8863ac7ea91SChristian Brauner 8873ac7ea91SChristian Brauner if (umount2(mnt_point, MNT_DETACH) != 0) { 8883ac7ea91SChristian Brauner free(sm); 8893ac7ea91SChristian Brauner _exit(9); 8903ac7ea91SChristian Brauner } 8913ac7ea91SChristian Brauner 8923ac7ea91SChristian Brauner free(sm); 8933ac7ea91SChristian Brauner } 8943ac7ea91SChristian Brauner 8953ac7ea91SChristian Brauner close(fd); 8963ac7ea91SChristian Brauner _exit(0); 8973ac7ea91SChristian Brauner } 8983ac7ea91SChristian Brauner 8993ac7ea91SChristian Brauner ASSERT_EQ(waitpid(pid, &status, 0), pid); 9003ac7ea91SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 9013ac7ea91SChristian Brauner 9023ac7ea91SChristian Brauner switch (WEXITSTATUS(status)) { 9033ac7ea91SChristian Brauner case 0: 9043ac7ea91SChristian Brauner break; 9053ac7ea91SChristian Brauner case 1: 9063ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("fsmount(FSMOUNT_NAMESPACE) failed or unshare failed"); 9073ac7ea91SChristian Brauner break; 9083ac7ea91SChristian Brauner case 3: 9093ac7ea91SChristian Brauner SKIP(return, "fsopen failed"); 9103ac7ea91SChristian Brauner break; 9113ac7ea91SChristian Brauner case 4: 9123ac7ea91SChristian Brauner SKIP(return, "fsconfig CMD_CREATE failed"); 9133ac7ea91SChristian Brauner break; 9143ac7ea91SChristian Brauner case 6: 9153ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 9163ac7ea91SChristian Brauner break; 9173ac7ea91SChristian Brauner case 7: 9183ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID"); 9193ac7ea91SChristian Brauner break; 9203ac7ea91SChristian Brauner case 8: 9213ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("setns into new namespace failed"); 9223ac7ea91SChristian Brauner break; 9233ac7ea91SChristian Brauner case 9: 9243ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("umount failed but should have succeeded"); 9253ac7ea91SChristian Brauner break; 9263ac7ea91SChristian Brauner case 13: 9273ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("listmount failed"); 9283ac7ea91SChristian Brauner break; 9293ac7ea91SChristian Brauner case 14: 9303ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("No mounts in new namespace"); 9313ac7ea91SChristian Brauner break; 9323ac7ea91SChristian Brauner case 15: 9333ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("statmount_alloc failed"); 9343ac7ea91SChristian Brauner break; 9353ac7ea91SChristian Brauner default: 9363ac7ea91SChristian Brauner ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)", 9373ac7ea91SChristian Brauner WEXITSTATUS(status)); 9383ac7ea91SChristian Brauner break; 9393ac7ea91SChristian Brauner } 9403ac7ea91SChristian Brauner } 9413ac7ea91SChristian Brauner 9423ac7ea91SChristian Brauner FIXTURE(fsmount_ns_mount_attrs) 9433ac7ea91SChristian Brauner { 9443ac7ea91SChristian Brauner int fd; 9453ac7ea91SChristian Brauner int fs_fd; 9463ac7ea91SChristian Brauner }; 9473ac7ea91SChristian Brauner 9483ac7ea91SChristian Brauner FIXTURE_SETUP(fsmount_ns_mount_attrs) 9493ac7ea91SChristian Brauner { 9503ac7ea91SChristian Brauner int ret; 9513ac7ea91SChristian Brauner 9523ac7ea91SChristian Brauner self->fd = -1; 9533ac7ea91SChristian Brauner self->fs_fd = -1; 9543ac7ea91SChristian Brauner 9553ac7ea91SChristian Brauner /* Check if fsopen syscall is supported */ 9563ac7ea91SChristian Brauner ret = sys_fsopen("tmpfs", 0); 9573ac7ea91SChristian Brauner if (ret == -1 && errno == ENOSYS) 9583ac7ea91SChristian Brauner SKIP(return, "fsopen() syscall not supported"); 9593ac7ea91SChristian Brauner if (ret >= 0) 9603ac7ea91SChristian Brauner close(ret); 9613ac7ea91SChristian Brauner 9623ac7ea91SChristian Brauner /* Check if statmount/listmount are supported */ 9633ac7ea91SChristian Brauner ret = statmount(0, 0, 0, 0, NULL, 0, 0); 9643ac7ea91SChristian Brauner if (ret == -1 && errno == ENOSYS) 9653ac7ea91SChristian Brauner SKIP(return, "statmount() syscall not supported"); 9663ac7ea91SChristian Brauner } 9673ac7ea91SChristian Brauner 9683ac7ea91SChristian Brauner FIXTURE_TEARDOWN(fsmount_ns_mount_attrs) 9693ac7ea91SChristian Brauner { 9703ac7ea91SChristian Brauner if (self->fd >= 0) 9713ac7ea91SChristian Brauner close(self->fd); 9723ac7ea91SChristian Brauner if (self->fs_fd >= 0) 9733ac7ea91SChristian Brauner close(self->fs_fd); 9743ac7ea91SChristian Brauner } 9753ac7ea91SChristian Brauner 9763ac7ea91SChristian Brauner TEST_F(fsmount_ns_mount_attrs, readonly) 9773ac7ea91SChristian Brauner { 9783ac7ea91SChristian Brauner struct statmount sm; 9793ac7ea91SChristian Brauner uint64_t new_ns_id; 9803ac7ea91SChristian Brauner uint64_t list[256]; 9813ac7ea91SChristian Brauner ssize_t nr_mounts; 9823ac7ea91SChristian Brauner int ret; 9833ac7ea91SChristian Brauner 9843ac7ea91SChristian Brauner self->fs_fd = create_tmpfs_fd(); 9853ac7ea91SChristian Brauner ASSERT_GE(self->fs_fd, 0); 9863ac7ea91SChristian Brauner 9873ac7ea91SChristian Brauner self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 9883ac7ea91SChristian Brauner MOUNT_ATTR_RDONLY); 9893ac7ea91SChristian Brauner if (self->fd < 0 && errno == EINVAL) 9903ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 9913ac7ea91SChristian Brauner 9923ac7ea91SChristian Brauner ASSERT_GE(self->fd, 0); 9933ac7ea91SChristian Brauner 9943ac7ea91SChristian Brauner ret = get_mnt_ns_id(self->fd, &new_ns_id); 9953ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 9963ac7ea91SChristian Brauner 9973ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 9983ac7ea91SChristian Brauner ASSERT_GE(nr_mounts, 1); 9993ac7ea91SChristian Brauner 10003ac7ea91SChristian Brauner ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 10013ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 10023ac7ea91SChristian Brauner 10033ac7ea91SChristian Brauner /* Verify the mount is read-only */ 10043ac7ea91SChristian Brauner ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_RDONLY); 10053ac7ea91SChristian Brauner } 10063ac7ea91SChristian Brauner 10073ac7ea91SChristian Brauner TEST_F(fsmount_ns_mount_attrs, noexec) 10083ac7ea91SChristian Brauner { 10093ac7ea91SChristian Brauner struct statmount sm; 10103ac7ea91SChristian Brauner uint64_t new_ns_id; 10113ac7ea91SChristian Brauner uint64_t list[256]; 10123ac7ea91SChristian Brauner ssize_t nr_mounts; 10133ac7ea91SChristian Brauner int ret; 10143ac7ea91SChristian Brauner 10153ac7ea91SChristian Brauner self->fs_fd = create_tmpfs_fd(); 10163ac7ea91SChristian Brauner ASSERT_GE(self->fs_fd, 0); 10173ac7ea91SChristian Brauner 10183ac7ea91SChristian Brauner self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 10193ac7ea91SChristian Brauner MOUNT_ATTR_NOEXEC); 10203ac7ea91SChristian Brauner if (self->fd < 0 && errno == EINVAL) 10213ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 10223ac7ea91SChristian Brauner 10233ac7ea91SChristian Brauner ASSERT_GE(self->fd, 0); 10243ac7ea91SChristian Brauner 10253ac7ea91SChristian Brauner ret = get_mnt_ns_id(self->fd, &new_ns_id); 10263ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 10273ac7ea91SChristian Brauner 10283ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 10293ac7ea91SChristian Brauner ASSERT_GE(nr_mounts, 1); 10303ac7ea91SChristian Brauner 10313ac7ea91SChristian Brauner ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 10323ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 10333ac7ea91SChristian Brauner 10343ac7ea91SChristian Brauner /* Verify the mount is noexec */ 10353ac7ea91SChristian Brauner ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOEXEC); 10363ac7ea91SChristian Brauner } 10373ac7ea91SChristian Brauner 10383ac7ea91SChristian Brauner TEST_F(fsmount_ns_mount_attrs, nosuid) 10393ac7ea91SChristian Brauner { 10403ac7ea91SChristian Brauner struct statmount sm; 10413ac7ea91SChristian Brauner uint64_t new_ns_id; 10423ac7ea91SChristian Brauner uint64_t list[256]; 10433ac7ea91SChristian Brauner ssize_t nr_mounts; 10443ac7ea91SChristian Brauner int ret; 10453ac7ea91SChristian Brauner 10463ac7ea91SChristian Brauner self->fs_fd = create_tmpfs_fd(); 10473ac7ea91SChristian Brauner ASSERT_GE(self->fs_fd, 0); 10483ac7ea91SChristian Brauner 10493ac7ea91SChristian Brauner self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 10503ac7ea91SChristian Brauner MOUNT_ATTR_NOSUID); 10513ac7ea91SChristian Brauner if (self->fd < 0 && errno == EINVAL) 10523ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 10533ac7ea91SChristian Brauner 10543ac7ea91SChristian Brauner ASSERT_GE(self->fd, 0); 10553ac7ea91SChristian Brauner 10563ac7ea91SChristian Brauner ret = get_mnt_ns_id(self->fd, &new_ns_id); 10573ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 10583ac7ea91SChristian Brauner 10593ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 10603ac7ea91SChristian Brauner ASSERT_GE(nr_mounts, 1); 10613ac7ea91SChristian Brauner 10623ac7ea91SChristian Brauner ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 10633ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 10643ac7ea91SChristian Brauner 10653ac7ea91SChristian Brauner /* Verify the mount is nosuid */ 10663ac7ea91SChristian Brauner ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOSUID); 10673ac7ea91SChristian Brauner } 10683ac7ea91SChristian Brauner 10693ac7ea91SChristian Brauner TEST_F(fsmount_ns_mount_attrs, noatime) 10703ac7ea91SChristian Brauner { 10713ac7ea91SChristian Brauner struct statmount sm; 10723ac7ea91SChristian Brauner uint64_t new_ns_id; 10733ac7ea91SChristian Brauner uint64_t list[256]; 10743ac7ea91SChristian Brauner ssize_t nr_mounts; 10753ac7ea91SChristian Brauner int ret; 10763ac7ea91SChristian Brauner 10773ac7ea91SChristian Brauner self->fs_fd = create_tmpfs_fd(); 10783ac7ea91SChristian Brauner ASSERT_GE(self->fs_fd, 0); 10793ac7ea91SChristian Brauner 10803ac7ea91SChristian Brauner self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 10813ac7ea91SChristian Brauner MOUNT_ATTR_NOATIME); 10823ac7ea91SChristian Brauner if (self->fd < 0 && errno == EINVAL) 10833ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 10843ac7ea91SChristian Brauner 10853ac7ea91SChristian Brauner ASSERT_GE(self->fd, 0); 10863ac7ea91SChristian Brauner 10873ac7ea91SChristian Brauner ret = get_mnt_ns_id(self->fd, &new_ns_id); 10883ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 10893ac7ea91SChristian Brauner 10903ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 10913ac7ea91SChristian Brauner ASSERT_GE(nr_mounts, 1); 10923ac7ea91SChristian Brauner 10933ac7ea91SChristian Brauner ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 10943ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 10953ac7ea91SChristian Brauner 10963ac7ea91SChristian Brauner /* Verify the mount is noatime */ 10973ac7ea91SChristian Brauner ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOATIME); 10983ac7ea91SChristian Brauner } 10993ac7ea91SChristian Brauner 11003ac7ea91SChristian Brauner TEST_F(fsmount_ns_mount_attrs, combined) 11013ac7ea91SChristian Brauner { 11023ac7ea91SChristian Brauner struct statmount sm; 11033ac7ea91SChristian Brauner uint64_t new_ns_id; 11043ac7ea91SChristian Brauner uint64_t list[256]; 11053ac7ea91SChristian Brauner ssize_t nr_mounts; 11063ac7ea91SChristian Brauner int ret; 11073ac7ea91SChristian Brauner 11083ac7ea91SChristian Brauner self->fs_fd = create_tmpfs_fd(); 11093ac7ea91SChristian Brauner ASSERT_GE(self->fs_fd, 0); 11103ac7ea91SChristian Brauner 11113ac7ea91SChristian Brauner self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 11123ac7ea91SChristian Brauner MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | 11133ac7ea91SChristian Brauner MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOATIME); 11143ac7ea91SChristian Brauner if (self->fd < 0 && errno == EINVAL) 11153ac7ea91SChristian Brauner SKIP(return, "FSMOUNT_NAMESPACE not supported"); 11163ac7ea91SChristian Brauner 11173ac7ea91SChristian Brauner ASSERT_GE(self->fd, 0); 11183ac7ea91SChristian Brauner 11193ac7ea91SChristian Brauner ret = get_mnt_ns_id(self->fd, &new_ns_id); 11203ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 11213ac7ea91SChristian Brauner 11223ac7ea91SChristian Brauner nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 11233ac7ea91SChristian Brauner ASSERT_GE(nr_mounts, 1); 11243ac7ea91SChristian Brauner 11253ac7ea91SChristian Brauner ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 11263ac7ea91SChristian Brauner ASSERT_EQ(ret, 0); 11273ac7ea91SChristian Brauner 11283ac7ea91SChristian Brauner /* Verify all attributes are set */ 11293ac7ea91SChristian Brauner ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_RDONLY); 11303ac7ea91SChristian Brauner ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOEXEC); 11313ac7ea91SChristian Brauner ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOSUID); 11323ac7ea91SChristian Brauner ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOATIME); 11333ac7ea91SChristian Brauner } 11343ac7ea91SChristian Brauner 11353ac7ea91SChristian Brauner TEST_HARNESS_MAIN 1136