From b77d66032f47838c5473d8eee3eea3202a080134 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 29 Nov 2021 13:50:30 -0500 Subject: [PATCH] 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 Sponsored by: The FreeBSD Foundation (cherry picked from commit 1c732c85911eb9e39071cbdb50dfb1f0d76de40f) --- sys/netpfil/ipfw/ip_dn_private.h | 2 +- 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 cc084f2fcc0..25015fe02c2 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 cee478a0327..93b361755d9 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; } -- 2.45.0