]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
time-util: fix overflow condition in usec_sub_signed()
authorLennart Poettering <lennart@poettering.net>
Wed, 24 Aug 2022 08:41:23 +0000 (10:41 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 24 Aug 2022 20:41:40 +0000 (21:41 +0100)
If the delta specified is INT64_MIN, and we negate that we'd end up at
INT64_MAX+1 which is outside of the int64_t type. Hence let's treat this
case specifically to avoid unintended overflows.

src/basic/time-util.h
src/test/test-time-util.c

index bf312442b0eae741dddc77c7b9c731ce22a747dd..c98f95a5301d85ccc6f29ce0c5b479b530c3de58 100644 (file)
@@ -189,10 +189,15 @@ static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) {
 }
 
 static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
+        if (delta == INT64_MIN) { /* prevent overflow */
+                assert_cc(-(INT64_MIN + 1) == INT64_MAX);
+                assert_cc(USEC_INFINITY > INT64_MAX);
+                return usec_add(timestamp, (usec_t) INT64_MAX + 1);
+        }
         if (delta < 0)
                 return usec_add(timestamp, (usec_t) (-delta));
-        else
-                return usec_sub_unsigned(timestamp, (usec_t) delta);
+
+        return usec_sub_unsigned(timestamp, (usec_t) delta);
 }
 
 #if SIZEOF_TIME_T == 8
index 58c5fa9be40cc6574f075bd611b0ac800b699d74..6b546fb9f572daf185262cfbe5df80fd5bdc40c9 100644 (file)
@@ -311,10 +311,26 @@ TEST(usec_sub_signed) {
         assert_se(usec_sub_signed(4, 1) == 3);
         assert_se(usec_sub_signed(4, 4) == 0);
         assert_se(usec_sub_signed(4, 5) == 0);
+
         assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY);
         assert_se(usec_sub_signed(USEC_INFINITY-3, -4) == USEC_INFINITY);
         assert_se(usec_sub_signed(USEC_INFINITY-3, -5) == USEC_INFINITY);
         assert_se(usec_sub_signed(USEC_INFINITY, 5) == USEC_INFINITY);
+
+        assert_se(usec_sub_signed(0, INT64_MAX) == 0);
+        assert_se(usec_sub_signed(0, -INT64_MAX) == INT64_MAX);
+        assert_se(usec_sub_signed(0, INT64_MIN) == (usec_t) INT64_MAX + 1);
+        assert_se(usec_sub_signed(0, -(INT64_MIN+1)) == 0);
+
+        assert_se(usec_sub_signed(USEC_INFINITY, INT64_MAX) == USEC_INFINITY);
+        assert_se(usec_sub_signed(USEC_INFINITY, -INT64_MAX) == USEC_INFINITY);
+        assert_se(usec_sub_signed(USEC_INFINITY, INT64_MIN) == USEC_INFINITY);
+        assert_se(usec_sub_signed(USEC_INFINITY, -(INT64_MIN+1)) == USEC_INFINITY);
+
+        assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MAX) == USEC_INFINITY-1-INT64_MAX);
+        assert_se(usec_sub_signed(USEC_INFINITY-1, -INT64_MAX) == USEC_INFINITY);
+        assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MIN) == USEC_INFINITY);
+        assert_se(usec_sub_signed(USEC_INFINITY-1, -(INT64_MIN+1)) == USEC_INFINITY-1-((usec_t) (-(INT64_MIN+1))));
 }
 
 TEST(format_timestamp) {