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 <wangxiongfe...@huawei.com>
Signed-off-by: Hongbo Yao <yaohon...@huawei.com>
---
 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

Reply via email to