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:
parent
d5ea04ee7b
commit
1c732c8591
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user