linux-user/alpha/sockbits.h | 8 ++++-- linux-user/generic/sockbits.h | 8 ++++-- linux-user/hppa/sockbits.h | 8 ++++-- linux-user/mips/sockbits.h | 8 ++++-- linux-user/ppc/sockbits.h | 8 +++--- linux-user/sparc/sockbits.h | 8 ++++-- linux-user/strace.c | 6 +++-- linux-user/syscall.c | 47 +++++++++++++++++++++-------------- 8 files changed, 67 insertions(+), 34 deletions(-)
Linux kernel has redefined some socket options values and
introduces y2038 safe code paths on 32-bit architectures.
See include/uapi/asm-generic/socket.h in the kernel sources.
The argument for SO_RCVTIMEO_NEW (66) SO_SNDTIMEO_NEW (67) is
struct __kernel_sock_timeval which always comprises two 64-bit
fields regardless of the architecture.
Unlike the kernel QEMU needs to support both old and new values
so SO_SNDTIME and SO_RCVTIMEO have been renamed to *_OLD,
but neither old nor new values have been marked as "default".
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
v2:
- added missing TARGET_ prefix in header files
linux-user/alpha/sockbits.h | 8 ++++--
linux-user/generic/sockbits.h | 8 ++++--
linux-user/hppa/sockbits.h | 8 ++++--
linux-user/mips/sockbits.h | 8 ++++--
linux-user/ppc/sockbits.h | 8 +++---
linux-user/sparc/sockbits.h | 8 ++++--
linux-user/strace.c | 6 +++--
linux-user/syscall.c | 47 +++++++++++++++++++++--------------
8 files changed, 67 insertions(+), 34 deletions(-)
diff --git a/linux-user/alpha/sockbits.h b/linux-user/alpha/sockbits.h
index d54dc98c09..114e808693 100644
--- a/linux-user/alpha/sockbits.h
+++ b/linux-user/alpha/sockbits.h
@@ -28,8 +28,8 @@
#define TARGET_SO_RCVBUFFORCE 0x100b
#define TARGET_SO_RCVLOWAT 0x1010
#define TARGET_SO_SNDLOWAT 0x1011
-#define TARGET_SO_RCVTIMEO 0x1012
-#define TARGET_SO_SNDTIMEO 0x1013
+#define TARGET_SO_RCVTIMEO_OLD 0x1012
+#define TARGET_SO_SNDTIMEO_OLD 0x1013
#define TARGET_SO_ACCEPTCONN 0x1014
#define TARGET_SO_PROTOCOL 0x1028
#define TARGET_SO_DOMAIN 0x1029
@@ -75,6 +75,10 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define TARGET_SO_NOFCS 43
+/* New socket timeout options that are y2038 safe. */
+#define TARGET_SO_RCVTIMEO_NEW 66
+#define TARGET_SO_SNDTIMEO_NEW 67
+
/* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
*/
diff --git a/linux-user/generic/sockbits.h b/linux-user/generic/sockbits.h
index b3b4a8e44c..7b78b9dcaa 100644
--- a/linux-user/generic/sockbits.h
+++ b/linux-user/generic/sockbits.h
@@ -34,8 +34,8 @@
#define TARGET_SO_PEERCRED 17
#define TARGET_SO_RCVLOWAT 18
#define TARGET_SO_SNDLOWAT 19
-#define TARGET_SO_RCVTIMEO 20
-#define TARGET_SO_SNDTIMEO 21
+#define TARGET_SO_RCVTIMEO_OLD 20
+#define TARGET_SO_SNDTIMEO_OLD 21
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define TARGET_SO_SECURITY_AUTHENTICATION 22
@@ -58,4 +58,8 @@
#define TARGET_SO_PROTOCOL 38
#define TARGET_SO_DOMAIN 39
+
+/* New socket timeout options that are y2038 safe. */
+#define TARGET_SO_RCVTIMEO_NEW 66
+#define TARGET_SO_SNDTIMEO_NEW 67
#endif
diff --git a/linux-user/hppa/sockbits.h b/linux-user/hppa/sockbits.h
index 23f69a3293..bb98a8c8be 100644
--- a/linux-user/hppa/sockbits.h
+++ b/linux-user/hppa/sockbits.h
@@ -17,8 +17,8 @@
#define TARGET_SO_RCVBUFFORCE 0x100b
#define TARGET_SO_SNDLOWAT 0x1003
#define TARGET_SO_RCVLOWAT 0x1004
-#define TARGET_SO_SNDTIMEO 0x1005
-#define TARGET_SO_RCVTIMEO 0x1006
+#define TARGET_SO_SNDTIMEO_OLD 0x1005
+#define TARGET_SO_RCVTIMEO_OLD 0x1006
#define TARGET_SO_ERROR 0x1007
#define TARGET_SO_TYPE 0x1008
#define TARGET_SO_PROTOCOL 0x1028
@@ -67,6 +67,10 @@
#define TARGET_SO_CNX_ADVICE 0x402E
+/* New socket timeout options that are y2038 safe. */
+#define TARGET_SO_RCVTIMEO_NEW 0x4040
+#define TARGET_SO_SNDTIMEO_NEW 0x4041
+
/* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
*/
diff --git a/linux-user/mips/sockbits.h b/linux-user/mips/sockbits.h
index 562cad88e2..11d25a5066 100644
--- a/linux-user/mips/sockbits.h
+++ b/linux-user/mips/sockbits.h
@@ -37,8 +37,8 @@
#define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */
#define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */
#define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */
-#define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */
-#define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */
+#define TARGET_SO_SNDTIMEO_OLD 0x1005 /* send timeout */
+#define TARGET_SO_RCVTIMEO_OLD 0x1006 /* receive timeout */
#define TARGET_SO_ACCEPTCONN 0x1009
#define TARGET_SO_PROTOCOL 0x1028 /* protocol type */
#define TARGET_SO_DOMAIN 0x1029 /* domain/socket family */
@@ -71,6 +71,10 @@
#define TARGET_SO_RCVBUFFORCE 33
#define TARGET_SO_PASSSEC 34
+/* New socket timeout options that are y2038 safe. */
+#define TARGET_SO_RCVTIMEO_NEW 66
+#define TARGET_SO_SNDTIMEO_NEW 67
+
/** sock_type - Socket types
*
* Please notice that for binary compat reasons MIPS has to
diff --git a/linux-user/ppc/sockbits.h b/linux-user/ppc/sockbits.h
index ee453347a3..25455a948e 100644
--- a/linux-user/ppc/sockbits.h
+++ b/linux-user/ppc/sockbits.h
@@ -14,10 +14,10 @@
#define TARGET_SO_RCVLOWAT 16
#undef TARGET_SO_SNDLOWAT
#define TARGET_SO_SNDLOWAT 17
-#undef TARGET_SO_RCVTIMEO
-#define TARGET_SO_RCVTIMEO 18
-#undef TARGET_SO_SNDTIMEO
-#define TARGET_SO_SNDTIMEO 19
+#undef TARGET_SO_RCVTIMEO_OLD
+#define TARGET_SO_RCVTIMEO_OLD 18
+#undef TARGET_SO_SNDTIMEO_OLD
+#define TARGET_SO_SNDTIMEO_OLD 19
#undef TARGET_SO_PASSCRED
#define TARGET_SO_PASSCRED 20
#undef TARGET_SO_PEERCRED
diff --git a/linux-user/sparc/sockbits.h b/linux-user/sparc/sockbits.h
index 0a822e3e1f..8fce0e5373 100644
--- a/linux-user/sparc/sockbits.h
+++ b/linux-user/sparc/sockbits.h
@@ -24,8 +24,8 @@
#define TARGET_SO_BSDCOMPAT 0x0400
#define TARGET_SO_RCVLOWAT 0x0800
#define TARGET_SO_SNDLOWAT 0x1000
-#define TARGET_SO_RCVTIMEO 0x2000
-#define TARGET_SO_SNDTIMEO 0x4000
+#define TARGET_SO_RCVTIMEO_OLD 0x2000
+#define TARGET_SO_SNDTIMEO_OLD 0x4000
#define TARGET_SO_ACCEPTCONN 0x8000
#define TARGET_SO_SNDBUF 0x1001
@@ -104,6 +104,10 @@
#define TARGET_SO_ZEROCOPY 0x003e
+/* New socket timeout options that are y2038 safe. */
+#define TARGET_SO_RCVTIMEO_NEW 0x0044
+#define TARGET_SO_SNDTIMEO_NEW 0x0045
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define TARGET_SO_SECURITY_AUTHENTICATION 0x5001
#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 1233ebceb0..9639d47d70 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -2970,11 +2970,13 @@ print_optint:
case TARGET_SO_RCVLOWAT:
qemu_log("SO_RCVLOWAT,");
goto print_optint;
- case TARGET_SO_RCVTIMEO:
+ case TARGET_SO_RCVTIMEO_OLD:
+ case TARGET_SO_RCVTIMEO_NEW:
qemu_log("SO_RCVTIMEO,");
print_timeval(optval, 0);
break;
- case TARGET_SO_SNDTIMEO:
+ case TARGET_SO_SNDTIMEO_OLD:
+ case TARGET_SO_SNDTIMEO_NEW:
qemu_log("SO_SNDTIMEO,");
print_timeval(optval, 0);
break;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 91360a072c..fb37b516db 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1132,7 +1132,8 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
return 0;
}
-#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME)
+#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME) || \
+ defined(TARGET_NR_getsockopt) || defined(TARGET_NR_setsockopt)
static inline abi_long copy_from_user_timeval64(struct timeval *tv,
abi_ulong target_tv_addr)
{
@@ -2358,21 +2359,28 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
#endif
case TARGET_SOL_SOCKET:
switch (optname) {
- case TARGET_SO_RCVTIMEO:
- case TARGET_SO_SNDTIMEO:
+ case TARGET_SO_RCVTIMEO_OLD:
+ case TARGET_SO_SNDTIMEO_OLD:
+ case TARGET_SO_RCVTIMEO_NEW:
+ case TARGET_SO_SNDTIMEO_NEW:
{
struct timeval tv;
+ bool old_timeval = (optname == TARGET_SO_RCVTIMEO_OLD ||
+ optname == TARGET_SO_SNDTIMEO_OLD);
- if (optlen != sizeof(struct target_timeval)) {
+ if (optlen != (old_timeval ? sizeof(struct target_timeval) : \
+ sizeof(struct target__kernel_sock_timeval))) {
return -TARGET_EINVAL;
}
- if (copy_from_user_timeval(&tv, optval_addr)) {
+ if ((old_timeval && copy_from_user_timeval(&tv, optval_addr)) ||
+ (!old_timeval && copy_from_user_timeval64(&tv, optval_addr))) {
return -TARGET_EFAULT;
}
ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
- optname == TARGET_SO_RCVTIMEO ?
+ optname == TARGET_SO_RCVTIMEO_OLD || \
+ optname == TARGET_SO_RCVTIMEO_NEW ?
SO_RCVTIMEO : SO_SNDTIMEO,
&tv, sizeof(tv)));
return ret;
@@ -2590,13 +2598,16 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
/* These don't just return a single integer */
case TARGET_SO_PEERNAME:
goto unimplemented;
- case TARGET_SO_RCVTIMEO: {
+ case TARGET_SO_RCVTIMEO_OLD:
+ case TARGET_SO_RCVTIMEO_NEW:
+ case TARGET_SO_SNDTIMEO_OLD:
+ case TARGET_SO_SNDTIMEO_NEW:
+ {
struct timeval tv;
socklen_t tvlen;
+ bool old_timeval = (optname == TARGET_SO_RCVTIMEO_OLD ||
+ optname == TARGET_SO_SNDTIMEO_OLD);
- optname = SO_RCVTIMEO;
-
-get_timeout:
if (get_user_u32(len, optlen)) {
return -TARGET_EFAULT;
}
@@ -2605,15 +2616,18 @@ get_timeout:
}
tvlen = sizeof(tv);
- ret = get_errno(getsockopt(sockfd, level, optname,
+ ret = get_errno(getsockopt(sockfd, level,
+ optname == TARGET_SO_RCVTIMEO_OLD || \
+ optname == TARGET_SO_RCVTIMEO_NEW ?
+ SO_RCVTIMEO : SO_SNDTIMEO,
&tv, &tvlen));
if (ret < 0) {
return ret;
}
- if (len > sizeof(struct target_timeval)) {
- len = sizeof(struct target_timeval);
- }
- if (copy_to_user_timeval(optval_addr, &tv)) {
+ len = MIN(len, (old_timeval ? sizeof(struct target_timeval) : \
+ sizeof(struct target__kernel_sock_timeval)));
+ if ((old_timeval && copy_to_user_timeval(optval_addr, &tv)) ||
+ (!old_timeval && copy_to_user_timeval64(optval_addr, &tv))) {
return -TARGET_EFAULT;
}
if (put_user_u32(len, optlen)) {
@@ -2621,9 +2635,6 @@ get_timeout:
}
break;
}
- case TARGET_SO_SNDTIMEO:
- optname = SO_SNDTIMEO;
- goto get_timeout;
case TARGET_SO_PEERCRED: {
struct ucred cr;
socklen_t crlen;
--
2.39.5
© 2016 - 2025 Red Hat, Inc.