aboutsummaryrefslogtreecommitdiff
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-05-19 12:01:40 +0100
committerRiku Voipio <riku.voipio@linaro.org>2016-05-27 14:50:39 +0300
commitc7e35da348e2e4df072e6979c48fa5283e07d1db (patch)
treebd505d5a61f849629c32ffa1a770d5a9f456f9fc /linux-user/syscall.c
parentd509eeb13c9c6fef4a29ca43c64f591d8c61d201 (diff)
linux-user: Handle negative values in timespec conversion
In a struct timespec, both fields are signed longs. Converting them from guest to host with code like host_ts->tv_sec = tswapal(target_ts->tv_sec); mishandles negative values if the guest has 32-bit longs and the host has 64-bit longs because tswapal()'s return type is abi_ulong: the assignment will zero-extend into the host long type rather than sign-extending it. Make the conversion routines use __get_user() and __set_user() instead: this automatically picks up the signedness of the field type and does the correct kind of sign or zero extension. It also handles the possibility that the target struct is not sufficiently aligned for the host's requirements. In particular, this fixes a hang when running the Linux Test Project mq_timedsend01 and mq_timedreceive01 tests: one of the test cases sets the timeout to -1 and expects an EINVAL failure, but we were setting a very long timeout instead. Signed-off-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.c8
1 files changed, 4 insertions, 4 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 4e419fb18a..6c4f5c6907 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5194,8 +5194,8 @@ static inline abi_long target_to_host_timespec(struct timespec *host_ts,
if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
return -TARGET_EFAULT;
- host_ts->tv_sec = tswapal(target_ts->tv_sec);
- host_ts->tv_nsec = tswapal(target_ts->tv_nsec);
+ __get_user(host_ts->tv_sec, &target_ts->tv_sec);
+ __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
unlock_user_struct(target_ts, target_addr, 0);
return 0;
}
@@ -5207,8 +5207,8 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr,
if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
return -TARGET_EFAULT;
- target_ts->tv_sec = tswapal(host_ts->tv_sec);
- target_ts->tv_nsec = tswapal(host_ts->tv_nsec);
+ __put_user(host_ts->tv_sec, &target_ts->tv_sec);
+ __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
unlock_user_struct(target_ts, target_addr, 1);
return 0;
}