linux-user/strace.list | 3 +++ linux-user/syscall.c | 44 +++++++++++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 13 ++++++++++++ 3 files changed, 60 insertions(+)
mount_setattr() was in the syscall tables but had no implementation, so
guests always got -ENOSYS. systemd uses it when setting up per-unit
credential mounts, which fails the affected units with EXIT_CREDENTIALS.
struct mount_attr is an extensible struct like open_how, so handle it the
same way openat2() does: reject sizes smaller than the ver0 struct and
require any unknown trailing bytes to be zero. All of its fields are
64-bit, and the MOUNT_ATTR_* and MS_* propagation values are identical on
every target, so only the byte order needs fixing up.
Signed-off-by: Matt Turner <mattst88@gmail.com>
---
linux-user/strace.list | 3 +++
linux-user/syscall.c | 44 +++++++++++++++++++++++++++++++++++++++
linux-user/syscall_defs.h | 13 ++++++++++++
3 files changed, 60 insertions(+)
diff --git ./linux-user/strace.list ./linux-user/strace.list
index 25ace05187..e952f15d20 100644
--- ./linux-user/strace.list
+++ ./linux-user/strace.list
@@ -1737,3 +1737,6 @@
#ifdef TARGET_NR_fspick
{ TARGET_NR_fspick, "fspick", "%s(%d,%s,%d)", NULL, NULL },
#endif
+#ifdef TARGET_NR_mount_setattr
+{ TARGET_NR_mount_setattr, "mount_setattr", "%s(%d,%s,%d,%p,%d)", NULL, NULL },
+#endif
diff --git ./linux-user/syscall.c ./linux-user/syscall.c
index dc028686f4..cfa68dfbdb 100644
--- ./linux-user/syscall.c
+++ ./linux-user/syscall.c
@@ -9735,6 +9735,13 @@ _syscall5(int, sys_move_mount, int, __from_dfd, const char *, __from_pathname,
int, __to_dfd, const char *, __to_pathname, unsigned int, flag)
#endif
+#if defined(TARGET_NR_mount_setattr) && defined(__NR_mount_setattr)
+#define __NR_sys_mount_setattr __NR_mount_setattr
+_syscall5(int, sys_mount_setattr, int, dfd, const char *, path,
+ unsigned int, flags, struct mount_attr_ver0 *, uattr,
+ size_t, usize)
+#endif
+
#if defined(TARGET_NR_fsopen) && defined(__NR_fsopen)
#define __NR_sys_fsopen __NR_fsopen
_syscall2(int, sys_fsopen, const char *, fs_name, unsigned int, flags);
@@ -14480,6 +14487,43 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return do_map_shadow_stack(cpu_env, arg1, arg2, arg3);
#endif
+#if defined(TARGET_NR_mount_setattr) && defined(__NR_mount_setattr)
+ case TARGET_NR_mount_setattr:
+ {
+ struct mount_attr_ver0 attr = {};
+ abi_ulong usize = arg5;
+
+ if (usize < sizeof(struct target_mount_attr_ver0)) {
+ return -TARGET_EINVAL;
+ }
+ ret = copy_struct_from_user(&attr, sizeof(attr), arg4, usize);
+ if (ret) {
+ if (ret == -TARGET_E2BIG) {
+ qemu_log_mask(LOG_UNIMP,
+ "Unimplemented mount_setattr mount_attr "
+ "size: " TARGET_ABI_FMT_lu "\n", usize);
+ }
+ return ret;
+ }
+ /*
+ * MOUNT_ATTR_* and the MS_* propagation flags have the same
+ * values on all targets, so only byte order needs fixing up.
+ */
+ attr.attr_set = tswap64(attr.attr_set);
+ attr.attr_clr = tswap64(attr.attr_clr);
+ attr.propagation = tswap64(attr.propagation);
+ attr.userns_fd = tswap64(attr.userns_fd);
+
+ p = lock_user_string(arg2);
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(sys_mount_setattr(arg1, p, arg3, &attr,
+ sizeof(attr)));
+ unlock_user(p, arg2, 0);
+ }
+ return ret;
+#endif
#if defined(TARGET_NR_fsopen) && defined(__NR_fsopen)
case TARGET_NR_fsopen:
{
diff --git ./linux-user/syscall_defs.h ./linux-user/syscall_defs.h
index e033c7db34..e28853c93b 100644
--- ./linux-user/syscall_defs.h
+++ ./linux-user/syscall_defs.h
@@ -2770,6 +2770,19 @@ struct target_open_how_ver0 {
abi_ullong mode;
abi_ullong resolve;
};
+/* from kernel's include/uapi/linux/mount.h */
+struct mount_attr_ver0 {
+ uint64_t attr_set;
+ uint64_t attr_clr;
+ uint64_t propagation;
+ uint64_t userns_fd;
+};
+struct target_mount_attr_ver0 {
+ abi_ullong attr_set;
+ abi_ullong attr_clr;
+ abi_ullong propagation;
+ abi_ullong userns_fd;
+};
#ifndef RESOLVE_NO_MAGICLINKS
#define RESOLVE_NO_MAGICLINKS 0x02
#endif
--
2.54.0
On 8/5/26 19:16, Matt Turner wrote: > mount_setattr() was in the syscall tables but had no implementation, so > guests always got -ENOSYS. systemd uses it when setting up per-unit > credential mounts, which fails the affected units with EXIT_CREDENTIALS. > > struct mount_attr is an extensible struct like open_how, so handle it the > same way openat2() does: reject sizes smaller than the ver0 struct and > require any unknown trailing bytes to be zero. All of its fields are > 64-bit, and the MOUNT_ATTR_* and MS_* propagation values are identical on > every target, so only the byte order needs fixing up. > > Signed-off-by: Matt Turner <mattst88@gmail.com> > --- > linux-user/strace.list | 3 +++ > linux-user/syscall.c | 44 +++++++++++++++++++++++++++++++++++++++ > linux-user/syscall_defs.h | 13 ++++++++++++ > 3 files changed, 60 insertions(+) Reviewed-by: Helge Deller <deller@gmx.de> I'll queue that patch (and the others) up for after qemu-v11.1 has been released. Thanks! Helge
© 2016 - 2026 Red Hat, Inc.