diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2018-11-06 12:36:54 +0900 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2018-11-06 19:24:47 +0300 |
commit | ed2e7967befb9074df92d0b8dab3863133e11462 (patch) | |
tree | 1b265820a1b5fee63b4628984b89fbcf7b5cd62d | |
parent | a0ca258adf97bf25bbe9714a5bb54e64371e098a (diff) | |
download | systemd-ed2e7967befb9074df92d0b8dab3863133e11462.tar.gz systemd-ed2e7967befb9074df92d0b8dab3863133e11462.tar.bz2 systemd-ed2e7967befb9074df92d0b8dab3863133e11462.zip |
time-util: make parse_sec() not accept "12.34.56"
This also changes the rational number treatment.
So, the limitations introduced by 8079c90333422bbc008b68a9b7cefbdb8a15a4e9
and f6a178e91dd5fccf43f659eca887788fd5dcdccf are relaxed.
Fixes #10619.
-rw-r--r-- | src/basic/time-util.c | 211 | ||||
-rw-r--r-- | src/test/test-time-util.c | 28 |
2 files changed, 136 insertions, 103 deletions
diff --git a/src/basic/time-util.c b/src/basic/time-util.c index e351684219..5dc3a7990b 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -868,7 +868,7 @@ int parse_timestamp(const char *t, usec_t *usec) { return tmp.return_value; } -static char* extract_multiplier(char *p, usec_t *multiplier) { +static const char* extract_multiplier(const char *p, usec_t *multiplier) { static const struct { const char *suffix; usec_t usec; @@ -942,8 +942,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { for (;;) { usec_t multiplier = default_unit, k; - long long l, z = 0; - unsigned n = 0; + long long l; char *e; p += strspn(p, WHITESPACE); @@ -966,46 +965,47 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { return -ERANGE; if (*e == '.') { - char *b = e + 1; - - /* Don't allow "0.-0", "3.+1" or "3. 1" */ - if (IN_SET(*b, '-', '+') || isspace(*b)) - return -EINVAL; - - errno = 0; - z = strtoll(b, &e, 10); - if (errno > 0) - return -errno; - if (z < 0) - return -ERANGE; - if (e == b) - return -EINVAL; - - n = e - b; - + p = e + 1; + p += strspn(p, DIGITS); } else if (e == p) return -EINVAL; + else + p = e; - e += strspn(e, WHITESPACE); - p = extract_multiplier(e, &multiplier); + s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier); + if (s == p && *s != '\0') + /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/ + return -EINVAL; - something = true; + p = s; + if ((usec_t) l >= USEC_INFINITY / multiplier) + return -ERANGE; - k = ((usec_t) -1) / multiplier; - if ((usec_t) l + 1 >= k || (usec_t) z >= k) + k = (usec_t) l * multiplier; + if (k >= USEC_INFINITY - r) return -ERANGE; - k = (usec_t) z * multiplier; + r += k; - for (; n > 0; n--) - k /= 10; + something = true; - k += (usec_t) l * multiplier; - if (k >= ((usec_t) -1) - r) - return -ERANGE; + if (*e == '.') { + usec_t m = multiplier / 10; + const char *b; - r += k; + for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) { + k = (usec_t) (*b - '0') * m; + if (k >= USEC_INFINITY - r) + return -ERANGE; + + r += k; + } + + /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/ + if (b == e + 1) + return -EINVAL; + } } *usec = r; @@ -1032,44 +1032,60 @@ int parse_sec_fix_0(const char *t, usec_t *ret) { return r; } -int parse_nsec(const char *t, nsec_t *nsec) { +static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) { static const struct { const char *suffix; nsec_t nsec; } table[] = { - { "seconds", NSEC_PER_SEC }, - { "second", NSEC_PER_SEC }, - { "sec", NSEC_PER_SEC }, - { "s", NSEC_PER_SEC }, + { "seconds", NSEC_PER_SEC }, + { "second", NSEC_PER_SEC }, + { "sec", NSEC_PER_SEC }, + { "s", NSEC_PER_SEC }, { "minutes", NSEC_PER_MINUTE }, - { "minute", NSEC_PER_MINUTE }, - { "min", NSEC_PER_MINUTE }, - { "months", NSEC_PER_MONTH }, - { "month", NSEC_PER_MONTH }, - { "msec", NSEC_PER_MSEC }, - { "ms", NSEC_PER_MSEC }, - { "m", NSEC_PER_MINUTE }, - { "hours", NSEC_PER_HOUR }, - { "hour", NSEC_PER_HOUR }, - { "hr", NSEC_PER_HOUR }, - { "h", NSEC_PER_HOUR }, - { "days", NSEC_PER_DAY }, - { "day", NSEC_PER_DAY }, - { "d", NSEC_PER_DAY }, - { "weeks", NSEC_PER_WEEK }, - { "week", NSEC_PER_WEEK }, - { "w", NSEC_PER_WEEK }, - { "years", NSEC_PER_YEAR }, - { "year", NSEC_PER_YEAR }, - { "y", NSEC_PER_YEAR }, - { "usec", NSEC_PER_USEC }, - { "us", NSEC_PER_USEC }, - { "µs", NSEC_PER_USEC }, - { "nsec", 1ULL }, - { "ns", 1ULL }, - { "", 1ULL }, /* default is nsec */ + { "minute", NSEC_PER_MINUTE }, + { "min", NSEC_PER_MINUTE }, + { "months", NSEC_PER_MONTH }, + { "month", NSEC_PER_MONTH }, + { "M", NSEC_PER_MONTH }, + { "msec", NSEC_PER_MSEC }, + { "ms", NSEC_PER_MSEC }, + { "m", NSEC_PER_MINUTE }, + { "hours", NSEC_PER_HOUR }, + { "hour", NSEC_PER_HOUR }, + { "hr", NSEC_PER_HOUR }, + { "h", NSEC_PER_HOUR }, + { "days", NSEC_PER_DAY }, + { "day", NSEC_PER_DAY }, + { "d", NSEC_PER_DAY }, + { "weeks", NSEC_PER_WEEK }, + { "week", NSEC_PER_WEEK }, + { "w", NSEC_PER_WEEK }, + { "years", NSEC_PER_YEAR }, + { "year", NSEC_PER_YEAR }, + { "y", NSEC_PER_YEAR }, + { "usec", NSEC_PER_USEC }, + { "us", NSEC_PER_USEC }, + { "µs", NSEC_PER_USEC }, + { "nsec", 1ULL }, + { "ns", 1ULL }, + { "", 1ULL }, /* default is nsec */ }; + size_t i; + + for (i = 0; i < ELEMENTSOF(table); i++) { + char *e; + + e = startswith(p, table[i].suffix); + if (e) { + *multiplier = table[i].nsec; + return e; + } + } + + return p; +} +int parse_nsec(const char *t, nsec_t *nsec) { const char *p, *s; nsec_t r = 0; bool something = false; @@ -1091,8 +1107,8 @@ int parse_nsec(const char *t, nsec_t *nsec) { } for (;;) { - long long l, z = 0; - size_t n = 0, i; + nsec_t multiplier = 1, k; + long long l; char *e; p += strspn(p, WHITESPACE); @@ -1104,7 +1120,7 @@ int parse_nsec(const char *t, nsec_t *nsec) { break; } - if (*p == '-') + if (*p == '-') /* Don't allow "-0" */ return -ERANGE; errno = 0; @@ -1115,54 +1131,47 @@ int parse_nsec(const char *t, nsec_t *nsec) { return -ERANGE; if (*e == '.') { - char *b = e + 1; - - if (IN_SET(*b, '-', '+') || isspace(*b)) - return -EINVAL; - - errno = 0; - z = strtoll(b, &e, 10); - if (errno > 0) - return -errno; - if (z < 0) - return -ERANGE; - if (e == b) - return -EINVAL; - - n = e - b; - + p = e + 1; + p += strspn(p, DIGITS); } else if (e == p) return -EINVAL; + else + p = e; - e += strspn(e, WHITESPACE); + s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier); + if (s == p && *s != '\0') + /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/ + return -EINVAL; - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - nsec_t k; + p = s; - k = ((nsec_t) -1) / table[i].nsec; - if ((nsec_t) l + 1 >= k || (nsec_t) z >= k) - return -ERANGE; + if ((nsec_t) l >= NSEC_INFINITY / multiplier) + return -ERANGE; + + k = (nsec_t) l * multiplier; + if (k >= NSEC_INFINITY - r) + return -ERANGE; - k = (nsec_t) z * table[i].nsec; + r += k; + + something = true; - for (; n > 0; n--) - k /= 10; + if (*e == '.') { + nsec_t m = multiplier / 10; + const char *b; - k += (nsec_t) l * table[i].nsec; - if (k >= ((nsec_t) -1) - r) + for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) { + k = (nsec_t) (*b - '0') * m; + if (k >= NSEC_INFINITY - r) return -ERANGE; r += k; - p = e + strlen(table[i].suffix); - - something = true; - break; } - if (i >= ELEMENTSOF(table)) - return -EINVAL; - + /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/ + if (b == e + 1) + return -EINVAL; + } } *nsec = r; diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c index 00051eb434..2ec2ade3f1 100644 --- a/src/test/test-time-util.c +++ b/src/test/test-time-util.c @@ -39,6 +39,14 @@ static void test_parse_sec(void) { assert_se(u == USEC_INFINITY); assert_se(parse_sec("+3.1s", &u) >= 0); assert_se(u == 3100 * USEC_PER_MSEC); + assert_se(parse_sec("3.1s.2", &u) >= 0); + assert_se(u == 3300 * USEC_PER_MSEC); + assert_se(parse_sec("3.1 .2", &u) >= 0); + assert_se(u == 3300 * USEC_PER_MSEC); + assert_se(parse_sec("3.1 sec .2 sec", &u) >= 0); + assert_se(u == 3300 * USEC_PER_MSEC); + assert_se(parse_sec("3.1 sec 1.2 sec", &u) >= 0); + assert_se(u == 4300 * USEC_PER_MSEC); assert_se(parse_sec(" xyz ", &u) < 0); assert_se(parse_sec("", &u) < 0); @@ -56,6 +64,10 @@ static void test_parse_sec(void) { assert_se(parse_sec("3.+1s", &u) < 0); assert_se(parse_sec("3. 1s", &u) < 0); assert_se(parse_sec("3.s", &u) < 0); + assert_se(parse_sec("12.34.56", &u) < 0); + assert_se(parse_sec("12..34", &u) < 0); + assert_se(parse_sec("..1234", &u) < 0); + assert_se(parse_sec("1234..", &u) < 0); } static void test_parse_sec_fix_0(void) { @@ -97,7 +109,7 @@ static void test_parse_time(void) { assert_se(u == 5 * USEC_PER_SEC); assert_se(parse_time("11111111111111y", &u, 1) == -ERANGE); - assert_se(parse_time("1.1111111111111y", &u, 1) == -ERANGE); + assert_se(parse_time("1.1111111111111y", &u, 1) >= 0); } static void test_parse_nsec(void) { @@ -129,6 +141,14 @@ static void test_parse_nsec(void) { assert_se(u == NSEC_INFINITY); assert_se(parse_nsec("+3.1s", &u) >= 0); assert_se(u == 3100 * NSEC_PER_MSEC); + assert_se(parse_nsec("3.1s.2", &u) >= 0); + assert_se(u == 3100 * NSEC_PER_MSEC); + assert_se(parse_nsec("3.1 .2s", &u) >= 0); + assert_se(u == 200 * NSEC_PER_MSEC + 3); + assert_se(parse_nsec("3.1 sec .2 sec", &u) >= 0); + assert_se(u == 3300 * NSEC_PER_MSEC); + assert_se(parse_nsec("3.1 sec 1.2 sec", &u) >= 0); + assert_se(u == 4300 * NSEC_PER_MSEC); assert_se(parse_nsec(" xyz ", &u) < 0); assert_se(parse_nsec("", &u) < 0); @@ -148,8 +168,12 @@ static void test_parse_nsec(void) { assert_se(parse_nsec("3.+1s", &u) < 0); assert_se(parse_nsec("3. 1s", &u) < 0); assert_se(parse_nsec("3.s", &u) < 0); + assert_se(parse_nsec("12.34.56", &u) < 0); + assert_se(parse_nsec("12..34", &u) < 0); + assert_se(parse_nsec("..1234", &u) < 0); + assert_se(parse_nsec("1234..", &u) < 0); assert_se(parse_nsec("1111111111111y", &u) == -ERANGE); - assert_se(parse_nsec("1.111111111111y", &u) == -ERANGE); + assert_se(parse_nsec("1.111111111111y", &u) >= 0); } static void test_format_timespan_one(usec_t x, usec_t accuracy) { |