|
|
Message-ID: <20261102165837.24591-8-kaloz@kernel.org>
Date: Mon, 2 Nov 2026 17:58:34 +0100
From: Imre Kaloz <kaloz@...nel.org>
To: musl@...ts.openwall.com
Subject: [PATCH 07/10] convert kernel timevals where suseconds_t is 32-bit
sparc64's kernel has a 32-bit suseconds_t, so its struct timeval is
{long, int}. These syscalls passed musl's struct timeval through
unchanged when time_t and long have the same width, which on
big-endian sparc64 puts tv_usec in the wrong half. SIOCGSTAMP returns
the same layout. SO_TIMESTAMP needs Linux 5.1 or later, since
recvmsg's conversion of the old timestamp assumes two longs.
---
src/internal/syscall.h | 5 +++++
src/linux/clock_adjtime.c | 18 ++++++++++++++++++
src/linux/wait4.c | 10 ++++++++++
src/misc/getrusage.c | 10 ++++++++++
src/misc/ioctl.c | 12 ++++++++++++
src/network/getsockopt.c | 13 +++++++++++++
src/network/setsockopt.c | 6 ++++++
src/select/select.c | 5 +++++
src/signal/getitimer.c | 12 ++++++++++++
src/signal/setitimer.c | 18 ++++++++++++++++++
10 files changed, 109 insertions(+)
diff --git a/src/internal/syscall.h b/src/internal/syscall.h
index 236fb68d..32ef6a05 100644
--- a/src/internal/syscall.h
+++ b/src/internal/syscall.h
@@ -352,6 +352,11 @@ static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a,
#define SYS_accept SYS_accept4
#endif
+#ifdef KERNEL_SUSECONDS_IS_INT
+/* struct __kernel_old_timeval, whose tv_usec is an int here */
+struct k_timeval { long tv_sec; int tv_usec; };
+#endif
+
#ifndef SO_RCVTIMEO_OLD
#define SO_RCVTIMEO_OLD 20
#endif
diff --git a/src/linux/clock_adjtime.c b/src/linux/clock_adjtime.c
index d4d03d24..b2c4393c 100644
--- a/src/linux/clock_adjtime.c
+++ b/src/linux/clock_adjtime.c
@@ -1,6 +1,7 @@
#include <sys/timex.h>
#include <time.h>
#include <errno.h>
+#include <string.h>
#include "syscall.h"
#define IS32BIT(x) !((x)+0x80000000ULL>>32)
@@ -144,8 +145,25 @@ int clock_adjtime (clockid_t clock_id, struct timex *utx)
}
return __syscall_ret(r);
}
+#ifdef KERNEL_SUSECONDS_IS_INT
+ struct timex ktx = *utx;
+ struct k_timeval ktv = { utx->time.tv_sec, utx->time.tv_usec };
+ memcpy(&ktx.time, &ktv, sizeof ktv);
+#ifdef SYS_adjtimex
+ if (clock_id==CLOCK_REALTIME) r = __syscall(SYS_adjtimex, &ktx);
+ else
+#endif
+ r = __syscall(SYS_clock_adjtime, clock_id, &ktx);
+ if (r>=0) {
+ memcpy(&ktv, &ktx.time, sizeof ktv);
+ *utx = ktx;
+ utx->time = (struct timeval){ ktv.tv_sec, ktv.tv_usec };
+ }
+ return __syscall_ret(r);
+#else
#ifdef SYS_adjtimex
if (clock_id==CLOCK_REALTIME) return syscall(SYS_adjtimex, utx);
#endif
return syscall(SYS_clock_adjtime, clock_id, utx);
+#endif
}
diff --git a/src/linux/wait4.c b/src/linux/wait4.c
index fb08c0d0..611158fc 100644
--- a/src/linux/wait4.c
+++ b/src/linux/wait4.c
@@ -27,6 +27,16 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru)
#endif
char *dest = ru ? (char *)&ru->ru_maxrss - 4*sizeof(long) : 0;
r = __sys_wait4(pid, status, options, dest);
+#ifdef KERNEL_SUSECONDS_IS_INT
+ if (r>0 && ru) {
+ struct k_timeval kt[2];
+ memcpy(kt, dest, sizeof kt);
+ ru->ru_utime = (struct timeval)
+ { .tv_sec = kt[0].tv_sec, .tv_usec = kt[0].tv_usec };
+ ru->ru_stime = (struct timeval)
+ { .tv_sec = kt[1].tv_sec, .tv_usec = kt[1].tv_usec };
+ }
+#endif
if (r>0 && ru && sizeof(time_t) > sizeof(long)) {
long kru[4];
memcpy(kru, dest, 4*sizeof(long));
diff --git a/src/misc/getrusage.c b/src/misc/getrusage.c
index 8e03e2e3..c7c44246 100644
--- a/src/misc/getrusage.c
+++ b/src/misc/getrusage.c
@@ -23,6 +23,16 @@ int getrusage(int who, struct rusage *ru)
#endif
char *dest = (char *)&ru->ru_maxrss - 4*sizeof(long);
r = __syscall(SYS_getrusage, who, dest);
+#ifdef KERNEL_SUSECONDS_IS_INT
+ if (!r) {
+ struct k_timeval kt[2];
+ memcpy(kt, dest, sizeof kt);
+ ru->ru_utime = (struct timeval)
+ { .tv_sec = kt[0].tv_sec, .tv_usec = kt[0].tv_usec };
+ ru->ru_stime = (struct timeval)
+ { .tv_sec = kt[1].tv_sec, .tv_usec = kt[1].tv_usec };
+ }
+#endif
if (!r && sizeof(time_t) > sizeof(long)) {
long kru[4];
memcpy(kru, dest, 4*sizeof(long));
diff --git a/src/misc/ioctl.c b/src/misc/ioctl.c
index 35804f02..553a699d 100644
--- a/src/misc/ioctl.c
+++ b/src/misc/ioctl.c
@@ -132,6 +132,18 @@ int ioctl(int fd, int req, ...)
va_start(ap, req);
arg = va_arg(ap, void *);
va_end(ap);
+#ifdef KERNEL_SUSECONDS_IS_INT
+ if (req == SIOCGSTAMP) {
+ struct k_timeval kt;
+ int r = __syscall(SYS_ioctl, fd, req, &kt);
+ if (!r) {
+ struct timeval *tv = arg;
+ tv->tv_sec = kt.tv_sec;
+ tv->tv_usec = kt.tv_usec;
+ }
+ return __syscall_ret(r);
+ }
+#endif
int r = __syscall(SYS_ioctl, fd, req, arg);
if (SIOCGSTAMP != SIOCGSTAMP_OLD && req && r==-ENOTTY) {
for (int i=0; i<sizeof compat_map/sizeof *compat_map; i++) {
diff --git a/src/network/getsockopt.c b/src/network/getsockopt.c
index d3640d9c..bd152983 100644
--- a/src/network/getsockopt.c
+++ b/src/network/getsockopt.c
@@ -5,7 +5,11 @@
int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t *restrict optlen)
{
+#ifdef KERNEL_SUSECONDS_IS_INT
+ struct k_timeval ktv;
+#else
long tv32[2];
+#endif
struct timeval *tv;
int r = __socketcall(getsockopt, fd, level, optname, optval, optlen, 0);
@@ -19,12 +23,21 @@ int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t
if (*optlen < sizeof *tv) return __syscall_ret(-EINVAL);
if (optname==SO_RCVTIMEO) optname=SO_RCVTIMEO_OLD;
if (optname==SO_SNDTIMEO) optname=SO_SNDTIMEO_OLD;
+#ifdef KERNEL_SUSECONDS_IS_INT
+ r = __socketcall(getsockopt, fd, level, optname,
+ &ktv, (socklen_t[]){sizeof ktv}, 0);
+ if (r<0) break;
+ tv = optval;
+ tv->tv_sec = ktv.tv_sec;
+ tv->tv_usec = ktv.tv_usec;
+#else
r = __socketcall(getsockopt, fd, level, optname,
tv32, (socklen_t[]){sizeof tv32}, 0);
if (r<0) break;
tv = optval;
tv->tv_sec = tv32[0];
tv->tv_usec = tv32[1];
+#endif
*optlen = sizeof *tv;
break;
case SO_TIMESTAMP:
diff --git a/src/network/setsockopt.c b/src/network/setsockopt.c
index 612a1947..ad949d1e 100644
--- a/src/network/setsockopt.c
+++ b/src/network/setsockopt.c
@@ -29,8 +29,14 @@ int setsockopt(int fd, int level, int optname, const void *optval, socklen_t opt
if (optname==SO_RCVTIMEO) optname=SO_RCVTIMEO_OLD;
if (optname==SO_SNDTIMEO) optname=SO_SNDTIMEO_OLD;
+#ifdef KERNEL_SUSECONDS_IS_INT
+ r = __socketcall(setsockopt, fd, level, optname,
+ ((struct k_timeval[]){{s, CLAMP(us)}}),
+ sizeof(struct k_timeval), 0);
+#else
r = __socketcall(setsockopt, fd, level, optname,
((long[]){s, CLAMP(us)}), 2*sizeof(long), 0);
+#endif
break;
case SO_TIMESTAMP:
case SO_TIMESTAMPNS:
diff --git a/src/select/select.c b/src/select/select.c
index f1d72863..248a140e 100644
--- a/src/select/select.c
+++ b/src/select/select.c
@@ -36,8 +36,13 @@ int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict
s = CLAMP(s);
#endif
#ifdef SYS_select
+#ifdef KERNEL_SUSECONDS_IS_INT
+ struct k_timeval ktv = { s, us };
+ return syscall_cp(SYS_select, n, rfds, wfds, efds, tv ? &ktv : 0);
+#else
return syscall_cp(SYS_select, n, rfds, wfds, efds,
tv ? ((long[]){s, us}) : 0);
+#endif
#else
return syscall_cp(SYS_pselect6, n, rfds, wfds, efds,
tv ? ((long[]){s, ns}) : 0, ((syscall_arg_t[]){ 0, _NSIG/8 }));
diff --git a/src/signal/getitimer.c b/src/signal/getitimer.c
index 36d1eb9d..30c538fc 100644
--- a/src/signal/getitimer.c
+++ b/src/signal/getitimer.c
@@ -14,5 +14,17 @@ int getitimer(int which, struct itimerval *old)
}
return __syscall_ret(r);
}
+#ifdef KERNEL_SUSECONDS_IS_INT
+ struct k_timeval kold[2];
+ int r = __syscall(SYS_getitimer, which, kold);
+ if (!r) {
+ old->it_interval = (struct timeval)
+ { kold[0].tv_sec, kold[0].tv_usec };
+ old->it_value = (struct timeval)
+ { kold[1].tv_sec, kold[1].tv_usec };
+ }
+ return __syscall_ret(r);
+#else
return syscall(SYS_getitimer, which, old);
+#endif
}
diff --git a/src/signal/setitimer.c b/src/signal/setitimer.c
index 0dfbeb4d..b38fe266 100644
--- a/src/signal/setitimer.c
+++ b/src/signal/setitimer.c
@@ -22,5 +22,23 @@ int setitimer(int which, const struct itimerval *restrict new, struct itimerval
}
return __syscall_ret(r);
}
+#ifdef KERNEL_SUSECONDS_IS_INT
+ struct k_timeval knew[2], kold[2];
+ if (new) {
+ knew[0] = (struct k_timeval)
+ { new->it_interval.tv_sec, new->it_interval.tv_usec };
+ knew[1] = (struct k_timeval)
+ { new->it_value.tv_sec, new->it_value.tv_usec };
+ }
+ int r = __syscall(SYS_setitimer, which, new ? knew : 0, old ? kold : 0);
+ if (!r && old) {
+ old->it_interval = (struct timeval)
+ { kold[0].tv_sec, kold[0].tv_usec };
+ old->it_value = (struct timeval)
+ { kold[1].tv_sec, kold[1].tv_usec };
+ }
+ return __syscall_ret(r);
+#else
return syscall(SYS_setitimer, which, new, old);
+#endif
}
--
2.47.3
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.