diff mbox

[PULL,v2,30/38] linux-user: Handle msgrcv error case correctly

Message ID 99874f65526ed7827202c6e17c62f30d47652bdd.1464353863.git.riku.voipio@linaro.org
State Accepted
Commit 99874f65526ed7827202c6e17c62f30d47652bdd
Headers show

Commit Message

Riku Voipio May 27, 2016, 1 p.m. UTC
From: Peter Maydell <peter.maydell@linaro.org>


The msgrcv ABI is a bit odd -- the msgsz argument is a size_t, which is
unsigned, but it must fail EINVAL if the value is negative when cast
to a long. We were incorrectly passing the value through an
"unsigned int", which meant that if the guest was 32-bit longs and
the host was 64-bit longs an input of 0xffffffff (which should trigger
EINVAL) would simply be passed to the host msgrcv() as 0xffffffff,
where it does not cause the host kernel to reject it.
Follow the same approach as do_msgsnd() in using a ssize_t and
doing the check for negative values by hand, so we correctly fail
in this corner case.

This fixes the msgrcv03 Linux Test Project test case, which otherwise
hangs.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Signed-off-by: Riku Voipio <riku.voipio@linaro.org>

---
 linux-user/syscall.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

-- 
2.1.4
diff mbox

Patch

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 6c4f5c6..cec5b80 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -3152,7 +3152,7 @@  static inline abi_long do_msgsnd(int msqid, abi_long msgp,
 }
 
 static inline abi_long do_msgrcv(int msqid, abi_long msgp,
-                                 unsigned int msgsz, abi_long msgtyp,
+                                 ssize_t msgsz, abi_long msgtyp,
                                  int msgflg)
 {
     struct target_msgbuf *target_mb;
@@ -3160,6 +3160,10 @@  static inline abi_long do_msgrcv(int msqid, abi_long msgp,
     struct msgbuf *host_mb;
     abi_long ret = 0;
 
+    if (msgsz < 0) {
+        return -TARGET_EINVAL;
+    }
+
     if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
         return -TARGET_EFAULT;