aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2021-11-29 18:50:30 +0000
committerMark Johnston <markj@FreeBSD.org>2021-11-29 18:57:24 +0000
commit1c732c85911eb9e39071cbdb50dfb1f0d76de40f (patch)
treef5329e6da01db09dd300e6c58c7609667ab11421
parentd5ea04ee7ba6c7cd8e0918a080caf5f2c8fb3955 (diff)
downloadsrc-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.h2
-rw-r--r--sys/netpfil/ipfw/ip_dummynet.c16
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;
}