mount_setattr(2) System Calls Manual mount_setattr(2) mount_setattr - (libc -lc) #include /* AT_* */ #include int mount_setattr(int dirfd, const char *path, unsigned int flags, struct mount_attr *attr, size_t size); mount_setattr() . mount_setattr() . path dirfd. dirfd AT_FDCWD path . path AT_EMPTY_PATH flags dirfd. ( openat(2) dirfd.) mount_setattr() (struct mount_attr) . mount_setattr() . . " " NOTES . size sizeof(struct mount_attr). struct mount_attr . . struct mount_attr MOUNT_ATTR_SIZE_VERnumber . struct mount_attr MOUNT_ATTR_SIZE_VER0. flags . : AT_EMPTY_PATH path dirfd . AT_RECURSIVE . AT_SYMLINK_NOFOLLOW . AT_NO_AUTOMOUNT . attr mount_setattr() mount_attr mount_attr(2type). attr_set attr_clr . attr_set attr_clr . attr_clr attr_set. : struct mount_attr attr = { .attr_clr = MOUNT_ATTR_NOEXEC | MOUNT_ATTR_NODEV, .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID, }; : unsigned int current_mnt_flags = mnt->mnt_flags; /* * .attr_clr * MOUNT_ATTR_NOEXEC MOUNT_ATTR_NODEV. */ current_mnt_flags &= ~attr->attr_clr; /* * .attr_set * MOUNT_ATTR_RDONLY MOUNT_ATTR_NOSUID. */ current_mnt_flags |= attr->attr_set; mnt->mnt_flags = current_mnt_flags; () () set-user-ID set-group-ID () () . attr_clr attr_set (idempotent) . attr_set attr_clr: MOUNT_ATTR_RDONLY attr_set . attr_clr . MOUNT_ATTR_NOSUID attr_set set-user-ID set-group-ID . attr_clr set-user-ID set-group-ID . MOUNT_ATTR_NODEV attr_set . attr_clr . MOUNT_ATTR_NOEXEC attr_set . attr_clr . MOUNT_ATTR_NOSYMFOLLOW attr_set . attr_clr . MOUNT_ATTR_NODIRATIME attr_set . attr_clr . MOUNT_ATTR_NODIRATIME noatime. . MOUNT_ATTR__ATIME - MOUNT_ATTR__ATIME. ( MOUNT_ATTR_NOEXEC) attr_set attr_clr fsmount(2) . attr_set MOUNT_ATTR__ATIME attr_clr. MOUNT_ATTR__ATIME attr_clr ( MOUNT_ATTR__ATIME ) attr_set MOUNT_ATTR__ATIME attr_clr. MOUNT_ATTR_RELATIME (atime) atime (mtime) (ctime). MOUNT_ATTR_RELATIME attr_set MOUNT_ATTR__ATIME attr_clr. MOUNT_ATTR_NOATIME ( ) . MOUNT_ATTR_NOATIME attr_set MOUNT_ATTR__ATIME attr_clr. MOUNT_ATTR_STRICTATIME (atime) . MOUNT_ATTR_STRICTATIME attr_set MOUNT_ATTR__ATIME attr_clr. MOUNT_ATTR_IDMAP attr_set (ID-mapped mount). userns_fd . MOUNT_ATTR_IDMAP attr_clr. " " NOTES. propagation . : MS_PRIVATE . MS_SHARED . MS_SLAVE . MS_UNBINDABLE . mount_namespaces(7). mount_setattr() . -1 errno . EBADF path dirfd AT_FDCWD . EBADF userns_fd . EBUSY MOUNT_ATTR_RDONLY . EBUSY MOUNT_ATTR_IDMAP userns_fd . EINVAL dirfd path mount_setattr() . EINVAL flags. EINVAL attr_set mount_attr. EINVAL attr_clr mount_attr. EINVAL propagation mount_attr. EINVAL MS_SHARED MS_SLAVE MS_PRIVATE MS_UNBINDABLE propagation mount_attr. EINVAL attr_set MOUNT_ATTR__ATIME attr_clr. EINVAL MOUNT_ATTR_IDMAP attr_clr. EINVAL userns_fd INT_MAX. EINVAL userns_fd . EINVAL . EINVAL . EINVAL attr_clr MOUNT_ATTR__ATIME. EINVAL . EINVAL ENOENT . ENOMEM MS_SHARED . . ENOSPC MS_SHARED . . EPERM MOUNT_ATTR_NOATIME MOUNT_ATTR_NODEV MOUNT_ATTR_NODIRATIME MOUNT_ATTR_NOEXEC MOUNT_ATTR_NOSUID MOUNT_ATTR_RDONLY . : o ( ). . o . CLONE_NEWUSER | CLONE_NEWNS unshare(2) clone(2) clone3(2). . -- -- ( ). EPERM userns_fd . EPERM (ID mapping) . EPERM CAP_SYS_ADMIN . . 5.12 glibc 2.36. (ID-mapped) . . . . . inodes xattr(7) : o security.capability VFS_CAP_REVISION_3 ( capabilities(7)). o system.posix_acl_access system.posix_acl_default ACL_USER ACL_GROUP. : o CAP_SYS_ADMIN . o . : o xfs(5) ( 5.12) o ext4(5) ( 5.12) o FAT ( 5.12) o btrfs(5) ( 5.15) o ntfs3 ( 5.15) o f2fs ( 5.18) o erofs ( 5.19) o overlayfs ( 5.19) o squashfs ( 6.2) o tmpfs ( 6.3) o cephfs ( 6.7) o hugetlbfs ( 6.9) o . . o (writers). o open_tree(2) OPEN_TREE_CLONE . ( : move_mount(2).) . . . . . "1000 1001 1" 1000 1001 . 1 1000 . 340 . (overflow) . user_namespaces(7). userns_fd ( MOUNT_ATTR_IDMAP attr_set) (container). systemd-homed.service(8). . : o . systemd-homed.service(8) . . o . chown(2). o . chown(2). chown(2) . o . o (DAC) . o . chown(2) . . mount_setattr() . o . . chown(2) . o . . chown(2) . ( mount(8)) . -o ro mount(8) " " " ". . ( ) (" - superblock flags" ) . mount(2) . mount_setattr() fsconfig(2) . mount_setattr() fsconfig(2). mount_setattr() mount_attr . mount_setattr() size . ( ). perf_setattr(2) perf_event_open(2) clone3(2) openat2(2). usize ksize : o ksize usize attr . o ksize usize . (no-op) . . o ksize usize . . -1 errno E2BIG. . struct mount_attr ( ) struct mount_attr . : struct mount_attr attr = { .attr_set = MOUNT_ATTR_RDONLY, .attr_clr = MOUNT_ATTR_NODEV }; memset(3) : struct mount_attr attr; memset(&attr, 0, sizeof(attr)); attr.attr_set = MOUNT_ATTR_RDONLY; attr.attr_clr = MOUNT_ATTR_NODEV; size ( E2BIG). /* * This program allows the caller to create a new detached mount * and set various properties on it. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include static const struct option longopts[] = { {"map-mount", required_argument, NULL, 'a'}, {"recursive", no_argument, NULL, 'b'}, {"read-only", no_argument, NULL, 'c'}, {"block-setid", no_argument, NULL, 'd'}, {"block-devices", no_argument, NULL, 'e'}, {"block-exec", no_argument, NULL, 'f'}, {"no-access-time", no_argument, NULL, 'g'}, { NULL, 0, NULL, 0 }, }; int main(int argc, char *argv[]) { int fd_userns = -1; int fd_tree; int index = 0; int ret; bool recursive = false; const char *source; const char *target; struct mount_attr *attr = &(struct mount_attr){}; while ((ret = getopt_long_only(argc, argv, "", longopts, &index)) != -1) { switch (ret) { case 'a': fd_userns = open(optarg, O_RDONLY | O_CLOEXEC); if (fd_userns == -1) err(EXIT_FAILURE, "open(%s)", optarg); break; case 'b': recursive = true; break; case 'c': attr->attr_set |= MOUNT_ATTR_RDONLY; break; case 'd': attr->attr_set |= MOUNT_ATTR_NOSUID; break; case 'e': attr->attr_set |= MOUNT_ATTR_NODEV; break; case 'f': attr->attr_set |= MOUNT_ATTR_NOEXEC; break; case 'g': attr->attr_set |= MOUNT_ATTR_NOATIME; attr->attr_clr |= MOUNT_ATTR__ATIME; break; default: errx(EXIT_FAILURE, "Invalid argument specified"); } } if ((argc - optind) < 2) errx(EXIT_FAILURE, "Missing source or target mount point"); source = argv[optind]; target = argv[optind + 1]; /* In the following, -1 as the 'dirfd' argument ensures that open_tree() fails if 'source' is not an absolute pathname. */ fd_tree = open_tree(-1, source, OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC | AT_EMPTY_PATH | (recursive ? AT_RECURSIVE : 0)); if (fd_tree == -1) err(EXIT_FAILURE, "open(%s)", source); if (fd_userns >= 0) { attr->attr_set |= MOUNT_ATTR_IDMAP; attr->userns_fd = fd_userns; } ret = mount_setattr(fd_tree, "", AT_EMPTY_PATH | (recursive ? AT_RECURSIVE : 0), attr, sizeof(struct mount_attr)); if (ret == -1) err(EXIT_FAILURE, "mount_setattr"); close(fd_userns); /* In the following, -1 as the 'to_dirfd' argument ensures that open_tree() fails if 'target' is not an absolute pathname. */ ret = move_mount(fd_tree, "", -1, target, MOVE_MOUNT_F_EMPTY_PATH); if (ret == -1) err(EXIT_FAILURE, "move_mount() to %s", target); close(fd_tree); exit(EXIT_SUCCESS); } newgidmap(1) newuidmap(1) clone(2) mount(2) unshare(2) proc(5) capabilities(7) mount_namespaces(7) user_namespaces(7) xattr(7) 3 . . : . 6.18 11 2026 mount_setattr(2)