summaryrefslogtreecommitdiff
path: root/net/sched
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2018-08-25 22:58:01 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-09-15 09:45:24 +0200
commit7f1e6ec4ff1234bb2bcf1dd7763cd16e66d6a3fe (patch)
tree68cb6b5317640e67d123cc7d73177ecda0968cb0 /net/sched
parentcb765f5c3c5b1e982112e4ccccb80bd90f7cb7bf (diff)
net: sched: Fix memory exposure from short TCA_U32_SEL
[ Upstream commit 98c8f125fd8a6240ea343c1aa50a1be9047791b8 ] Via u32_change(), TCA_U32_SEL has an unspecified type in the netlink policy, so max length isn't enforced, only minimum. This means nkeys (from userspace) was being trusted without checking the actual size of nla_len(), which could lead to a memory over-read, and ultimately an exposure via a call to u32_dump(). Reachability is CAP_NET_ADMIN within a namespace. Reported-by: Al Viro <viro@zeniv.linux.org.uk> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: Cong Wang <xiyou.wangcong@gmail.com> Cc: Jiri Pirko <jiri@resnulli.us> Cc: "David S. Miller" <davem@davemloft.net> Cc: netdev@vger.kernel.org Signed-off-by: Kees Cook <keescook@chromium.org> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/sched')
-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 ba37d8f57e68..0c9bc29dcf97 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -903,6 +903,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;
@@ -1024,8 +1025,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;
@@ -1038,7 +1042,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;