aboutsummaryrefslogtreecommitdiff
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
authorTom Musta <tommusta@gmail.com>2014-08-12 13:53:43 -0500
committerRiku Voipio <riku.voipio@linaro.org>2014-08-22 15:06:35 +0300
commit29560a6cb7a7a705de3d7dfb44e8b1c0a12ad37d (patch)
tree7fcffede3c3aaab25b041acd671920af4adc63d9 /linux-user/syscall.c
parent6f6a40328b6f4679082583c2b3a949cda451a991 (diff)
linux-user: writev Partial Writes
Although not technically not required by POSIX, the writev system call will typically write out its buffers individually. That is, if the first buffer is written successfully, but the second buffer pointer is invalid, then the first chuck will be written and its size is returned. Signed-off-by: Tom Musta <tommusta@gmail.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 1da216e2fb..ebdc70e4ca 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1803,6 +1803,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
abi_ulong total_len, max_len;
int i;
int err = 0;
+ bool bad_address = false;
if (count == 0) {
errno = 0;
@@ -1843,9 +1844,20 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
vec[i].iov_base = 0;
} else {
vec[i].iov_base = lock_user(type, base, len, copy);
+ /* If the first buffer pointer is bad, this is a fault. But
+ * subsequent bad buffers will result in a partial write; this
+ * is realized by filling the vector with null pointers and
+ * zero lengths. */
if (!vec[i].iov_base) {
- err = EFAULT;
- goto fail;
+ if (i == 0) {
+ err = EFAULT;
+ goto fail;
+ } else {
+ bad_address = true;
+ }
+ }
+ if (bad_address) {
+ len = 0;
}
if (len > max_len - total_len) {
len = max_len - total_len;