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:
parent
3a5d30bf27
commit
501bb4b0cb
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user