12e66bb
From: Peter Maydell <peter.maydell@linaro.org>
12e66bb
Date: Tue, 8 Jan 2019 18:49:00 +0000
12e66bb
Subject: [PATCH] linux-user: make pwrite64/pread64(fd, NULL, 0, offset) return
12e66bb
 0
12e66bb
MIME-Version: 1.0
12e66bb
Content-Type: text/plain; charset=UTF-8
12e66bb
Content-Transfer-Encoding: 8bit
12e66bb
12e66bb
Linux returns success if pwrite64() or pread64() are called with a
12e66bb
zero length NULL buffer, but QEMU was returning -TARGET_EFAULT.
12e66bb
12e66bb
This is the same bug that we fixed in commit 58cfa6c2e6eb51b23cc9
12e66bb
for the write syscall, and long before that in 38d840e6790c29f59
12e66bb
for the read syscall.
12e66bb
12e66bb
Fixes: https://bugs.launchpad.net/qemu/+bug/1810433
12e66bb
12e66bb
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12e66bb
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
12e66bb
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12e66bb
Message-Id: <20190108184900.9654-1-peter.maydell@linaro.org>
12e66bb
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
12e66bb
(cherry picked from commit 2bd3f8998e1e7dcd9afc29fab252fb9936f9e956)
12e66bb
---
12e66bb
 linux-user/syscall.c | 22 ++++++++++++++++++----
12e66bb
 1 file changed, 18 insertions(+), 4 deletions(-)
12e66bb
12e66bb
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
12e66bb
index 280137da8c..b13a170e52 100644
12e66bb
--- a/linux-user/syscall.c
12e66bb
+++ b/linux-user/syscall.c
12e66bb
@@ -9677,8 +9677,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
12e66bb
             arg4 = arg5;
12e66bb
             arg5 = arg6;
12e66bb
         }
12e66bb
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
12e66bb
-            return -TARGET_EFAULT;
12e66bb
+        if (arg2 == 0 && arg3 == 0) {
12e66bb
+            /* Special-case NULL buffer and zero length, which should succeed */
12e66bb
+            p = 0;
12e66bb
+        } else {
12e66bb
+            p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
12e66bb
+            if (!p) {
12e66bb
+                return -TARGET_EFAULT;
12e66bb
+            }
12e66bb
+        }
12e66bb
         ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
12e66bb
         unlock_user(p, arg2, ret);
12e66bb
         return ret;
12e66bb
@@ -9687,8 +9694,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
12e66bb
             arg4 = arg5;
12e66bb
             arg5 = arg6;
12e66bb
         }
12e66bb
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
12e66bb
-            return -TARGET_EFAULT;
12e66bb
+        if (arg2 == 0 && arg3 == 0) {
12e66bb
+            /* Special-case NULL buffer and zero length, which should succeed */
12e66bb
+            p = 0;
12e66bb
+        } else {
12e66bb
+            p = lock_user(VERIFY_READ, arg2, arg3, 1);
12e66bb
+            if (!p) {
12e66bb
+                return -TARGET_EFAULT;
12e66bb
+            }
12e66bb
+        }
12e66bb
         ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
12e66bb
         unlock_user(p, arg2, 0);
12e66bb
         return ret;