|
Kmods SIG |
8d16be |
From fcbad8293d52864d87d0b9f6035fd87a049d59d8 Mon Sep 17 00:00:00 2001
|
|
Kmods SIG |
8d16be |
From: Arnd Bergmann <arnd@arndb.de>
|
|
Kmods SIG |
8d16be |
Date: Fri, 8 Nov 2019 21:34:28 +0100
|
|
Kmods SIG |
8d16be |
Subject: [Backport fcbad8293d52] netfilter: xt_time: use time64_t
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
The current xt_time driver suffers from the y2038 overflow on 32-bit
|
|
Kmods SIG |
8d16be |
architectures, when the time of day calculations break.
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
Also, on both 32-bit and 64-bit architectures, there is a problem with
|
|
Kmods SIG |
8d16be |
info->date_start/stop, which is part of the user ABI and overflows in
|
|
Kmods SIG |
8d16be |
in 2106.
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
Fix the first issue by using time64_t and explicit calls to div_u64()
|
|
Kmods SIG |
8d16be |
and div_u64_rem(), and document the seconds issue.
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
The explicit 64-bit division is unfortunately slower on 32-bit
|
|
Kmods SIG |
8d16be |
architectures, but doing it as unsigned lets us use the optimized
|
|
Kmods SIG |
8d16be |
division-through-multiplication path in most configurations. This should
|
|
Kmods SIG |
8d16be |
be fine, as the code already does not allow any negative time of day
|
|
Kmods SIG |
8d16be |
values.
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
Using u32 seconds values consistently would probably also work and
|
|
Kmods SIG |
8d16be |
be a little more efficient, but that doesn't feel right as it would
|
|
Kmods SIG |
8d16be |
propagate the y2106 overflow to more place rather than fewer.
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
|
Kmods SIG |
8d16be |
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
Kmods SIG |
8d16be |
---
|
|
Kmods SIG |
8d16be |
src/xt_time.c | 19 +++++++++++--------
|
|
Kmods SIG |
8d16be |
1 file changed, 11 insertions(+), 8 deletions(-)
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
diff --git a/src/xt_time.c b/src/xt_time.c
|
|
Kmods SIG |
8d16be |
index 8dbb4d48f2ed5995dedaa8eb4f4b18a0ba91acb2..67cb984894153d5db895e104adacf51422926e34 100644
|
|
Kmods SIG |
8d16be |
--- a/src/xt_time.c
|
|
Kmods SIG |
8d16be |
+++ b/src/xt_time.c
|
|
Kmods SIG |
8d16be |
@@ -77,12 +77,12 @@ static inline bool is_leap(unsigned int y)
|
|
Kmods SIG |
8d16be |
* This is done in three separate functions so that the most expensive
|
|
Kmods SIG |
8d16be |
* calculations are done last, in case a "simple match" can be found earlier.
|
|
Kmods SIG |
8d16be |
*/
|
|
Kmods SIG |
8d16be |
-static inline unsigned int localtime_1(struct xtm *r, time_t time)
|
|
Kmods SIG |
8d16be |
+static inline unsigned int localtime_1(struct xtm *r, time64_t time)
|
|
Kmods SIG |
8d16be |
{
|
|
Kmods SIG |
8d16be |
unsigned int v, w;
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
/* Each day has 86400s, so finding the hour/minute is actually easy. */
|
|
Kmods SIG |
8d16be |
- v = time % SECONDS_PER_DAY;
|
|
Kmods SIG |
8d16be |
+ div_u64_rem(time, SECONDS_PER_DAY, &v);
|
|
Kmods SIG |
8d16be |
r->second = v % 60;
|
|
Kmods SIG |
8d16be |
w = v / 60;
|
|
Kmods SIG |
8d16be |
r->minute = w % 60;
|
|
Kmods SIG |
8d16be |
@@ -90,13 +90,13 @@ static inline unsigned int localtime_1(struct xtm *r, time_t time)
|
|
Kmods SIG |
8d16be |
return v;
|
|
Kmods SIG |
8d16be |
}
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
-static inline void localtime_2(struct xtm *r, time_t time)
|
|
Kmods SIG |
8d16be |
+static inline void localtime_2(struct xtm *r, time64_t time)
|
|
Kmods SIG |
8d16be |
{
|
|
Kmods SIG |
8d16be |
/*
|
|
Kmods SIG |
8d16be |
* Here comes the rest (weekday, monthday). First, divide the SSTE
|
|
Kmods SIG |
8d16be |
* by seconds-per-day to get the number of _days_ since the epoch.
|
|
Kmods SIG |
8d16be |
*/
|
|
Kmods SIG |
8d16be |
- r->dse = time / 86400;
|
|
Kmods SIG |
8d16be |
+ r->dse = div_u64(time, SECONDS_PER_DAY);
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
/*
|
|
Kmods SIG |
8d16be |
* 1970-01-01 (w=0) was a Thursday (4).
|
|
Kmods SIG |
8d16be |
@@ -105,7 +105,7 @@ static inline void localtime_2(struct xtm *r, time_t time)
|
|
Kmods SIG |
8d16be |
r->weekday = (4 + r->dse - 1) % 7 + 1;
|
|
Kmods SIG |
8d16be |
}
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
-static void localtime_3(struct xtm *r, time_t time)
|
|
Kmods SIG |
8d16be |
+static void localtime_3(struct xtm *r, time64_t time)
|
|
Kmods SIG |
8d16be |
{
|
|
Kmods SIG |
8d16be |
unsigned int year, i, w = r->dse;
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
@@ -160,7 +160,7 @@ time_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
|
Kmods SIG |
8d16be |
const struct xt_time_info *info = par->matchinfo;
|
|
Kmods SIG |
8d16be |
unsigned int packet_time;
|
|
Kmods SIG |
8d16be |
struct xtm current_time;
|
|
Kmods SIG |
8d16be |
- s64 stamp;
|
|
Kmods SIG |
8d16be |
+ time64_t stamp;
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
/*
|
|
Kmods SIG |
8d16be |
* We need real time here, but we can neither use skb->tstamp
|
|
Kmods SIG |
8d16be |
@@ -173,14 +173,14 @@ time_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
|
Kmods SIG |
8d16be |
* 1. match before 13:00
|
|
Kmods SIG |
8d16be |
* 2. match after 13:00
|
|
Kmods SIG |
8d16be |
*
|
|
Kmods SIG |
8d16be |
- * If you match against processing time (get_seconds) it
|
|
Kmods SIG |
8d16be |
+ * If you match against processing time (ktime_get_real_seconds) it
|
|
Kmods SIG |
8d16be |
* may happen that the same packet matches both rules if
|
|
Kmods SIG |
8d16be |
* it arrived at the right moment before 13:00, so it would be
|
|
Kmods SIG |
8d16be |
* better to check skb->tstamp and set it via __net_timestamp()
|
|
Kmods SIG |
8d16be |
* if needed. This however breaks outgoing packets tx timestamp,
|
|
Kmods SIG |
8d16be |
* and causes them to get delayed forever by fq packet scheduler.
|
|
Kmods SIG |
8d16be |
*/
|
|
Kmods SIG |
8d16be |
- stamp = get_seconds();
|
|
Kmods SIG |
8d16be |
+ stamp = ktime_get_real_seconds();
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
if (info->flags & XT_TIME_LOCAL_TZ)
|
|
Kmods SIG |
8d16be |
/* Adjust for local timezone */
|
|
Kmods SIG |
8d16be |
@@ -193,6 +193,9 @@ time_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
|
Kmods SIG |
8d16be |
* - 'now' is in the weekday mask
|
|
Kmods SIG |
8d16be |
* - 'now' is in the daytime range time_start..time_end
|
|
Kmods SIG |
8d16be |
* (and by default, libxt_time will set these so as to match)
|
|
Kmods SIG |
8d16be |
+ *
|
|
Kmods SIG |
8d16be |
+ * note: info->date_start/stop are unsigned 32-bit values that
|
|
Kmods SIG |
8d16be |
+ * can hold values beyond y2038, but not after y2106.
|
|
Kmods SIG |
8d16be |
*/
|
|
Kmods SIG |
8d16be |
|
|
Kmods SIG |
8d16be |
if (stamp < info->date_start || stamp > info->date_stop)
|
|
Kmods SIG |
8d16be |
--
|
|
Kmods SIG |
8d16be |
2.31.1
|
|
Kmods SIG |
8d16be |
|