Skip to content

mount tries to use mount_setattr even if unsupported by running kernel (<5.12) #2247

@thesamesam

Description

@thesamesam

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!)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions