From: Clayton Craft <[email protected]>

Linux 6.12 added AT_HANDLE_MNT_ID_UNIQUE, which indicates that mount_id
is 64-bits. If name_to_handle_at is called with this flag set then qemu
passes a 4 byte int to the kernel, which then tries to store 8 bytes in
a 4 byte variable, causing a SIGSEGV[1][2].

This stores mount_id in a 64-bit var if the flag is set.

1. https://gitlab.postmarketos.org/postmarketOS/pmaports/-/work_items/4431
2. https://github.com/systemd/systemd/issues/41279

Signed-off-by: Clayton Craft <[email protected]>
Reviewed-by: Helge Deller <[email protected]>
Message-id: [email protected]
Signed-off-by: Peter Maydell <[email protected]>
(cherry picked from commit 22966937f4130278259a79d6462d1a0887e22c6e)
Signed-off-by: Michael Tokarev <[email protected]>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e6dd35d2a1..3f61dd732c 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8040,6 +8040,9 @@ static int do_futex(CPUState *cpu, bool time64, 
target_ulong uaddr,
 #endif
 
 #if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
+#ifndef AT_HANDLE_MNT_ID_UNIQUE
+#define AT_HANDLE_MNT_ID_UNIQUE 0x001
+#endif
 static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
                                      abi_long handle, abi_long mount_id,
                                      abi_long flags)
@@ -8047,6 +8050,7 @@ static abi_long do_name_to_handle_at(abi_long dirfd, 
abi_long pathname,
     struct file_handle *target_fh;
     struct file_handle *fh;
     int mid = 0;
+    uint64_t mid64 = 0;
     abi_long ret;
     char *name;
     unsigned int size, total_size;
@@ -8070,7 +8074,12 @@ static abi_long do_name_to_handle_at(abi_long dirfd, 
abi_long pathname,
     fh = g_malloc0(total_size);
     fh->handle_bytes = size;
 
-    ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
+    if (flags & AT_HANDLE_MNT_ID_UNIQUE) {
+        ret = get_errno(name_to_handle_at(dirfd, path(name), fh,
+                                          (int *)&mid64, flags));
+    } else {
+        ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
+    }
     unlock_user(name, pathname, 0);
 
     /* man name_to_handle_at(2):
@@ -8084,8 +8093,14 @@ static abi_long do_name_to_handle_at(abi_long dirfd, 
abi_long pathname,
     g_free(fh);
     unlock_user(target_fh, handle, total_size);
 
-    if (put_user_s32(mid, mount_id)) {
-        return -TARGET_EFAULT;
+    if (flags & AT_HANDLE_MNT_ID_UNIQUE) {
+        if (put_user_u64(mid64, mount_id)) {
+            return -TARGET_EFAULT;
+        }
+    } else {
+        if (put_user_s32(mid, mount_id)) {
+            return -TARGET_EFAULT;
+        }
     }
 
     return ret;
-- 
2.47.3


Reply via email to