-
Notifications
You must be signed in to change notification settings - Fork 1.3k
mount tries to use mount_setattr even if unsupported by running kernel (<5.12) #2247
Description
Originally reported downstream in Gentoo at https://bugs.gentoo.org/906797.
Bisect says 6e94230, although I see there's a bunch of mount work between 2.38.1 and 2.39 so I wouldn't be surprised if it's slightly off and just a nearby commit.
As of util-linux-2.39 (2.38.1 was fine), mount (e.g. mount -o remount,ro /) will try to use mount_setattr even if it's not available at runtime. It looks like a check is done at build-time but there's no callback for ENOSYS:
# ./mount -o remount,ro /boot
mount: /boot: mount_setattr system call failed: Function not implemented.
dmesg(1) may have more information after failed mount system call.
This fails on Linux 5.10 which is LTS, so still supported upstream as mount_setattr was added in Linux 5.12.
strace says the following on Linux 5.10.147 with util-linux 2.39:
17470 readlink("/boot", 0x7ffec5f50750, 1023) = -1 EINVAL (Invalid argument)
17470 statx(AT_FDCWD, "/sbin/mount.ext4", AT_STATX_DONT_SYNC|AT_NO_AUTOMOUNT, STATX_TYPE|STATX_MODE|STATX_INO, 0x7ffec5f4f940) = -1 ENOENT (No such file or directory)
[...]
17470 open_tree(AT_FDCWD, "/boot", OPEN_TREE_CLOEXEC) = 3
17470 getuid() = 0
17470 geteuid() = 0
17470 getgid() = 0
17470 getegid() = 0
17470 prctl(PR_GET_DUMPABLE) = 1 (SUID_DUMP_USER)
17470 newfstatat(AT_FDCWD, "/run/mount/utab", 0x7ffec5f50bc0, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)
17470 mkdir("/run/mount", 0755) = -1 EEXIST (File exists)
17470 newfstatat(AT_FDCWD, "/run/mount/utab", 0x7ffec5f50ab0, 0) = -1 ENOENT (No such file or directory)
17470 newfstatat(AT_FDCWD, "/run/mount", {st_mode=S_IFDIR|0755, st_size=40, ...}, 0) = 0
17470 geteuid() = 0
17470 getegid() = 0
17470 getuid() = 0
17470 getgid() = 0
17470 access("/run/mount", R_OK|W_OK) = 0
17470 fspick(3, "", FSPICK_NO_AUTOMOUNT|FSPICK_EMPTY_PATH) = 4
17470 fsconfig(4, FSCONFIG_SET_FLAG, "ro", NULL, 0) = 0
17470 fsconfig(4, FSCONFIG_CMD_RECONFIGURE, NULL, NULL, 0) = 0
17470 mount_setattr(3, "", AT_EMPTY_PATH, {attr_set=MOUNT_ATTR_RDONLY, attr_clr=MOUNT_ATTR_NOSUID|MOUNT_ATTR_NODEV|MOUNT_ATTR_NOEXEC|MOUNT_ATTR_NOSYMFOLLOW, propagation=0 /* MS_??? */, userns_fd=0}, 32) = -1 ENOSYS (Function not implemented)
17470 close(4) = 0
17470 close(3) = 0
[.. aborts ..]
It doesn't then attempt to use mount().
The build-time test would fail on systems with an older copy of linux-headers, but many people (including us in Gentoo) don't pin linux-headers to the kernel version because it'd be tricky logistically, but also because of e.g. advice from glibc at https://sourceware.org/glibc/wiki/FAQ#What_version_of_the_Linux_kernel_headers_should_be_used.3F.
(I was looking for a tool to easily test this on a machine with a newer kernel and stumbled across the new enosys tool in master, nice!)