Commit cdd9951340 for qemu.org

commit cdd99513409c3d36cbe21d70baeb80fab9852912
Author: TAKANO Mitsuhiro <takano32@gmail.com>
Date:   Sat Oct 31 20:55:00 2026 +0000

    linux-user: allow a zero-length getrandom with a NULL buffer

    The kernel never looks at the buffer of a zero-length request, so
    getrandom(NULL, 0, 0) returns 0.  qemu-user hands the request to
    lock_user() unconditionally, and a NULL or otherwise unusable address
    fails there with EFAULT even though nothing is copied.

    read(), write(), pread64() and pwrite64() already special-case the
    zero-length request; do the same here.  The address plays no part in it:
    with a zero length it is never dereferenced, whatever value the caller
    passes.

    Fixes: f894efd19917 ("linux-user: add getrandom() syscall")
    Signed-off-by: TAKANO Mitsuhiro <takano32@gmail.com>
    Signed-off-by: Helge Deller <deller@gmx.de>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9d85a193ef..59cbf5feaa 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -11456,6 +11456,14 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
 #endif
 #if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
     case TARGET_NR_getrandom:
+        if (arg2 == 0) {
+            /*
+             * A zero-length request has no buffer to lock, and the kernel
+             * never looks at the pointer for it, so pass the call through
+             * instead of failing on a NULL or otherwise unusable address.
+             */
+            return get_errno(getrandom(NULL, 0, arg3));
+        }
         p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
         if (!p) {
             return -TARGET_EFAULT;
diff --git a/tests/tcg/multiarch/linux/linux-null-buffer.c b/tests/tcg/multiarch/linux/linux-null-buffer.c
new file mode 100644
index 0000000000..6246e47707
--- /dev/null
+++ b/tests/tcg/multiarch/linux/linux-null-buffer.c
@@ -0,0 +1,19 @@
+/*
+ * A zero-length getrandom() needs no valid buffer: the kernel never looks at
+ * the pointer, so getrandom(NULL, 0, 0) succeeds.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#define _GNU_SOURCE
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/random.h>
+
+int main(void)
+{
+    errno = 0;
+    assert(getrandom(NULL, 0, 0) == 0);
+
+    return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/multiarch/meson.build b/tests/tcg/multiarch/meson.build
index e60a052700..8f2f57d9ab 100644
--- a/tests/tcg/multiarch/meson.build
+++ b/tests/tcg/multiarch/meson.build
@@ -57,6 +57,7 @@ tests += {
 # Linux tests
 tests += {
   multiarch/'linux/linux-madvise.c': {},
+  multiarch/'linux/linux-null-buffer.c': {},
   multiarch/'linux/linux-shmat-maps.c': {},
   multiarch/'linux/linux-shmat-null.c': {},
   multiarch/'linux/linux-sigrtminmax.c': {},