diff options
Diffstat (limited to 'net/sched/cls_u32.c')
| -rw-r--r-- | net/sched/cls_u32.c | 10 | 
1 files changed, 8 insertions, 2 deletions
| diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index d5d2a6dc3921..f218ccf1e2d9 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -914,6 +914,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,  	struct nlattr *opt = tca[TCA_OPTIONS];  	struct nlattr *tb[TCA_U32_MAX + 1];  	u32 htid, flags = 0; +	size_t sel_size;  	int err;  #ifdef CONFIG_CLS_U32_PERF  	size_t size; @@ -1076,8 +1077,13 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,  	}  	s = nla_data(tb[TCA_U32_SEL]); +	sel_size = struct_size(s, keys, s->nkeys); +	if (nla_len(tb[TCA_U32_SEL]) < sel_size) { +		err = -EINVAL; +		goto erridr; +	} -	n = kzalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), GFP_KERNEL); +	n = kzalloc(offsetof(typeof(*n), sel) + sel_size, GFP_KERNEL);  	if (n == NULL) {  		err = -ENOBUFS;  		goto erridr; @@ -1092,7 +1098,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,  	}  #endif -	memcpy(&n->sel, s, sizeof(*s) + s->nkeys*sizeof(struct tc_u32_key)); +	memcpy(&n->sel, s, sel_size);  	RCU_INIT_POINTER(n->ht_up, ht);  	n->handle = handle;  	n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; |