summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-11-10 17:27:16 +0100
committerLennart Poettering <lennart@poettering.net>2015-11-10 17:36:52 +0100
commit2d49a208f8ad9d1c4e79fa4302451e35d06de707 (patch)
treeb5e272a774f7f3d26e6ed876445e58bf409ada8e
parentb374689c02c681671a3c3c0b0fd3add32386b442 (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.c100
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);