--- /dev/null
+From 1137b5e2529a8f5ca8ee709288ecba3e68044df2 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Thu, 19 Oct 2017 20:51:10 +0800
+Subject: ipsec: Fix aborted xfrm policy dump crash
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+commit 1137b5e2529a8f5ca8ee709288ecba3e68044df2 upstream.
+
+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>
+Cc: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/xfrm/xfrm_user.c | 25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -1652,32 +1652,34 @@ static int dump_one_policy(struct xfrm_p
+
+ 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;
+@@ -2415,6 +2417,7 @@ static const struct nla_policy xfrma_spd
+
+ 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;
+@@ -2428,6 +2431,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 },
+@@ -2479,6 +2483,7 @@ static int xfrm_user_rcv_msg(struct sk_b
+
+ {
+ struct netlink_dump_control c = {
++ .start = link->start,
+ .dump = link->dump,
+ .done = link->done,
+ };
--- /dev/null
+From fc9e50f5a5a4e1fa9ba2756f745a13e693cf6a06 Mon Sep 17 00:00:00 2001
+From: Tom Herbert <tom@herbertland.com>
+Date: Tue, 15 Dec 2015 15:41:37 -0800
+Subject: netlink: add a start callback for starting a netlink dump
+
+From: Tom Herbert <tom@herbertland.com>
+
+commit fc9e50f5a5a4e1fa9ba2756f745a13e693cf6a06 upstream.
+
+The start callback allows the caller to set up a context for the
+dump callbacks. Presumably, the context can then be destroyed in
+the done callback.
+
+Signed-off-by: Tom Herbert <tom@herbertland.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Cc: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/netlink.h | 2 ++
+ include/net/genetlink.h | 2 ++
+ net/netlink/af_netlink.c | 4 ++++
+ net/netlink/genetlink.c | 16 ++++++++++++++++
+ 4 files changed, 24 insertions(+)
+
+--- a/include/linux/netlink.h
++++ b/include/linux/netlink.h
+@@ -131,6 +131,7 @@ netlink_skb_clone(struct sk_buff *skb, g
+ struct netlink_callback {
+ struct sk_buff *skb;
+ const struct nlmsghdr *nlh;
++ int (*start)(struct netlink_callback *);
+ int (*dump)(struct sk_buff * skb,
+ struct netlink_callback *cb);
+ int (*done)(struct netlink_callback *cb);
+@@ -153,6 +154,7 @@ struct nlmsghdr *
+ __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags);
+
+ struct netlink_dump_control {
++ int (*start)(struct netlink_callback *);
+ int (*dump)(struct sk_buff *skb, struct netlink_callback *);
+ int (*done)(struct netlink_callback *);
+ void *data;
+--- a/include/net/genetlink.h
++++ b/include/net/genetlink.h
+@@ -114,6 +114,7 @@ static inline void genl_info_net_set(str
+ * @flags: flags
+ * @policy: attribute validation policy
+ * @doit: standard command callback
++ * @start: start callback for dumps
+ * @dumpit: callback for dumpers
+ * @done: completion callback for dumps
+ * @ops_list: operations list
+@@ -122,6 +123,7 @@ struct genl_ops {
+ const struct nla_policy *policy;
+ int (*doit)(struct sk_buff *skb,
+ struct genl_info *info);
++ int (*start)(struct netlink_callback *cb);
+ int (*dumpit)(struct sk_buff *skb,
+ struct netlink_callback *cb);
+ int (*done)(struct netlink_callback *cb);
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -2203,6 +2203,7 @@ int __netlink_dump_start(struct sock *ss
+
+ cb = &nlk->cb;
+ memset(cb, 0, sizeof(*cb));
++ cb->start = control->start;
+ cb->dump = control->dump;
+ cb->done = control->done;
+ cb->nlh = nlh;
+@@ -2216,6 +2217,9 @@ int __netlink_dump_start(struct sock *ss
+
+ mutex_unlock(nlk->cb_mutex);
+
++ if (cb->start)
++ cb->start(cb);
++
+ ret = netlink_dump(sk);
+ sock_put(sk);
+
+--- a/net/netlink/genetlink.c
++++ b/net/netlink/genetlink.c
+@@ -513,6 +513,20 @@ void *genlmsg_put(struct sk_buff *skb, u
+ }
+ EXPORT_SYMBOL(genlmsg_put);
+
++static int genl_lock_start(struct netlink_callback *cb)
++{
++ /* our ops are always const - netlink API doesn't propagate that */
++ const struct genl_ops *ops = cb->data;
++ int rc = 0;
++
++ if (ops->start) {
++ genl_lock();
++ rc = ops->start(cb);
++ genl_unlock();
++ }
++ return rc;
++}
++
+ static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+ {
+ /* our ops are always const - netlink API doesn't propagate that */
+@@ -577,6 +591,7 @@ static int genl_family_rcv_msg(struct ge
+ .module = family->module,
+ /* we have const, but the netlink API doesn't */
+ .data = (void *)ops,
++ .start = genl_lock_start,
+ .dump = genl_lock_dumpit,
+ .done = genl_lock_done,
+ };
+@@ -588,6 +603,7 @@ static int genl_family_rcv_msg(struct ge
+ } else {
+ struct netlink_dump_control c = {
+ .module = family->module,
++ .start = ops->start,
+ .dump = ops->dumpit,
+ .done = ops->done,
+ };