Oliver Neukum 562185
From 39ff83f2f6cc5cc1458dfcea9697f96338210beb Mon Sep 17 00:00:00 2001
Oliver Neukum 562185
From: Lukas Hannen <lukas.hannen@opensource.tttech-industrial.com>
Oliver Neukum 562185
Date: Wed, 25 Aug 2021 10:12:43 +0000
Oliver Neukum 562185
Subject: [PATCH] time: Handle negative seconds correctly in timespec64_to_ns()
Oliver Neukum 562185
Git-commit: 39ff83f2f6cc5cc1458dfcea9697f96338210beb
Oliver Neukum 562185
References: git-fixes
Oliver Neukum 562185
Patch-mainline: v5.15-rc1
Oliver Neukum 562185
Oliver Neukum 562185
timespec64_ns() prevents multiplication overflows by comparing the seconds
Oliver Neukum 562185
value of the timespec to KTIME_SEC_MAX. If the value is greater or equal it
Oliver Neukum 562185
returns KTIME_MAX.
Oliver Neukum 562185
Oliver Neukum 562185
But that check casts the signed seconds value to unsigned which makes the
Oliver Neukum 562185
comparision true for all negative values and therefore return wrongly
Oliver Neukum 562185
KTIME_MAX.
Oliver Neukum 562185
Oliver Neukum 562185
Negative second values are perfectly valid and required in some places,
Oliver Neukum 562185
e.g. ptp_clock_adjtime().
Oliver Neukum 562185
Oliver Neukum 562185
Remove the cast and add a check for the negative boundary which is required
Oliver Neukum 562185
to prevent undefined behaviour due to multiplication underflow.
Oliver Neukum 562185
Oliver Neukum 562185
Fixes: cb47755725da ("time: Prevent undefined behaviour in timespec64_to_ns()")'
Oliver Neukum 562185
Signed-off-by: Lukas Hannen <lukas.hannen@opensource.tttech-industrial.com>
Oliver Neukum 562185
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Oliver Neukum 562185
Cc: stable@vger.kernel.org
Oliver Neukum 562185
Link: https://lore.kernel.org/r/AM6PR01MB541637BD6F336B8FFB72AF80EEC69@AM6PR01MB5416.eurprd01.prod.exchangelabs.com
Oliver Neukum 562185
Signed-off-by: Oliver Neukum <oneukum@suse.com>
Oliver Neukum 562185
---
Oliver Neukum 562185
 include/linux/time64.h |    9 +++++++--
Oliver Neukum 562185
 1 file changed, 7 insertions(+), 2 deletions(-)
Oliver Neukum 562185
Oliver Neukum 562185
--- a/include/linux/time64.h
Oliver Neukum 562185
+++ b/include/linux/time64.h
Oliver Neukum 562185
@@ -39,7 +39,9 @@ struct itimerspec64 {
Oliver Neukum 562185
 /* Located here for timespec[64]_valid_strict */
Oliver Neukum 562185
 #define TIME64_MAX			((s64)~((u64)1 << 63))
Oliver Neukum 562185
 #define KTIME_MAX			((s64)~((u64)1 << 63))
Oliver Neukum 562185
+#define KTIME_MIN			(-KTIME_MAX - 1)
Oliver Neukum 562185
 #define KTIME_SEC_MAX			(KTIME_MAX / NSEC_PER_SEC)
Oliver Neukum 562185
+#define KTIME_SEC_MIN			(KTIME_MIN / NSEC_PER_SEC)
Oliver Neukum 562185
 
Oliver Neukum 562185
 #if __BITS_PER_LONG == 64
Oliver Neukum 562185
 
Oliver Neukum 562185
@@ -188,10 +190,13 @@ static inline bool timespec64_valid_stri
Oliver Neukum 562185
  */
Oliver Neukum 562185
 static inline s64 timespec64_to_ns(const struct timespec64 *ts)
Oliver Neukum 562185
 {
Oliver Neukum 562185
-	/* Prevent multiplication overflow */
Oliver Neukum 562185
-	if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX)
Oliver Neukum 562185
+	/* Prevent multiplication overflow / underflow */
Oliver Neukum 562185
+	if (ts->tv_sec >= KTIME_SEC_MAX)
Oliver Neukum 562185
 		return KTIME_MAX;
Oliver Neukum 562185
 
Oliver Neukum 562185
+	if (ts->tv_sec <= KTIME_SEC_MIN)
Oliver Neukum 562185
+		return KTIME_MIN;
Oliver Neukum 562185
+
Oliver Neukum 562185
 	return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
Oliver Neukum 562185
 }
Oliver Neukum 562185