From 79dd77de124c47263f54e5f686273487e0016a8f Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 20 Dec 2012 11:00:11 +0000 Subject: [PATCH 1/4] linux-user: correct msgrcv() All parameters must be swapped before the call of do_msgrcv(). Allow faked (debian fakeroot daemon) to work properly. WITHOUT this patch: $ faked-sysv --foreground --debug using 1723744788 as msg key msg_key=1723744788 1723744788:431 FAKEROOT: msg=131072, key=1723744788 FAKEROOT: r=-1, received message type=-150996052, message=-160219330 FAKEROOT, get_msg: Bad address r=14, EINTR=4 fakeroot: clearing up message queues and semaphores, signal=-1 fakeroot: database save FAILED WITH this patch: $ faked-sysv --foreground --debug using 1569385744 as msg key msg_key=1569385744 1569385744:424 FAKEROOT: msg=0, key=1569385744 ^C fakeroot: clearing up message queues and semaphores, signal=2 fakeroot: database save FAILED Signed-off-by: Laurent Vivier Reviewed-by: Peter Maydell --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 693e66fc4f..a6f42718c8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2897,7 +2897,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, return -TARGET_EFAULT; host_mb = g_malloc(msgsz+sizeof(long)); - ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg)); + ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg)); if (ret > 0) { abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong); @@ -3189,7 +3189,7 @@ static abi_long do_ipc(unsigned int call, int first, break; } - ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third); + ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third); unlock_user_struct(tmp, ptr, 0); break; From 910ee4e5f4a1df5b1bd144dfca1ae466e2a86a78 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 31 Dec 2012 09:45:06 +0000 Subject: [PATCH 2/4] linux-user: correct print_timeval() swap tv_sec and tv_usec Signed-off-by: Laurent Vivier Reviewed-by: Peter Maydell --- linux-user/strace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 6ec90e8974..4e91a6eb9c 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -682,7 +682,7 @@ print_timeval(abi_ulong tv_addr, int last) if (!tv) return; gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}%s", - tv->tv_sec, tv->tv_usec, get_comma(last)); + tswapal(tv->tv_sec), tswapal(tv->tv_usec), get_comma(last)); unlock_user(tv, tv_addr, 0); } else gemu_log("NULL%s", get_comma(last)); From 1b09aeb90827c1d91383a9eae42ce8f25909857b Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 1 Jan 2013 08:24:11 +0000 Subject: [PATCH 3/4] linux-user: correct setsockopt() SO_SNDTIMEO and SO_RCVTIMEO take a struct timeval, not an int To test this, you can use : QEMU_STRACE= ping localhost 2>&1 |grep TIMEO 568 setsockopt(3,SOL_SOCKET,SO_SNDTIMEO,{1,0},8) = 0 568 setsockopt(3,SOL_SOCKET,SO_RCVTIMEO,{1,0},8) = 0 Signed-off-by: Laurent Vivier Reviewed-by: Peter Maydell --- linux-user/syscall.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a6f42718c8..151f4f3272 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1489,6 +1489,28 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, break; case TARGET_SOL_SOCKET: switch (optname) { + case TARGET_SO_RCVTIMEO: + { + struct timeval tv; + + optname = SO_RCVTIMEO; + +set_timeout: + if (optlen != sizeof(struct target_timeval)) { + return -TARGET_EINVAL; + } + + if (copy_from_user_timeval(&tv, optval_addr)) { + return -TARGET_EFAULT; + } + + ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, + &tv, sizeof(tv))); + return ret; + } + case TARGET_SO_SNDTIMEO: + optname = SO_SNDTIMEO; + goto set_timeout; /* Options with 'int' argument. */ case TARGET_SO_DEBUG: optname = SO_DEBUG; @@ -1540,12 +1562,6 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, case TARGET_SO_RCVLOWAT: optname = SO_RCVLOWAT; break; - case TARGET_SO_RCVTIMEO: - optname = SO_RCVTIMEO; - break; - case TARGET_SO_SNDTIMEO: - optname = SO_SNDTIMEO; - break; break; default: goto unimplemented; From c07ecc6866f8c5eb2e0b23ba20214000310355e0 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 7 Jan 2013 11:40:06 +0000 Subject: [PATCH 4/4] linux-user: correct reboot() According to man reboot(2), the 4th argument is only used with LINUX_REBOOT_CMD_RESTART2. In other cases, trying to convert the value can generate EFAULT. Signed-off-by: Laurent Vivier Reviewed-by: Peter Maydell --- linux-user/syscall.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 151f4f3272..08538fc35c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -101,6 +101,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include +#include #include "linux_loop.h" #include "cpu-uname.h" @@ -6451,10 +6452,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_reboot: - if (!(p = lock_user_string(arg4))) - goto efault; - ret = reboot(arg1, arg2, arg3, p); - unlock_user(p, arg4, 0); + if (arg3 == LINUX_REBOOT_CMD_RESTART2) { + /* arg4 must be ignored in all other cases */ + p = lock_user_string(arg4); + if (!p) { + goto efault; + } + ret = get_errno(reboot(arg1, arg2, arg3, p)); + unlock_user(p, arg4, 0); + } else { + ret = get_errno(reboot(arg1, arg2, arg3, NULL)); + } break; #ifdef TARGET_NR_readdir case TARGET_NR_readdir: