Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: socket: implement 64-bit timestamps

The 'timeval' and 'timespec' data structures used for socket timestamps
are going to be redefined in user space based on 64-bit time_t in future
versions of the C library to deal with the y2038 overflow problem,
which breaks the ABI definition.

Unlike many modern ioctl commands, SIOCGSTAMP and SIOCGSTAMPNS do not
use the _IOR() macro to encode the size of the transferred data, so it
remains ambiguous whether the application uses the old or new layout.

The best workaround I could find is rather ugly: we redefine the command
code based on the size of the respective data structure with a ternary
operator. This lets it get evaluated as late as possible, hopefully after
that structure is visible to the caller. We cannot use an #ifdef here,
because inux/sockios.h might have been included before any libc header
that could determine the size of time_t.

The ioctl implementation now interprets the new command codes as always
referring to the 64-bit structure on all architectures, while the old
architecture specific command code still refers to the old architecture
specific layout. The new command number is only used when they are
actually different.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Arnd Bergmann and committed by
David S. Miller
0768e170 5ce5d8a5

+50 -16
+2 -2
arch/alpha/include/uapi/asm/sockios.h
··· 11 11 #define SIOCSPGRP _IOW('s', 8, pid_t) 12 12 #define SIOCGPGRP _IOR('s', 9, pid_t) 13 13 14 - #define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ 15 - #define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ 14 + #define SIOCGSTAMP_OLD 0x8906 /* Get stamp (timeval) */ 15 + #define SIOCGSTAMPNS_OLD 0x8907 /* Get stamp (timespec) */ 16 16 17 17 #endif /* _ASM_ALPHA_SOCKIOS_H */
+2 -2
arch/mips/include/uapi/asm/sockios.h
··· 21 21 #define SIOCSPGRP _IOW('s', 8, pid_t) 22 22 #define SIOCGPGRP _IOR('s', 9, pid_t) 23 23 24 - #define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ 25 - #define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ 24 + #define SIOCGSTAMP_OLD 0x8906 /* Get stamp (timeval) */ 25 + #define SIOCGSTAMPNS_OLD 0x8907 /* Get stamp (timespec) */ 26 26 27 27 #endif /* _ASM_SOCKIOS_H */
+3 -2
arch/sh/include/uapi/asm/sockios.h
··· 10 10 #define SIOCSPGRP _IOW('s', 8, pid_t) 11 11 #define SIOCGPGRP _IOR('s', 9, pid_t) 12 12 13 - #define SIOCGSTAMP _IOR('s', 100, struct timeval) /* Get stamp (timeval) */ 14 - #define SIOCGSTAMPNS _IOR('s', 101, struct timespec) /* Get stamp (timespec) */ 13 + #define SIOCGSTAMP_OLD _IOR('s', 100, struct timeval) /* Get stamp (timeval) */ 14 + #define SIOCGSTAMPNS_OLD _IOR('s', 101, struct timespec) /* Get stamp (timespec) */ 15 + 15 16 #endif /* __ASM_SH_SOCKIOS_H */
+2 -2
arch/xtensa/include/uapi/asm/sockios.h
··· 26 26 #define SIOCSPGRP _IOW('s', 8, pid_t) 27 27 #define SIOCGPGRP _IOR('s', 9, pid_t) 28 28 29 - #define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ 30 - #define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ 29 + #define SIOCGSTAMP_OLD 0x8906 /* Get stamp (timeval) */ 30 + #define SIOCGSTAMPNS_OLD 0x8907 /* Get stamp (timespec) */ 31 31 32 32 #endif /* _XTENSA_SOCKIOS_H */
+2 -2
include/uapi/asm-generic/sockios.h
··· 8 8 #define FIOGETOWN 0x8903 9 9 #define SIOCGPGRP 0x8904 10 10 #define SIOCATMARK 0x8905 11 - #define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ 12 - #define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ 11 + #define SIOCGSTAMP_OLD 0x8906 /* Get stamp (timeval) */ 12 + #define SIOCGSTAMPNS_OLD 0x8907 /* Get stamp (timespec) */ 13 13 14 14 #endif /* __ASM_GENERIC_SOCKIOS_H */
+21
include/uapi/linux/sockios.h
··· 19 19 #ifndef _LINUX_SOCKIOS_H 20 20 #define _LINUX_SOCKIOS_H 21 21 22 + #include <asm/bitsperlong.h> 22 23 #include <asm/sockios.h> 23 24 24 25 /* Linux-specific socket ioctls */ ··· 27 26 #define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) */ 28 27 29 28 #define SOCK_IOC_TYPE 0x89 29 + 30 + /* 31 + * the timeval/timespec data structure layout is defined by libc, 32 + * so we need to cover both possible versions on 32-bit. 33 + */ 34 + /* Get stamp (timeval) */ 35 + #define SIOCGSTAMP_NEW _IOR(SOCK_IOC_TYPE, 0x06, long long[2]) 36 + /* Get stamp (timespec) */ 37 + #define SIOCGSTAMPNS_NEW _IOR(SOCK_IOC_TYPE, 0x07, long long[2]) 38 + 39 + #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) 40 + /* on 64-bit and x32, avoid the ?: operator */ 41 + #define SIOCGSTAMP SIOCGSTAMP_OLD 42 + #define SIOCGSTAMPNS SIOCGSTAMPNS_OLD 43 + #else 44 + #define SIOCGSTAMP ((sizeof(struct timeval)) == 8 ? \ 45 + SIOCGSTAMP_OLD : SIOCGSTAMP_NEW) 46 + #define SIOCGSTAMPNS ((sizeof(struct timespec)) == 8 ? \ 47 + SIOCGSTAMPNS_OLD : SIOCGSTAMPNS_NEW) 48 + #endif 30 49 31 50 /* Routing table calls. */ 32 51 #define SIOCADDRT 0x890B /* add routing table entry */
+18 -6
net/socket.c
··· 1164 1164 1165 1165 err = open_related_ns(&net->ns, get_net_ns); 1166 1166 break; 1167 - case SIOCGSTAMP: 1168 - case SIOCGSTAMPNS: 1167 + case SIOCGSTAMP_OLD: 1168 + case SIOCGSTAMPNS_OLD: 1169 1169 if (!sock->ops->gettstamp) { 1170 1170 err = -ENOIOCTLCMD; 1171 1171 break; 1172 1172 } 1173 1173 err = sock->ops->gettstamp(sock, argp, 1174 - cmd == SIOCGSTAMP, false); 1174 + cmd == SIOCGSTAMP_OLD, 1175 + !IS_ENABLED(CONFIG_64BIT)); 1176 + case SIOCGSTAMP_NEW: 1177 + case SIOCGSTAMPNS_NEW: 1178 + if (!sock->ops->gettstamp) { 1179 + err = -ENOIOCTLCMD; 1180 + break; 1181 + } 1182 + err = sock->ops->gettstamp(sock, argp, 1183 + cmd == SIOCGSTAMP_NEW, 1184 + false); 1175 1185 break; 1176 1186 default: 1177 1187 err = sock_do_ioctl(net, sock, cmd, arg); ··· 3334 3324 case SIOCADDRT: 3335 3325 case SIOCDELRT: 3336 3326 return routing_ioctl(net, sock, cmd, argp); 3337 - case SIOCGSTAMP: 3338 - case SIOCGSTAMPNS: 3327 + case SIOCGSTAMP_OLD: 3328 + case SIOCGSTAMPNS_OLD: 3339 3329 if (!sock->ops->gettstamp) 3340 3330 return -ENOIOCTLCMD; 3341 - return sock->ops->gettstamp(sock, argp, cmd == SIOCGSTAMP, 3331 + return sock->ops->gettstamp(sock, argp, cmd == SIOCGSTAMP_OLD, 3342 3332 !COMPAT_USE_64BIT_TIME); 3343 3333 3344 3334 case SIOCBONDSLAVEINFOQUERY: ··· 3358 3348 case SIOCADDDLCI: 3359 3349 case SIOCDELDLCI: 3360 3350 case SIOCGSKNS: 3351 + case SIOCGSTAMP_NEW: 3352 + case SIOCGSTAMPNS_NEW: 3361 3353 return sock_ioctl(file, cmd, arg); 3362 3354 3363 3355 case SIOCGIFFLAGS: