On Wed, Jul 29, 2020 at 07:39:43PM +0200, Klemens Nanni wrote:
>
> Poking and testing around in brconfig.c for tpmr(4) stuff, I noticed a
> lot of old code around strto*l(3).
>
> Many pass unbounded `long' values into the `[u]int32_t' struct members
> without limiting them to at least the type size the value is stored in,
> some report wrong commands in error messages, e.g.
>
> # ifconfig switch1 portno vether1 9223372036854775808 # LONG_MAX + 1
> ifconfig: invalid arg for portidx: 9223372036854775808
>
> some pass values to the kernel that are above limits documented in
> ifconfig(8), e.g.
>
> # ifconfig bridge0 maxage 50
> ifconfig: bridge0: Invalid argument
>
> and others overflow in-kernel due to that (causing persistent damage
> that causes deleting and adding bridge members to fix it).
>
> I'm aware that moving to strtonum(3) drops the ability to pass numbers
> in bases others than ten, e.g. `ifconfig bridge0 ifcost vether0 0x3'
> mut now be `... 15', but all of the options really want a decimal number
> as far as I can judge after reading ifconfig(8) and testing them.
>
> The only exception to this is switch(4)'s `datapath' which is printed in
> hexadecimal, so I left it untouched such that it can be copy-pasted and
> set as is.
>
> Diff below applies converts all places to the very same strtonum() idiom
> with proper range checks based on documented or type limits.
>
> I've tested each option manually: valid values are still valid and but
> more out of range values are catched now, many of them up front in
> ifconfig rather than the kerne's ioctl() path.
>
> I've also checked most of the ioctl() paths to see what those really
> check for. One or two diffs for the kernel should follow soon.
>
> Feedback? OK?
Ping.
Alternatively, we can avoid duplicating the ioctl specific min/max
values in strtonum(3) calls, just use the struct member type's *_MAX
defines and rely on the kernel for appropiate boundary checks - this is
what the code does now.
Feedback? OK?
Index: brconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/brconfig.c,v
retrieving revision 1.28
diff -u -p -r1.28 brconfig.c
--- brconfig.c 5 Aug 2020 06:22:11 -0000 1.28
+++ brconfig.c 8 Aug 2020 03:04:30 -0000
@@ -419,18 +419,13 @@ void
bridge_timeout(const char *arg, int d)
{
struct ifbrparam bp;
- long newtime;
- char *endptr;
+ const char *errstr;
- errno = 0;
- newtime = strtol(arg, &endptr, 0);
- if (arg[0] == '\0' || endptr[0] != '\0' ||
- (newtime & ~INT_MAX) != 0L ||
- (errno == ERANGE && newtime == LONG_MAX))
- errx(1, "invalid arg for timeout: %s", arg);
+ bp.ifbrp_ctime = strtonum(arg, 0, UINT32_MAX, &errstr);
+ if (errstr)
+ err(1, "timeout %s is: %s", arg, errstr);
strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
- bp.ifbrp_ctime = newtime;
if (ioctl(sock, SIOCBRDGSTO, (caddr_t)&bp) == -1)
err(1, "%s", ifname);
}
@@ -439,17 +434,13 @@ void
bridge_maxage(const char *arg, int d)
{
struct ifbrparam bp;
- unsigned long v;
- char *endptr;
+ const char *errstr;
- errno = 0;
- v = strtoul(arg, &endptr, 0);
- if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
- (errno == ERANGE && v == ULONG_MAX))
- errx(1, "invalid arg for maxage: %s", arg);
+ bp.ifbrp_maxage = strtonum(arg, 0, UINT8_MAX, &errstr);
+ if (errstr)
+ errx(1, "maxage %s is: %s", arg, errstr);
strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
- bp.ifbrp_maxage = v;
if (ioctl(sock, SIOCBRDGSMA, (caddr_t)&bp) == -1)
err(1, "%s", ifname);
}
@@ -458,17 +449,13 @@ void
bridge_priority(const char *arg, int d)
{
struct ifbrparam bp;
- unsigned long v;
- char *endptr;
+ const char *errstr;
- errno = 0;
- v = strtoul(arg, &endptr, 0);
- if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffffUL ||
- (errno == ERANGE && v == ULONG_MAX))
- errx(1, "invalid arg for spanpriority: %s", arg);
+ bp.ifbrp_prio = strtonum(arg, 0, UINT16_MAX, &errstr);
+ if (errstr)
+ errx(1, "spanpriority %s is: %s", arg, errstr);
strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
- bp.ifbrp_prio = v;
if (ioctl(sock, SIOCBRDGSPRI, (caddr_t)&bp) == -1)
err(1, "%s", ifname);
}
@@ -479,7 +466,7 @@ bridge_protect(const char *ifsname, cons
struct ifbreq breq;
unsigned long v;
char *optlist, *str;
- char *endptr;
+ const char *errstr;
strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name));
strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
@@ -492,11 +479,9 @@ bridge_protect(const char *ifsname, cons
str = strtok(optlist, ",");
while (str != NULL) {
- errno = 0;
- v = strtoul(str, &endptr, 0);
- if (str[0] == '\0' || endptr[0] != '\0' || v == 0 || v > 31 ||
- (errno == ERANGE && v == ULONG_MAX))
- err(1, "invalid value for protected domain: %s", str);
+ v = strtonum(str, 1, 31, &errstr);
+ if (errstr)
+ err(1, "protected domain %s is: %s", str, errstr);
breq.ifbr_protected |= (1 << (v - 1));
str = strtok(NULL, ",");
}
@@ -545,17 +530,14 @@ void
bridge_fwddelay(const char *arg, int d)
{
struct ifbrparam bp;
- unsigned long v;
- char *endptr;
+ const char *errstr;
- errno = 0;
- v = strtoul(arg, &endptr, 0);
- if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
- (errno == ERANGE && v == ULONG_MAX))
- errx(1, "invalid arg for fwddelay: %s", arg);
+ bp.ifbrp_fwddelay = strtonum(arg, 0, UINT8_MAX, &errstr);
+ if (errstr)
+ errx(1, "fwddelay %s is: %s", arg, errstr);
strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
- bp.ifbrp_fwddelay = v;
+
if (ioctl(sock, SIOCBRDGSFD, (caddr_t)&bp) == -1)
err(1, "%s", ifname);
}
@@ -564,17 +546,14 @@ void
bridge_hellotime(const char *arg, int d)
{
struct ifbrparam bp;
- unsigned long v;
- char *endptr;
+ const char *errstr;
- errno = 0;
- v = strtoul(arg, &endptr, 0);
- if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
- (errno == ERANGE && v == ULONG_MAX))
- errx(1, "invalid arg for hellotime: %s", arg);
+ bp.ifbrp_hellotime = strtonum(arg, 0, UINT8_MAX, &errstr);
+ if (errstr)
+ errx(1, "hellotime %s is: %s", arg, errstr);
strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
- bp.ifbrp_hellotime = v;
+
if (ioctl(sock, SIOCBRDGSHT, (caddr_t)&bp) == -1)
err(1, "%s", ifname);
}
@@ -584,16 +563,13 @@ bridge_maxaddr(const char *arg, int d)
{
struct ifbrparam bp;
unsigned long newsize;
- char *endptr;
+ const char *errstr;
- errno = 0;
- newsize = strtoul(arg, &endptr, 0);
- if (arg[0] == '\0' || endptr[0] != '\0' || newsize > 0xffffffffUL ||
- (errno == ERANGE && newsize == ULONG_MAX))
- errx(1, "invalid arg for maxaddr: %s", arg);
+ bp.ifbrp_csize = strtonum(arg, 0, UINT32_MAX, &errstr);
+ if (errstr)
+ errx(1, "maxaddr %s is: %s", arg, errstr);
strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
- bp.ifbrp_csize = newsize;
if (ioctl(sock, SIOCBRDGSCACHE, (caddr_t)&bp) == -1)
err(1, "%s", ifname);
}
@@ -619,19 +595,15 @@ void
bridge_ifprio(const char *ifsname, const char *val)
{
struct ifbreq breq;
- unsigned long v;
- char *endptr;
+ const char *errstr;
+
+ breq.ifbr_priority = strtonum(val, 0, UINT8_MAX, &errstr);
+ if (errstr)
+ errx(1, "ifpriority %s is: %s", val, errstr);
strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name));
strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
- errno = 0;
- v = strtoul(val, &endptr, 0);
- if (val[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
- (errno == ERANGE && v == ULONG_MAX))
- err(1, "invalid arg for ifpriority: %s", val);
- breq.ifbr_priority = v;
-
if (ioctl(sock, SIOCBRDGSIFPRIO, (caddr_t)&breq) == -1)
err(1, "%s: %s", ifname, val);
}
@@ -640,20 +612,15 @@ void
bridge_ifcost(const char *ifsname, const char *val)
{
struct ifbreq breq;
- unsigned long v;
- char *endptr;
+ const char *errstr;
+
+ breq.ifbr_path_cost = strtonum(val, 0, UINT32_MAX, &errstr);
+ if (errstr)
+ errx(1, "ifcost %s is: %s", val, errstr);
strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name));
strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
- errno = 0;
- v = strtoul(val, &endptr, 0);
- if (val[0] == '\0' || endptr[0] != '\0' || v > 0xffffffffUL ||
- (errno == ERANGE && v == ULONG_MAX))
- errx(1, "invalid arg for ifcost: %s", val);
-
- breq.ifbr_path_cost = v;
-
if (ioctl(sock, SIOCBRDGSIFCOST, (caddr_t)&breq) == -1)
err(1, "%s: %s", ifname, val);
}
@@ -750,7 +717,7 @@ bridge_holdcnt(const char *value, int d)
bp.ifbrp_txhc = strtonum(value, 0, UINT8_MAX, &errstr);
if (errstr)
- err(1, "holdcnt %s %s", value, errstr);
+ err(1, "holdcnt %s is: %s", value, errstr);
strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
if (ioctl(sock, SIOCBRDGSTXHC, (caddr_t)&bp) == -1)
@@ -1213,18 +1180,14 @@ void
switch_portno(const char *ifsname, const char *val)
{
struct ifbreq breq;
- uint32_t newportidx;
- char *endptr;
+ const char *errstr;
+
+ breq.ifbr_portno = strtonum(val, 0, UINT32_MAX, &errstr);
+ if (errstr)
+ errx(1, "portno %s is: %s", val, errstr);
strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name));
strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
-
- errno = 0;
- newportidx = strtol(val, &endptr, 0);
- if (val[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
- errx(1, "invalid arg for portidx: %s", val);
-
- breq.ifbr_portno = newportidx;
if (ioctl(sock, SIOCSWSPORTNO, (caddr_t)&breq) == -1) {
if (errno == EEXIST)
return;