]> git.baikalelectronics.ru Git - kernel.git/commitdiff
xfrm: xfrm_policy: fix a possible double xfrm_pols_put() in xfrm_bundle_lookup()
authorHangyu Hua <hbh25y@gmail.com>
Wed, 1 Jun 2022 06:46:25 +0000 (14:46 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 29 Jul 2022 15:14:10 +0000 (17:14 +0200)
[ Upstream commit d5b498b46edd95255ec5cf3e2da09142539821cc ]

xfrm_policy_lookup() will call xfrm_pol_hold_rcu() to get a refcount of
pols[0]. This refcount can be dropped in xfrm_expand_policies() when
xfrm_expand_policies() return error. pols[0]'s refcount is balanced in
here. But xfrm_bundle_lookup() will also call xfrm_pols_put() with
num_pols == 1 to drop this refcount when xfrm_expand_policies() return
error.

This patch also fix an illegal address access. pols[0] will save a error
point when xfrm_policy_lookup fails. This lead to xfrm_pols_put to resolve
an illegal address in xfrm_bundle_lookup's error path.

Fix these by setting num_pols = 0 in xfrm_expand_policies()'s error path.

Fixes: bceb06bc1841 ("xfrm: cache bundles instead of policies for outgoing flows")
Signed-off-by: Hangyu Hua <hbh25y@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/xfrm/xfrm_policy.c

index 3ecb77c58c44e53f3028641391f1797da4d5fd0f..28a8cdef8e51f8edd1dc8891c142e06d5cadf79e 100644 (file)
@@ -2679,8 +2679,10 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family,
                *num_xfrms = 0;
                return 0;
        }
-       if (IS_ERR(pols[0]))
+       if (IS_ERR(pols[0])) {
+               *num_pols = 0;
                return PTR_ERR(pols[0]);
+       }
 
        *num_xfrms = pols[0]->xfrm_nr;
 
@@ -2695,6 +2697,7 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family,
                if (pols[1]) {
                        if (IS_ERR(pols[1])) {
                                xfrm_pols_put(pols, *num_pols);
+                               *num_pols = 0;
                                return PTR_ERR(pols[1]);
                        }
                        (*num_pols)++;