Message ID | 1512482627-29116-2-git-send-email-marcelo.cerri@canonical.com |
---|---|
State | New |
Headers | show |
Series | Fixes for CVE-2017-16939 and CVE-2017-1000405 | expand |
On 12/05/17 15:03, Marcelo Henrique Cerri wrote: > From: Herbert Xu <herbert@gondor.apana.org.au> > > An independent security researcher, Mohamed Ghannam, has reported > this vulnerability to Beyond Security's SecuriTeam Secure Disclosure > program. > > The xfrm_dump_policy_done function expects xfrm_dump_policy to > have been called at least once or it will crash. This can be > triggered if a dump fails because the target socket's receive > buffer is full. > > This patch fixes it by using the cb->start mechanism to ensure that > the initialisation is always done regardless of the buffer situation. > > Fixes: 12a169e7d8f4 ("ipsec: Put dumpers on the dump list") > Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> > Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> > > CVE-2017-16939 > (cherry picked from commit 1137b5e2529a8f5ca8ee709288ecba3e68044df2) > Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com> Clean cherry-pick, fix tested on other series as well and verified to fix the issue. Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> > --- > net/xfrm/xfrm_user.c | 25 +++++++++++++++---------- > 1 file changed, 15 insertions(+), 10 deletions(-) > > diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c > index 66698552fbd6..4638446c1c41 100644 > --- a/net/xfrm/xfrm_user.c > +++ b/net/xfrm/xfrm_user.c > @@ -1656,32 +1656,34 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr > > static int xfrm_dump_policy_done(struct netlink_callback *cb) > { > - struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; > + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; > struct net *net = sock_net(cb->skb->sk); > > xfrm_policy_walk_done(walk, net); > return 0; > } > > +static int xfrm_dump_policy_start(struct netlink_callback *cb) > +{ > + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; > + > + BUILD_BUG_ON(sizeof(*walk) > sizeof(cb->args)); > + > + xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); > + return 0; > +} > + > static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) > { > struct net *net = sock_net(skb->sk); > - struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; > + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; > struct xfrm_dump_info info; > > - BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) > > - sizeof(cb->args) - sizeof(cb->args[0])); > - > info.in_skb = cb->skb; > info.out_skb = skb; > info.nlmsg_seq = cb->nlh->nlmsg_seq; > info.nlmsg_flags = NLM_F_MULTI; > > - if (!cb->args[0]) { > - cb->args[0] = 1; > - xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); > - } > - > (void) xfrm_policy_walk(net, walk, dump_one_policy, &info); > > return skb->len; > @@ -2416,6 +2418,7 @@ static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = { > > static const struct xfrm_link { > int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); > + int (*start)(struct netlink_callback *); > int (*dump)(struct sk_buff *, struct netlink_callback *); > int (*done)(struct netlink_callback *); > const struct nla_policy *nla_pol; > @@ -2429,6 +2432,7 @@ static const struct xfrm_link { > [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, > [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, > [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, > + .start = xfrm_dump_policy_start, > .dump = xfrm_dump_policy, > .done = xfrm_dump_policy_done }, > [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, > @@ -2480,6 +2484,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) > > { > struct netlink_dump_control c = { > + .start = link->start, > .dump = link->dump, > .done = link->done, > }; >
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 66698552fbd6..4638446c1c41 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1656,32 +1656,34 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr static int xfrm_dump_policy_done(struct netlink_callback *cb) { - struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; struct net *net = sock_net(cb->skb->sk); xfrm_policy_walk_done(walk, net); return 0; } +static int xfrm_dump_policy_start(struct netlink_callback *cb) +{ + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; + + BUILD_BUG_ON(sizeof(*walk) > sizeof(cb->args)); + + xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); + return 0; +} + static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); - struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args; struct xfrm_dump_info info; - BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) > - sizeof(cb->args) - sizeof(cb->args[0])); - info.in_skb = cb->skb; info.out_skb = skb; info.nlmsg_seq = cb->nlh->nlmsg_seq; info.nlmsg_flags = NLM_F_MULTI; - if (!cb->args[0]) { - cb->args[0] = 1; - xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); - } - (void) xfrm_policy_walk(net, walk, dump_one_policy, &info); return skb->len; @@ -2416,6 +2418,7 @@ static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = { static const struct xfrm_link { int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); + int (*start)(struct netlink_callback *); int (*dump)(struct sk_buff *, struct netlink_callback *); int (*done)(struct netlink_callback *); const struct nla_policy *nla_pol; @@ -2429,6 +2432,7 @@ static const struct xfrm_link { [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, + .start = xfrm_dump_policy_start, .dump = xfrm_dump_policy, .done = xfrm_dump_policy_done }, [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, @@ -2480,6 +2484,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { struct netlink_dump_control c = { + .start = link->start, .dump = link->dump, .done = link->done, };