summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/sched/cls_u32.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index da574a16e7b3..e377dd5b06a6 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -851,6 +851,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;
@@ -967,8 +968,11 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
return -EINVAL;
s = nla_data(tb[TCA_U32_SEL]);
+ sel_size = sizeof(*s) + sizeof(*s->keys) * s->nkeys;
+ if (nla_len(tb[TCA_U32_SEL]) < sel_size)
+ return -EINVAL;
- 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)
return -ENOBUFS;
@@ -981,7 +985,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;