Blob Blame History Raw
From e34f90aba7c18c1552a4d3438c2e1d75c6cbe77d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 5 Jun 2013 19:33:45 -0400
Subject: [PATCH] Properly check for overflow in offsets

(cherry picked from commit b32ff512191bf873266ee8067f6f6c8a30c96a5e)
---
 src/shared/util.c    | 18 ++++++++++++++----
 src/test/test-util.c | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/src/shared/util.c b/src/shared/util.c
index 1526b92c25..14820be6fe 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -2265,7 +2265,7 @@ ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
 int parse_bytes(const char *t, off_t *bytes) {
         static const struct {
                 const char *suffix;
-                off_t factor;
+                unsigned long long factor;
         } table[] = {
                 { "B", 1 },
                 { "K", 1024ULL },
@@ -2278,7 +2278,7 @@ int parse_bytes(const char *t, off_t *bytes) {
         };
 
         const char *p;
-        off_t r = 0;
+        unsigned long long r = 0;
 
         assert(t);
         assert(bytes);
@@ -2305,7 +2305,17 @@ int parse_bytes(const char *t, off_t *bytes) {
 
                 for (i = 0; i < ELEMENTSOF(table); i++)
                         if (startswith(e, table[i].suffix)) {
-                                r += (off_t) l * table[i].factor;
+                                unsigned long long tmp;
+                                if ((unsigned long long) l > ULLONG_MAX / table[i].factor)
+                                        return -ERANGE;
+                                tmp = l * table[i].factor;
+                                if (tmp > ULLONG_MAX - r)
+                                        return -ERANGE;
+
+                                r += tmp;
+                                if ((unsigned long long) (off_t) r != r)
+                                        return -ERANGE;
+
                                 p = e + strlen(table[i].suffix);
                                 break;
                         }
@@ -2313,7 +2323,7 @@ int parse_bytes(const char *t, off_t *bytes) {
                 if (i >= ELEMENTSOF(table))
                         return -EINVAL;
 
-        } while (*p != 0);
+        } while (*p);
 
         *bytes = r;
 
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 4c3a8a6b88..9396aebd63 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -439,6 +439,44 @@ static void test_protect_errno(void) {
         assert(errno == 12);
 }
 
+static void test_parse_bytes(void) {
+        off_t bytes;
+
+        assert_se(parse_bytes("111", &bytes) == 0);
+        assert_se(bytes == 111);
+
+        assert_se(parse_bytes(" 112 B", &bytes) == 0);
+        assert_se(bytes == 112);
+
+        assert_se(parse_bytes("3 K", &bytes) == 0);
+        assert_se(bytes == 3*1024);
+
+        assert_se(parse_bytes(" 4 M 11K", &bytes) == 0);
+        assert_se(bytes == 4*1024*1024 + 11 * 1024);
+
+        assert_se(parse_bytes("3B3G", &bytes) == 0);
+        assert_se(bytes == 3ULL*1024*1024*1024 + 3);
+
+        assert_se(parse_bytes("3B3G4T", &bytes) == 0);
+        assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
+
+        assert_se(parse_bytes("12P", &bytes) == 0);
+        assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024);
+
+        assert_se(parse_bytes("3E 2P", &bytes) == 0);
+        assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024);
+
+        assert_se(parse_bytes("12X", &bytes) == -EINVAL);
+
+        assert_se(parse_bytes("1024E", &bytes) == -ERANGE);
+        assert_se(parse_bytes("-1", &bytes) == -ERANGE);
+        assert_se(parse_bytes("-1024E", &bytes) == -ERANGE);
+
+        assert_se(parse_bytes("-1024P", &bytes) == -ERANGE);
+
+        assert_se(parse_bytes("-10B 20K", &bytes) == -ERANGE);
+}
+
 int main(int argc, char *argv[]) {
         test_streq_ptr();
         test_first_word();
@@ -467,6 +505,7 @@ int main(int argc, char *argv[]) {
         test_u64log2();
         test_get_process_comm();
         test_protect_errno();
+        test_parse_bytes();
 
         return 0;
 }