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
This commit is contained in:
Mark Johnston 2021-11-29 13:50:30 -05:00
parent d5ea04ee7b
commit 1c732c8591
2 changed files with 9 additions and 9 deletions

View File

@ -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);

View File

@ -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;
}