diff options
author | Mark Johnston <markj@FreeBSD.org> | 2021-11-29 18:50:30 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2021-11-29 18:57:24 +0000 |
commit | 1c732c85911eb9e39071cbdb50dfb1f0d76de40f (patch) | |
tree | f5329e6da01db09dd300e6c58c7609667ab11421 | |
parent | d5ea04ee7ba6c7cd8e0918a080caf5f2c8fb3955 (diff) | |
download | src-1c732c85911eb9e39071cbdb50dfb1f0d76de40f.tar.gz src-1c732c85911eb9e39071cbdb50dfb1f0d76de40f.zip |
dummynet: Fix socket option length validation for IP_DUMMYNET3
The socket option handler tries to ensure that the option length is no
larger than some reasonable maximum, and no smaller than sizeof(struct
dn_id). But the loaded option length is stored in an int, which is
converted to an unsigned integer for the comparison with a size_t, so
negative values are not caught and instead get passed to malloc().
Change the code to use a size_t for the buffer size.
Reviewed by: kp
MFC after: 1 week
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D33133
-rw-r--r-- | sys/netpfil/ipfw/ip_dn_private.h | 2 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_dummynet.c | 16 |
2 files changed, 9 insertions, 9 deletions
diff --git a/sys/netpfil/ipfw/ip_dn_private.h b/sys/netpfil/ipfw/ip_dn_private.h index cc084f2fcc0d..25015fe02c2d 100644 --- a/sys/netpfil/ipfw/ip_dn_private.h +++ b/sys/netpfil/ipfw/ip_dn_private.h @@ -437,7 +437,7 @@ int dn_compat_copy_queue(struct copy_args *a, void *_o); int dn_compat_copy_pipe(struct copy_args *a, void *_o); int copy_data_helper_compat(void *_o, void *_arg); int dn_compat_calc_size(void); -int do_config(void *p, int l); +int do_config(void *p, size_t l); /* function to drain idle object */ void dn_drain_scheduler(void); diff --git a/sys/netpfil/ipfw/ip_dummynet.c b/sys/netpfil/ipfw/ip_dummynet.c index 919445ff71d0..0cd606bd56b2 100644 --- a/sys/netpfil/ipfw/ip_dummynet.c +++ b/sys/netpfil/ipfw/ip_dummynet.c @@ -1991,7 +1991,7 @@ dummynet_flush(void) * processed on a config_sched. */ int -do_config(void *p, int l) +do_config(void *p, size_t l) { struct dn_id o; union { @@ -2015,7 +2015,7 @@ do_config(void *p, int l) while (l >= sizeof(o)) { memcpy(&o, (char *)p + off, sizeof(o)); if (o.len < sizeof(o) || l < o.len) { - D("bad len o.len %d len %d", o.len, l); + D("bad len o.len %d len %zu", o.len, l); err = EINVAL; break; } @@ -2487,7 +2487,8 @@ ip_dn_ctl(struct sockopt *sopt) { struct epoch_tracker et; void *p = NULL; - int error, l; + size_t l; + int error; error = priv_check(sopt->sopt_td, PRIV_NETINET_DUMMYNET); if (error) @@ -2516,14 +2517,14 @@ ip_dn_ctl(struct sockopt *sopt) error = ip_dummynet_compat(sopt); break; - case IP_DUMMYNET3 : + case IP_DUMMYNET3: if (sopt->sopt_dir == SOPT_GET) { error = dummynet_get(sopt, NULL); break; } l = sopt->sopt_valsize; if (l < sizeof(struct dn_id) || l > 12000) { - D("argument len %d invalid", l); + D("argument len %zu invalid", l); break; } p = malloc(l, M_TEMP, M_NOWAIT); @@ -2532,9 +2533,8 @@ ip_dn_ctl(struct sockopt *sopt) break; } error = sooptcopyin(sopt, p, l, l); - if (error) - break ; - error = do_config(p, l); + if (error == 0) + error = do_config(p, l); break; } |