diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2011-02-22 13:02:26 +0000 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2011-03-06 19:06:27 +0100 |
commit | 0c1592d93585ddce572a71a77534ca765c5f5d34 (patch) | |
tree | 16845c422b05e50130611c851d4e7ac2f115b046 | |
parent | 26883c699eee60c6f2dd63818a9dd470f2c567fc (diff) |
linux-user: Fix large seeks by 32 bit guest on 64 bit host
When emulating a 32 bit Linux user-mode program on a 64 bit target
we implement the llseek syscall in terms of lseek. Correct a bug
which meant we were silently casting the result of host lseek()
to a 32 bit integer as it passed through get_errno() and thus
throwing away the top half.
We also don't try to store the result back to userspace unless
the seek succeeded; this matches the kernel behaviour.
Thanks to Eoghan Sherry for identifying the problem and suggesting
a solution.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
-rw-r--r-- | linux-user/syscall.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cf8a4c3876..23d7a630f5 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6127,16 +6127,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR__llseek /* Not on alpha */ case TARGET_NR__llseek: { + int64_t res; #if !defined(__NR_llseek) - ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5)); - if (put_user_s64(ret, arg4)) - goto efault; + res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5); + if (res == -1) { + ret = get_errno(res); + } else { + ret = 0; + } #else - int64_t res; ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5)); - if (put_user_s64(res, arg4)) - goto efault; #endif + if ((ret == 0) && put_user_s64(res, arg4)) { + goto efault; + } } break; #endif |