linux-user/syscall.c | 50 +++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-)
From: Helge Deller <deller@gmx.de>
Some programs test availability of socket options by asking for the
value with an NULL optval address, which currenrly always trigger an
EFAULT in qemu. Fix it by allowing a NULL address, in the same manner
as the Linux kernel on physical machines.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/2390
Signed-off-by: Helge Deller <deller@gmx.de>
---
linux-user/syscall.c | 50 +++++++++++++++++++++++++-------------------
1 file changed, 28 insertions(+), 22 deletions(-)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 4594909242..d68edb7afd 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2644,6 +2644,10 @@ get_timeout:
if (ret < 0) {
return ret;
}
+ /* special case: destination address is NULL, return 0 */
+ if (optval_addr) {
+ len = 0;
+ }
if (len == sizeof(struct target__kernel_sock_timeval)) {
if (copy_to_user_timeval64(optval_addr, &tv)) {
return -TARGET_EFAULT;
@@ -2844,7 +2848,10 @@ get_timeout:
}
if (len > lv)
len = lv;
- if (len == 4) {
+ if (!optval_addr) {
+ /* writing to NULL does not give error */
+ len = 0;
+ } else if (len == 4) {
if (put_user_u32(val, optval_addr))
return -TARGET_EFAULT;
} else {
@@ -2877,18 +2884,24 @@ get_timeout:
return -TARGET_EINVAL;
lv = sizeof(lv);
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
+write_ret:
if (ret < 0)
return ret;
- if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
+ if (!optval_addr) {
+ len = 0;
+ } else if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
len = 1;
- if (put_user_u32(len, optlen)
- || put_user_u8(val, optval_addr))
+ if (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))
+ if (put_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ }
+ if (put_user_u32(len, optlen)) {
return -TARGET_EFAULT;
}
break;
@@ -2939,20 +2952,7 @@ get_timeout:
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;
- }
+ goto write_ret;
break;
default:
ret = -TARGET_ENOPROTOOPT;
@@ -2986,8 +2986,14 @@ get_timeout:
if (ret < 0) {
return ret;
}
- if (put_user_u32(lv, optlen)
- || put_user_u32(val, optval_addr)) {
+ if (optval_addr) {
+ if (put_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ } else {
+ lv = 0;
+ }
+ if (put_user_u32(lv, optlen)) {
return -TARGET_EFAULT;
}
break;
--
2.53.0
On 4/28/2026 2:46 PM, Helge Deller wrote: > From: Helge Deller <deller@gmx.de> > > Some programs test availability of socket options by asking for the > value with an NULL optval address, which currenrly always trigger an > EFAULT in qemu. Fix it by allowing a NULL address, in the same manner > as the Linux kernel on physical machines. > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/2390 > Signed-off-by: Helge Deller <deller@gmx.de> > --- > linux-user/syscall.c | 50 +++++++++++++++++++++++++------------------- > 1 file changed, 28 insertions(+), 22 deletions(-) > Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
© 2016 - 2026 Red Hat, Inc.