summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2018-11-06 12:36:54 +0900
committerLennart Poettering <lennart@poettering.net>2018-11-06 19:24:47 +0300
commited2e7967befb9074df92d0b8dab3863133e11462 (patch)
tree1b265820a1b5fee63b4628984b89fbcf7b5cd62d
parenta0ca258adf97bf25bbe9714a5bb54e64371e098a (diff)
downloadsystemd-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.c211
-rw-r--r--src/test/test-time-util.c28
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) {