summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2013-06-05 19:33:45 -0400
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2013-06-10 10:10:06 -0400
commitb32ff512191bf873266ee8067f6f6c8a30c96a5e (patch)
treeec7442f8e8967af14804e673adec4f4e0deb5c38
parent3001c74580c1713bd634990a0b2ab351fdec7a98 (diff)
Properly check for overflow in offsets
-rw-r--r--src/shared/util.c18
-rw-r--r--src/test/test-util.c39
2 files changed, 53 insertions, 4 deletions
diff --git a/src/shared/util.c b/src/shared/util.c
index d0bbf78bf3..17928ec36e 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -2261,7 +2261,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 },
@@ -2274,7 +2274,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);
@@ -2301,7 +2301,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;
}
@@ -2309,7 +2319,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;
}