[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAM_iQpUWUcSgXZfn851ABHLPE=dvQ-oQyV=yAXbauTLLiH=p3w@mail.gmail.com>
Date: Fri, 4 Jan 2019 20:49:48 -0800
From: Cong Wang <xiyou.wangcong@...il.com>
To: Florian Westphal <fw@...len.de>
Cc: Steffen Klassert <steffen.klassert@...unet.com>,
Linux Kernel Network Developers <netdev@...r.kernel.org>
Subject: Re: [PATCH ipsec 7/7] xfrm: policy: fix infinite loop when merging src-nodes
On Fri, Jan 4, 2019 at 5:19 AM Florian Westphal <fw@...len.de> wrote:
>
> With very small change to test script we can trigger softlockup due to
> bogus assignment of 'p' (policy to be examined) on restart.
>
> Previously the two to-be-merged nodes had same address/prefixlength pair,
> so no erase/reinsert was necessary, we only had to append the list from
> node a to b.
>
> If prefix lengths are different, the node has to be deleted and re-inserted
> into the tree, with the updated prefix length. This was broken; due to
> bogus update to 'p' this loops forever.
>
> Add a 'restart' label and use that instead.
>
> While at it, don't perform the unneeded reinserts of the policies that
> are already sorted into the 'new' node.
>
> A previous patch in this series made xfrm_policy_inexact_list_reinsert()
> use the relative position indicator to sort policies according to age in
> case priorities are identical.
>
> Fixes: 6ac098b2a9d30 ("xfrm: policy: add 2nd-level saddr trees for inexact policies")
> Signed-off-by: Florian Westphal <fw@...len.de>
> ---
> net/xfrm/xfrm_policy.c | 15 +++++++--------
> tools/testing/selftests/net/xfrm_policy.sh | 4 ++--
> 2 files changed, 9 insertions(+), 10 deletions(-)
>
> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index e691683223ee..8cfd75b62396 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c
> @@ -886,12 +886,13 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net,
> struct rb_root *new,
> u16 family)
> {
> - struct rb_node **p, *parent = NULL;
> struct xfrm_pol_inexact_node *node;
> + struct rb_node **p, *parent;
>
> /* we should not have another subtree here */
> WARN_ON_ONCE(!RB_EMPTY_ROOT(&n->root));
> -
> +restart:
> + parent = NULL;
> p = &new->rb_node;
> while (*p) {
> u8 prefixlen;
> @@ -911,12 +912,11 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net,
> } else {
> struct xfrm_policy *tmp;
>
> - hlist_for_each_entry(tmp, &node->hhead, bydst)
> - tmp->bydst_reinsert = true;
> - hlist_for_each_entry(tmp, &n->hhead, bydst)
> + hlist_for_each_entry(tmp, &n->hhead, bydst) {
hlist_for_each_entry_safe()?
> tmp->bydst_reinsert = true;
> + hlist_del_rcu(&tmp->bydst);
> + }
>
> - INIT_HLIST_HEAD(&node->hhead);
> xfrm_policy_inexact_list_reinsert(net, node, family);
>
> if (node->prefixlen == n->prefixlen) {
> @@ -928,8 +928,7 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net,
> kfree_rcu(n, rcu);
> n = node;
> n->prefixlen = prefixlen;
> - *p = new->rb_node;
> - parent = NULL;
> + goto restart;
> }
> }
>
> diff --git a/tools/testing/selftests/net/xfrm_policy.sh b/tools/testing/selftests/net/xfrm_policy.sh
> index 8ce54600d4d1..71d7fdc513c1 100755
> --- a/tools/testing/selftests/net/xfrm_policy.sh
> +++ b/tools/testing/selftests/net/xfrm_policy.sh
> @@ -78,8 +78,8 @@ do_overlap()
> # adds a new node in the 10.0.0.0/24 tree (dst node exists).
> ip -net $ns xfrm policy add src 10.2.0.0/24 dst 10.0.0.0/24 dir fwd priority 200 action block
>
> - # adds a 10.2.0.0/24 node, but for different dst.
> - ip -net $ns xfrm policy add src 10.2.0.0/24 dst 10.0.1.0/24 dir fwd priority 200 action block
> + # adds a 10.2.0.0/23 node, but for different dst.
> + ip -net $ns xfrm policy add src 10.2.0.0/23 dst 10.0.1.0/24 dir fwd priority 200 action block
>
> # dst now overlaps with the 10.0.1.0/24 ESP policy in fwd.
> # kernel must 'promote' existing one (10.0.0.0/24) to 10.0.0.0/23.
> --
> 2.19.2
>
Powered by blists - more mailing lists