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