diff options
-rw-r--r-- | linux-user/syscall.c | 61 |
1 files changed, 57 insertions, 4 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 280137da8c..d6605b8b50 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2352,6 +2352,45 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, break; } break; + case SOL_IPV6: + switch (optname) { + case IPV6_MTU_DISCOVER: + case IPV6_MTU: + case IPV6_V6ONLY: + case IPV6_RECVPKTINFO: + case IPV6_UNICAST_HOPS: + case IPV6_MULTICAST_HOPS: + case IPV6_MULTICAST_LOOP: + case IPV6_RECVERR: + case IPV6_RECVHOPLIMIT: + case IPV6_2292HOPLIMIT: + case IPV6_CHECKSUM: + if (get_user_u32(len, optlen)) + return -TARGET_EFAULT; + if (len < 0) + return -TARGET_EINVAL; + lv = sizeof(lv); + ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); + if (ret < 0) + return ret; + if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { + len = 1; + if (put_user_u32(len, optlen) + || put_user_u8(val, optval_addr)) + return -TARGET_EFAULT; + } else { + if (len > sizeof(int)) + len = sizeof(int); + if (put_user_u32(len, optlen) + || put_user_u32(val, optval_addr)) + return -TARGET_EFAULT; + } + break; + default: + ret = -TARGET_ENOPROTOOPT; + break; + } + break; default: unimplemented: gemu_log("getsockopt level=%d optname=%d not yet supported\n", @@ -9677,8 +9716,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, arg4 = arg5; arg5 = arg6; } - if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) - return -TARGET_EFAULT; + if (arg2 == 0 && arg3 == 0) { + /* Special-case NULL buffer and zero length, which should succeed */ + p = 0; + } else { + p = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (!p) { + return -TARGET_EFAULT; + } + } ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5))); unlock_user(p, arg2, ret); return ret; @@ -9687,8 +9733,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, arg4 = arg5; arg5 = arg6; } - if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) - return -TARGET_EFAULT; + if (arg2 == 0 && arg3 == 0) { + /* Special-case NULL buffer and zero length, which should succeed */ + p = 0; + } else { + p = lock_user(VERIFY_READ, arg2, arg3, 1); + if (!p) { + return -TARGET_EFAULT; + } + } ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5))); unlock_user(p, arg2, 0); return ret; |