summary refs log tree commit diff stats
path: root/linux-user
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-02-17 18:55:33 +0000
committerRiku Voipio <riku.voipio@linaro.org>2014-02-18 16:54:06 +0200
commit501bb4b0cb1debf2b495f0ba3980b97ceca652f5 (patch)
treeabab89c80b5135d4a91e257379de848559dc299c /linux-user
parent3a5d30bf272c8db8e16e1e7ad5b8953f08df3e82 (diff)
downloadfocaccia-qemu-501bb4b0cb1debf2b495f0ba3980b97ceca652f5.tar.gz
focaccia-qemu-501bb4b0cb1debf2b495f0ba3980b97ceca652f5.zip
linux-user: Fix error handling in lock_iovec()
In lock_iovec() if lock_user() failed we were doing an unlock_user
but not a free(vec), which is the wrong way round. We were also
assuming that free() and unlock_user() don't touch errno, which
is not guaranteed. Fix both these problems.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/syscall.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f3700876a3..bb3e4b1641 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1707,6 +1707,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
     struct iovec *vec;
     abi_ulong total_len, max_len;
     int i;
+    int err = 0;
 
     if (count == 0) {
         errno = 0;
@@ -1726,7 +1727,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
     target_vec = lock_user(VERIFY_READ, target_addr,
                            count * sizeof(struct target_iovec), 1);
     if (target_vec == NULL) {
-        errno = EFAULT;
+        err = EFAULT;
         goto fail2;
     }
 
@@ -1740,7 +1741,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
         abi_long len = tswapal(target_vec[i].iov_len);
 
         if (len < 0) {
-            errno = EINVAL;
+            err = EINVAL;
             goto fail;
         } else if (len == 0) {
             /* Zero length pointer is ignored.  */
@@ -1748,7 +1749,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
         } else {
             vec[i].iov_base = lock_user(type, base, len, copy);
             if (!vec[i].iov_base) {
-                errno = EFAULT;
+                err = EFAULT;
                 goto fail;
             }
             if (len > max_len - total_len) {
@@ -1763,9 +1764,10 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
     return vec;
 
  fail:
-    free(vec);
- fail2:
     unlock_user(target_vec, target_addr, 0);
+ fail2:
+    free(vec);
+    errno = err;
     return NULL;
 }