[RFC PATCH 1/2] ktime: add ktime_sub_safe() to avoid undefined behaviour

From: Hongbo Yao
Date: Wed Mar 06 2019 - 08:00:56 EST


This patch add a new ktime_sub_unsafe() helper which won't throw a
UBSAN warning when it does overflows, and then it add ktime_sub_safe()
which will check if the result of ktime_sub_unsafe overflows.This patch
modify the above functions to use ktime_sub_safe instead of ktime_sub();

Signed-off-by: Xiongfeng Wang <wangxiongfeng2@xxxxxxxxxx>
Signed-off-by: Hongbo Yao <yaohongbo@xxxxxxxxxx>
---
include/linux/ktime.h | 8 ++++++++
kernel/time/hrtimer.c | 16 ++++++++++++++++
2 files changed, 24 insertions(+)

diff --git a/include/linux/ktime.h b/include/linux/ktime.h
index b2bb44f87f5a..325e794b0dd1 100644
--- a/include/linux/ktime.h
+++ b/include/linux/ktime.h
@@ -45,6 +45,12 @@ static inline ktime_t ktime_set(const s64 secs, const unsigned long nsecs)
/* Subtract two ktime_t variables. rem = lhs -rhs: */
#define ktime_sub(lhs, rhs) ((lhs) - (rhs))

+/*
+ * Same as ktime_sub(), but avoids undefined behaviour on overflow; however,
+ * this means that you must check the result for overflow yourself.
+ */
+#define ktime_sub_unsafe(lhs, rhs) ((u64) (lhs) - (rhs))
+
/* Add two ktime_t variables. res = lhs + rhs: */
#define ktime_add(lhs, rhs) ((lhs) + (rhs))

@@ -215,6 +221,8 @@ static inline ktime_t ktime_sub_ms(const ktime_t kt, const u64 msec)

extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs);

+extern ktime_t ktime_sub_safe(const ktime_t lhs, const ktime_t rhs);
+
/**
* ktime_to_timespec_cond - convert a ktime_t variable to timespec
* format only if the variable contains data
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index e1a549c9e399..cadc5bcbfc9e 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -317,6 +317,22 @@ s64 __ktime_divns(const ktime_t kt, s64 div)
EXPORT_SYMBOL_GPL(__ktime_divns);
#endif /* BITS_PER_LONG >= 64 */

+/*
+ * sub two ktime values and do a safety check for overflow:
+ */
+ktime_t ktime_sub_safe(const ktime_t lhs, const ktime_t rhs)
+{
+ ktime_t res = ktime_sub_unsafe(lhs, rhs);
+
+ if (lhs > 0 && rhs < 0 && res < 0)
+ res = ktime_set(KTIME_SEC_MAX, 0);
+ else if (lhs < 0 && rhs > 0 && res > 0)
+ res = ktime_set(-KTIME_SEC_MAX, 0);
+
+ return res;
+}
+EXPORT_SYMBOL_GPL(ktime_sub_safe);
+
/*
* Add two ktime values and do a safety check for overflow:
*/
--
2.20.1