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>
This commit is contained in:
Peter Maydell 2014-02-17 18:55:33 +00:00 committed by Riku Voipio
parent 3a5d30bf27
commit 501bb4b0cb

View File

@ -1707,6 +1707,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
struct iovec *vec; struct iovec *vec;
abi_ulong total_len, max_len; abi_ulong total_len, max_len;
int i; int i;
int err = 0;
if (count == 0) { if (count == 0) {
errno = 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, target_vec = lock_user(VERIFY_READ, target_addr,
count * sizeof(struct target_iovec), 1); count * sizeof(struct target_iovec), 1);
if (target_vec == NULL) { if (target_vec == NULL) {
errno = EFAULT; err = EFAULT;
goto fail2; 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); abi_long len = tswapal(target_vec[i].iov_len);
if (len < 0) { if (len < 0) {
errno = EINVAL; err = EINVAL;
goto fail; goto fail;
} else if (len == 0) { } else if (len == 0) {
/* Zero length pointer is ignored. */ /* Zero length pointer is ignored. */
@ -1748,7 +1749,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
} else { } else {
vec[i].iov_base = lock_user(type, base, len, copy); vec[i].iov_base = lock_user(type, base, len, copy);
if (!vec[i].iov_base) { if (!vec[i].iov_base) {
errno = EFAULT; err = EFAULT;
goto fail; goto fail;
} }
if (len > max_len - total_len) { if (len > max_len - total_len) {
@ -1763,9 +1764,10 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
return vec; return vec;
fail: fail:
free(vec);
fail2:
unlock_user(target_vec, target_addr, 0); unlock_user(target_vec, target_addr, 0);
fail2:
free(vec);
errno = err;
return NULL; return NULL;
} }