* [PATCH 03/16] net: sock: use __kernel_old_timespec instead of timespec
2019-11-08 21:32 [PATCH 00/16] drivers: y2038 updates Arnd Bergmann
@ 2019-11-08 21:32 ` Arnd Bergmann
2019-11-09 19:09 ` Deepa Dinamani
2019-11-08 21:32 ` [PATCH 09/16] netfilter: nft_meta: use 64-bit time arithmetic Arnd Bergmann
2019-11-08 21:32 ` [PATCH 10/16] packet: clarify timestamp overflow Arnd Bergmann
2 siblings, 1 reply; 7+ messages in thread
From: Arnd Bergmann @ 2019-11-08 21:32 UTC (permalink / raw)
To: y2038, David S. Miller, Eric Dumazet, Alexey Kuznetsov,
Hideaki YOSHIFUJI
Cc: linux-kernel, Arnd Bergmann, Willem de Bruijn, Florian Westphal,
Jakub Kicinski, Matthew Wilcox (Oracle),
Stanislav Fomichev, John Hurley, Jonathan Lemon, Pedro Tammela,
Deepa Dinamani, netdev
The 'timespec' type definition and helpers like ktime_to_timespec()
or timespec64_to_timespec() should no longer be used in the kernel so
we can remove them and avoid introducing y2038 issues in new code.
Change the socket code that needs to pass a timespec to user space for
backward compatibility to use __kernel_old_timespec instead. This type
has the same layout but with a clearer defined name.
Slightly reformat tcp_recv_timestamp() for consistency after the removal
of timespec64_to_timespec().
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
include/linux/skbuff.h | 7 +++++--
net/compat.c | 2 +-
net/ipv4/tcp.c | 28 ++++++++++++++++------------
net/socket.c | 2 +-
4 files changed, 23 insertions(+), 16 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 64a395c7f689..6d64ffe92867 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3656,9 +3656,12 @@ static inline void skb_get_new_timestamp(const struct sk_buff *skb,
}
static inline void skb_get_timestampns(const struct sk_buff *skb,
- struct timespec *stamp)
+ struct __kernel_old_timespec *stamp)
{
- *stamp = ktime_to_timespec(skb->tstamp);
+ struct timespec64 ts = ktime_to_timespec64(skb->tstamp);
+
+ stamp->tv_sec = ts.tv_sec;
+ stamp->tv_nsec = ts.tv_nsec;
}
static inline void skb_get_new_timestampns(const struct sk_buff *skb,
diff --git a/net/compat.c b/net/compat.c
index 0f7ded26059e..47d99c784947 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -232,7 +232,7 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
(type == SO_TIMESTAMPNS_OLD || type == SO_TIMESTAMPING_OLD)) {
int count = type == SO_TIMESTAMPNS_OLD ? 1 : 3;
int i;
- struct timespec *ts = (struct timespec *)data;
+ struct __kernel_old_timespec *ts = data;
for (i = 0; i < count; i++) {
cts[i].tv_sec = ts[i].tv_sec;
cts[i].tv_nsec = ts[i].tv_nsec;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index d8876f0e9672..013f635db19c 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1864,29 +1864,33 @@ static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
if (sock_flag(sk, SOCK_RCVTSTAMP)) {
if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
if (new_tstamp) {
- struct __kernel_timespec kts = {tss->ts[0].tv_sec, tss->ts[0].tv_nsec};
-
+ struct __kernel_timespec kts = {
+ .tv_sec = tss->ts[0].tv_sec,
+ .tv_nsec = tss->ts[0].tv_nsec,
+ };
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW,
sizeof(kts), &kts);
} else {
- struct timespec ts_old = timespec64_to_timespec(tss->ts[0]);
-
+ struct __kernel_old_timespec ts_old = {
+ .tv_sec = tss->ts[0].tv_sec,
+ .tv_nsec = tss->ts[0].tv_nsec,
+ };
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
sizeof(ts_old), &ts_old);
}
} else {
if (new_tstamp) {
- struct __kernel_sock_timeval stv;
-
- stv.tv_sec = tss->ts[0].tv_sec;
- stv.tv_usec = tss->ts[0].tv_nsec / 1000;
+ struct __kernel_sock_timeval stv = {
+ .tv_sec = tss->ts[0].tv_sec,
+ .tv_usec = tss->ts[0].tv_nsec / 1000,
+ };
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_NEW,
sizeof(stv), &stv);
} else {
- struct __kernel_old_timeval tv;
-
- tv.tv_sec = tss->ts[0].tv_sec;
- tv.tv_usec = tss->ts[0].tv_nsec / 1000;
+ struct __kernel_old_timeval tv = {
+ .tv_sec = tss->ts[0].tv_sec,
+ .tv_usec = tss->ts[0].tv_nsec / 1000,
+ };
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
sizeof(tv), &tv);
}
diff --git a/net/socket.c b/net/socket.c
index 98f6544b0096..9ab00a080760 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -793,7 +793,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW,
sizeof(ts), &ts);
} else {
- struct timespec ts;
+ struct __kernel_old_timespec ts;
skb_get_timestampns(skb, &ts);
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
--
2.20.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 03/16] net: sock: use __kernel_old_timespec instead of timespec
2019-11-08 21:32 ` [PATCH 03/16] net: sock: use __kernel_old_timespec instead of timespec Arnd Bergmann
@ 2019-11-09 19:09 ` Deepa Dinamani
0 siblings, 0 replies; 7+ messages in thread
From: Deepa Dinamani @ 2019-11-09 19:09 UTC (permalink / raw)
To: Arnd Bergmann
Cc: y2038 Mailman List, David S. Miller, Eric Dumazet,
Alexey Kuznetsov, Hideaki YOSHIFUJI, Linux Kernel Mailing List,
Willem de Bruijn, Florian Westphal, Jakub Kicinski,
Matthew Wilcox (Oracle),
Stanislav Fomichev, John Hurley, Jonathan Lemon, Pedro Tammela,
Linux Network Devel Mailing List
Acked-by: Deepa Dinamani <deepa.kernel@gmail.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 09/16] netfilter: nft_meta: use 64-bit time arithmetic
2019-11-08 21:32 [PATCH 00/16] drivers: y2038 updates Arnd Bergmann
2019-11-08 21:32 ` [PATCH 03/16] net: sock: use __kernel_old_timespec instead of timespec Arnd Bergmann
@ 2019-11-08 21:32 ` Arnd Bergmann
2019-11-09 11:20 ` Phil Sutter
2019-11-15 22:44 ` Pablo Neira Ayuso
2019-11-08 21:32 ` [PATCH 10/16] packet: clarify timestamp overflow Arnd Bergmann
2 siblings, 2 replies; 7+ messages in thread
From: Arnd Bergmann @ 2019-11-08 21:32 UTC (permalink / raw)
To: y2038, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal,
David S. Miller
Cc: linux-kernel, Arnd Bergmann, Ander Juaristi, wenxu,
Thomas Gleixner, Phil Sutter, netfilter-devel, coreteam, netdev
On 32-bit architectures, get_seconds() returns an unsigned 32-bit
time value, which also matches the type used in the nft_meta
code. This will not overflow in year 2038 as a time_t would, but
it still suffers from the overflow problem later on in year 2106.
Change this instance to use the time64_t type consistently
and avoid the deprecated get_seconds().
The nft_meta_weekday() calculation potentially gets a little slower
on 32-bit architectures, but now it has the same behavior as on
64-bit architectures and does not overflow.
Fixes: 63d10e12b00d ("netfilter: nft_meta: support for time matching")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
net/netfilter/nft_meta.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index 317e3a9e8c5b..dda1e55d5801 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -33,19 +33,19 @@
static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state);
-static u8 nft_meta_weekday(unsigned long secs)
+static u8 nft_meta_weekday(time64_t secs)
{
unsigned int dse;
u8 wday;
secs -= NFT_META_SECS_PER_MINUTE * sys_tz.tz_minuteswest;
- dse = secs / NFT_META_SECS_PER_DAY;
+ dse = div_u64(secs, NFT_META_SECS_PER_DAY);
wday = (4 + dse) % NFT_META_DAYS_PER_WEEK;
return wday;
}
-static u32 nft_meta_hour(unsigned long secs)
+static u32 nft_meta_hour(time64_t secs)
{
struct tm tm;
@@ -250,10 +250,10 @@ void nft_meta_get_eval(const struct nft_expr *expr,
nft_reg_store64(dest, ktime_get_real_ns());
break;
case NFT_META_TIME_DAY:
- nft_reg_store8(dest, nft_meta_weekday(get_seconds()));
+ nft_reg_store8(dest, nft_meta_weekday(ktime_get_real_seconds()));
break;
case NFT_META_TIME_HOUR:
- *dest = nft_meta_hour(get_seconds());
+ *dest = nft_meta_hour(ktime_get_real_seconds());
break;
default:
WARN_ON(1);
--
2.20.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 09/16] netfilter: nft_meta: use 64-bit time arithmetic
2019-11-08 21:32 ` [PATCH 09/16] netfilter: nft_meta: use 64-bit time arithmetic Arnd Bergmann
@ 2019-11-09 11:20 ` Phil Sutter
2019-11-15 22:44 ` Pablo Neira Ayuso
1 sibling, 0 replies; 7+ messages in thread
From: Phil Sutter @ 2019-11-09 11:20 UTC (permalink / raw)
To: Arnd Bergmann
Cc: y2038, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal,
David S. Miller, linux-kernel, Ander Juaristi, wenxu,
Thomas Gleixner, netfilter-devel, coreteam, netdev
On Fri, Nov 08, 2019 at 10:32:47PM +0100, Arnd Bergmann wrote:
> On 32-bit architectures, get_seconds() returns an unsigned 32-bit
> time value, which also matches the type used in the nft_meta
> code. This will not overflow in year 2038 as a time_t would, but
> it still suffers from the overflow problem later on in year 2106.
I wonder if the assumption that people will still use nft_meta 80 years
from now is an optimistic or pessimistic one. :)
> Change this instance to use the time64_t type consistently
> and avoid the deprecated get_seconds().
>
> The nft_meta_weekday() calculation potentially gets a little slower
> on 32-bit architectures, but now it has the same behavior as on
> 64-bit architectures and does not overflow.
>
> Fixes: 63d10e12b00d ("netfilter: nft_meta: support for time matching")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Phil Sutter <phil@nwl.cc>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 09/16] netfilter: nft_meta: use 64-bit time arithmetic
2019-11-08 21:32 ` [PATCH 09/16] netfilter: nft_meta: use 64-bit time arithmetic Arnd Bergmann
2019-11-09 11:20 ` Phil Sutter
@ 2019-11-15 22:44 ` Pablo Neira Ayuso
1 sibling, 0 replies; 7+ messages in thread
From: Pablo Neira Ayuso @ 2019-11-15 22:44 UTC (permalink / raw)
To: Arnd Bergmann
Cc: y2038, Jozsef Kadlecsik, Florian Westphal, David S. Miller,
linux-kernel, Ander Juaristi, wenxu, Thomas Gleixner,
Phil Sutter, netfilter-devel, coreteam, netdev
On Fri, Nov 08, 2019 at 10:32:47PM +0100, Arnd Bergmann wrote:
> On 32-bit architectures, get_seconds() returns an unsigned 32-bit
> time value, which also matches the type used in the nft_meta
> code. This will not overflow in year 2038 as a time_t would, but
> it still suffers from the overflow problem later on in year 2106.
>
> Change this instance to use the time64_t type consistently
> and avoid the deprecated get_seconds().
>
> The nft_meta_weekday() calculation potentially gets a little slower
> on 32-bit architectures, but now it has the same behavior as on
> 64-bit architectures and does not overflow.
Applied, thanks Arnd.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 10/16] packet: clarify timestamp overflow
2019-11-08 21:32 [PATCH 00/16] drivers: y2038 updates Arnd Bergmann
2019-11-08 21:32 ` [PATCH 03/16] net: sock: use __kernel_old_timespec instead of timespec Arnd Bergmann
2019-11-08 21:32 ` [PATCH 09/16] netfilter: nft_meta: use 64-bit time arithmetic Arnd Bergmann
@ 2019-11-08 21:32 ` Arnd Bergmann
2 siblings, 0 replies; 7+ messages in thread
From: Arnd Bergmann @ 2019-11-08 21:32 UTC (permalink / raw)
To: y2038, David S. Miller
Cc: linux-kernel, Arnd Bergmann, Willem de Bruijn, Eric Dumazet,
Maxim Mikityanskiy, Paolo Abeni, Neil Horman, netdev
The memory mapped packet socket data structure in version 1 through 3
all contain 32-bit second values for the packet time stamps, which makes
them suffer from the overflow of time_t in y2038 or y2106 (depending
on whether user space interprets the value as signed or unsigned).
The implementation uses the deprecated getnstimeofday() function.
In order to get rid of that, this changes the code to use
ktime_get_real_ts64() as a replacement, documenting the nature of the
overflow. As long as the user applications treat the timestamps as
unsigned, or only use the difference between timestamps, they are
fine, and changing the timestamps to 64-bit wouldn't require a more
invasive user space API change.
Note: a lot of other APIs suffer from incompatible structures when
time_t gets redefined to 64-bit in 32-bit user space, but this one
does not.
Acked-by: Willem de Bruijn <willemb@google.com>
Link: https://lore.kernel.org/lkml/CAF=yD-Jomr-gWSR-EBNKnSpFL46UeG564FLfqTCMNEm-prEaXA@mail.gmail.com/T/#u
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
net/packet/af_packet.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 82a50e850245..0bfdb07e253b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -408,17 +408,17 @@ static int __packet_get_status(const struct packet_sock *po, void *frame)
}
}
-static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts,
+static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec64 *ts,
unsigned int flags)
{
struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
if (shhwtstamps &&
(flags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
- ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts))
+ ktime_to_timespec64_cond(shhwtstamps->hwtstamp, ts))
return TP_STATUS_TS_RAW_HARDWARE;
- if (ktime_to_timespec_cond(skb->tstamp, ts))
+ if (ktime_to_timespec64_cond(skb->tstamp, ts))
return TP_STATUS_TS_SOFTWARE;
return 0;
@@ -428,13 +428,20 @@ static __u32 __packet_set_timestamp(struct packet_sock *po, void *frame,
struct sk_buff *skb)
{
union tpacket_uhdr h;
- struct timespec ts;
+ struct timespec64 ts;
__u32 ts_status;
if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
return 0;
h.raw = frame;
+ /*
+ * versions 1 through 3 overflow the timestamps in y2106, since they
+ * all store the seconds in a 32-bit unsigned integer.
+ * If we create a version 4, that should have a 64-bit timestamp,
+ * either 64-bit seconds + 32-bit nanoseconds, or just 64-bit
+ * nanoseconds.
+ */
switch (po->tp_version) {
case TPACKET_V1:
h.h1->tp_sec = ts.tv_sec;
@@ -774,8 +781,8 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1,
* It shouldn't really happen as we don't close empty
* blocks. See prb_retire_rx_blk_timer_expired().
*/
- struct timespec ts;
- getnstimeofday(&ts);
+ struct timespec64 ts;
+ ktime_get_real_ts64(&ts);
h1->ts_last_pkt.ts_sec = ts.tv_sec;
h1->ts_last_pkt.ts_nsec = ts.tv_nsec;
}
@@ -805,7 +812,7 @@ static void prb_thaw_queue(struct tpacket_kbdq_core *pkc)
static void prb_open_block(struct tpacket_kbdq_core *pkc1,
struct tpacket_block_desc *pbd1)
{
- struct timespec ts;
+ struct timespec64 ts;
struct tpacket_hdr_v1 *h1 = &pbd1->hdr.bh1;
smp_rmb();
@@ -818,7 +825,7 @@ static void prb_open_block(struct tpacket_kbdq_core *pkc1,
BLOCK_NUM_PKTS(pbd1) = 0;
BLOCK_LEN(pbd1) = BLK_PLUS_PRIV(pkc1->blk_sizeof_priv);
- getnstimeofday(&ts);
+ ktime_get_real_ts64(&ts);
h1->ts_first_pkt.ts_sec = ts.tv_sec;
h1->ts_first_pkt.ts_nsec = ts.tv_nsec;
@@ -2162,7 +2169,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
unsigned long status = TP_STATUS_USER;
unsigned short macoff, netoff, hdrlen;
struct sk_buff *copy_skb = NULL;
- struct timespec ts;
+ struct timespec64 ts;
__u32 ts_status;
bool is_drop_n_account = false;
bool do_vnet = false;
@@ -2294,7 +2301,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
skb_copy_bits(skb, 0, h.raw + macoff, snaplen);
if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
- getnstimeofday(&ts);
+ ktime_get_real_ts64(&ts);
status |= ts_status;
--
2.20.0
^ permalink raw reply related [flat|nested] 7+ messages in thread