Commit 697ac639 authored by Stephen Hemminger's avatar Stephen Hemminger

utils: fix range checking for get_u32/get_u64 et all

Be more careful about overflow in strtoXX routines.
Checks are based on documented interface on man pages.
Based on suggestion from "Mr Dash Four".
Signed-off-by: default avatarStephen Hemminger <stephen@networkplumber.org>
parent ce93fffe
......@@ -12,6 +12,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
......@@ -38,9 +39,28 @@ int get_integer(int *val, const char *arg, int base)
if (!arg || !*arg)
return -1;
res = strtol(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN)
/* If there were no digits at all, strtol() stores
* the original value of nptr in *endptr (and returns 0).
* In particular, if *nptr is not '\0' but **endptr is '\0' on return,
* the entire string is valid.
*/
if (!ptr || ptr == arg || *ptr)
return -1;
/* If an underflow occurs, strtol() returns LONG_MIN.
* If an overflow occurs, strtol() returns LONG_MAX.
* In both cases, errno is set to ERANGE.
*/
if ((res == LONG_MAX || res == LONG_MIN) && errno == ERANGE)
return -1;
/* Outside range of int */
if (res < INT_MIN || res > INT_MAX)
return -1;
*val = res;
return 0;
}
......@@ -87,9 +107,21 @@ int get_unsigned(unsigned *val, const char *arg, int base)
if (!arg || !*arg)
return -1;
res = strtoul(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
/* empty string or trailing non-digits */
if (!ptr || ptr == arg || *ptr)
return -1;
/* overflow */
if (res == ULONG_MAX && errno == ERANGE)
return -1;
/* out side range of unsigned */
if (res > UINT_MAX)
return -1;
*val = res;
return 0;
}
......@@ -107,17 +139,32 @@ int get_time_rtt(unsigned *val, const char *arg, int *raw)
unsigned long res;
char *p;
if (strchr(arg,'.') != NULL) {
t = strtod(arg,&p);
if (strchr(arg, '.') != NULL) {
t = strtod(arg, &p);
if (t < 0.0)
return -1;
}
else {
/* extra non-digits */
if (!p || p == arg || *p)
return -1;
/* over/underflow */
if ((t == HUGE_VALF || t == HUGE_VALL) && errno == ERANGE)
return -1;
} else {
res = strtoul(arg, &p, 0);
if (res > UINT_MAX)
/* empty string or trailing non-digits */
if (!p || p == arg || *p)
return -1;
/* overflow */
if (res == ULONG_MAX && errno == ERANGE)
return -1;
t = (double)res;
}
if (p == arg)
return -1;
*raw = 1;
......@@ -151,9 +198,21 @@ int get_u64(__u64 *val, const char *arg, int base)
if (!arg || !*arg)
return -1;
res = strtoull(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res == 0xFFFFFFFFULL)
return -1;
/* empty string or trailing non-digits */
if (!ptr || ptr == arg || *ptr)
return -1;
/* overflow */
if (res == ULLONG_MAX && errno == ERANGE)
return -1;
/* in case ULL is 128 bits */
if (res > 0xFFFFFFFFFFFFFFFFULL)
return -1;
*val = res;
return 0;
}
......@@ -166,8 +225,19 @@ int get_u32(__u32 *val, const char *arg, int base)
if (!arg || !*arg)
return -1;
res = strtoul(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
/* empty string or trailing non-digits */
if (!ptr || ptr == arg || *ptr)
return -1;
/* overflow */
if (res == ULONG_MAX && errno == ERANGE)
return -1;
/* in case UL > 32 bits */
if (res > 0xFFFFFFFFUL)
return -1;
*val = res;
return 0;
}
......@@ -180,8 +250,18 @@ int get_u16(__u16 *val, const char *arg, int base)
if (!arg || !*arg)
return -1;
res = strtoul(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
/* empty string or trailing non-digits */
if (!ptr || ptr == arg || *ptr)
return -1;
/* overflow */
if (res == ULONG_MAX && errno == ERANGE)
return -1;
if (res > 0xFFFFUL)
return -1;
*val = res;
return 0;
}
......@@ -193,9 +273,19 @@ int get_u8(__u8 *val, const char *arg, int base)
if (!arg || !*arg)
return -1;
res = strtoul(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > 0xFF)
/* empty string or trailing non-digits */
if (!ptr || ptr == arg || *ptr)
return -1;
/* overflow */
if (res == ULONG_MAX && errno == ERANGE)
return -1;
if (res > 0xFFUL)
return -1;
*val = res;
return 0;
}
......@@ -210,10 +300,13 @@ int get_s32(__s32 *val, const char *arg, int base)
if (!arg || !*arg)
return -1;
res = strtol(arg, &ptr, base);
if (ptr == arg || *ptr ||
((res == LONG_MIN || res == LONG_MAX) && errno == ERANGE) ||
res > INT32_MAX || res < INT32_MIN)
if (!ptr || ptr == arg || *ptr)
return -1;
if ((res == LONG_MIN || res == LONG_MAX) && errno == ERANGE)
return -1;
if (res > INT32_MAX || res < INT32_MIN)
return -1;
*val = res;
return 0;
}
......@@ -226,8 +319,13 @@ int get_s16(__s16 *val, const char *arg, int base)
if (!arg || !*arg)
return -1;
res = strtol(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000)
if (!ptr || ptr == arg || *ptr)
return -1;
if ((res == LONG_MIN || res == LONG_MAX) && errno == ERANGE)
return -1;
if (res > 0x7FFF || res < -0x8000)
return -1;
*val = res;
return 0;
}
......@@ -240,7 +338,11 @@ int get_s8(__s8 *val, const char *arg, int base)
if (!arg || !*arg)
return -1;
res = strtol(arg, &ptr, base);
if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80)
if (!ptr || ptr == arg || *ptr)
return -1;
if ((res == LONG_MIN || res == LONG_MAX) && errno == ERANGE)
return -1;
if (res > 0x7F || res < -0x80)
return -1;
*val = res;
return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment