diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-11-10 17:27:16 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-11-10 17:36:52 +0100 |
commit | 2d49a208f8ad9d1c4e79fa4302451e35d06de707 (patch) | |
tree | b5e272a774f7f3d26e6ed876445e58bf409ada8e | |
parent | b374689c02c681671a3c3c0b0fd3add32386b442 (diff) |
parse-util: really refuse parsing negative values as positive ones, even on x86-32
strtoull() doesn't make it particularly easy to detect passed-in
negative numbers, as it silently converts them to positive ones without
generating any error. Since we are not interested in negative values we
should hence explicitly filter them out by looking at the string
directly and returning ERANGE if we see a leading "-".
Fixes: #1829
-rw-r--r-- | src/basic/parse-util.c | 100 |
1 files changed, 66 insertions, 34 deletions
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index b6358c459a..151067e916 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -67,11 +67,14 @@ int parse_mode(const char *s, mode_t *ret) { assert(s); assert(ret); + s += strspn(s, WHITESPACE); + if (s[0] == '-') + return -ERANGE; + errno = 0; l = strtol(s, &x, 8); if (errno != 0) return -errno; - if (!x || x == s || *x) return -EINVAL; if (l < 0 || l > 07777) @@ -162,15 +165,15 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { unsigned i; p += strspn(p, WHITESPACE); - if (*p == '-') - return -ERANGE; errno = 0; l = strtoull(p, &e, 10); - if (errno > 0) + if (errno != 0) return -errno; if (e == p) return -EINVAL; + if (*p == '-') + return -ERANGE; if (*e == '.') { e++; @@ -181,7 +184,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { char *e2; l2 = strtoull(e, &e2, 10); - if (errno > 0) + if (errno != 0) return -errno; /* Ignore failure. E.g. 10.M is valid */ @@ -307,12 +310,24 @@ int safe_atou(const char *s, unsigned *ret_u) { assert(s); assert(ret_u); - errno = 0; - l = strtoul(s, &x, 0); + /* strtoul() is happy to parse negative values, and silently + * converts them to unsigned values without generating an + * error. We want a clean error, hence let's look for the "-" + * prefix on our own, and generate an error. But let's do so + * only after strtoul() validated that the string is clean + * otherwise, so that we return EINVAL preferably over + * ERANGE. */ - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; + s += strspn(s, WHITESPACE); + errno = 0; + l = strtoul(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; if ((unsigned long) (unsigned) l != l) return -ERANGE; @@ -329,10 +344,10 @@ int safe_atoi(const char *s, int *ret_i) { errno = 0; l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; if ((long) (int) l != l) return -ERANGE; @@ -347,11 +362,16 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) { assert(s); assert(ret_llu); + s += strspn(s, WHITESPACE); + errno = 0; l = strtoull(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (*s == '-') + return -ERANGE; *ret_llu = l; return 0; @@ -366,9 +386,10 @@ int safe_atolli(const char *s, long long int *ret_lli) { errno = 0; l = strtoll(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; *ret_lli = l; return 0; @@ -381,12 +402,16 @@ int safe_atou8(const char *s, uint8_t *ret) { assert(s); assert(ret); + s += strspn(s, WHITESPACE); + errno = 0; l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; if ((unsigned long) (uint8_t) l != l) return -ERANGE; @@ -401,12 +426,16 @@ int safe_atou16(const char *s, uint16_t *ret) { assert(s); assert(ret); + s += strspn(s, WHITESPACE); + errno = 0; l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; if ((unsigned long) (uint16_t) l != l) return -ERANGE; @@ -423,10 +452,10 @@ int safe_atoi16(const char *s, int16_t *ret) { errno = 0; l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; if ((long) (int16_t) l != l) return -ERANGE; @@ -448,10 +477,13 @@ int safe_atod(const char *s, double *ret_d) { errno = 0; d = strtod_l(s, &x, loc); - - if (!x || x == s || *x || errno) { + if (errno != 0) { freelocale(loc); - return errno ? -errno : -EINVAL; + return -errno; + } + if (!x || x == s || *x) { + freelocale(loc); + return -EINVAL; } freelocale(loc); |