diff mbox series

[1/1] xfrm: xfrm_policy: fix a possible double xfrm_pols_put() in xfrm_bundle_lookup()

Message ID 20230201132258.37913-2-andrei.gherzan@canonical.com
State New
Headers show
Series [1/1] xfrm: xfrm_policy: fix a possible double xfrm_pols_put() in xfrm_bundle_lookup() | expand

Commit Message

Andrei Gherzan Feb. 1, 2023, 1:22 p.m. UTC
From: Hangyu Hua <hbh25y@gmail.com>

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: 80c802f3073e ("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>
CVE-2022-36879
(cherry picked from commit f85daf0e725358be78dfd208dea5fd665d8cb901)
Signed-off-by: Andrei Gherzan <andrei.gherzan at canonical.com>
---
 net/xfrm/xfrm_policy.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

Comments

Andrei Gherzan Feb. 1, 2023, 1:28 p.m. UTC | #1
On 23/02/01 01:22PM, Andrei Gherzan wrote:
> From: Hangyu Hua <hbh25y@gmail.com>
> 
> 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: 80c802f3073e ("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>
> CVE-2022-36879
> (cherry picked from commit f85daf0e725358be78dfd208dea5fd665d8cb901)
> Signed-off-by: Andrei Gherzan <andrei.gherzan at canonical.com>
> ---
>  net/xfrm/xfrm_policy.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index 19aa994f5d2c..96bad1e38f7d 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c
> @@ -2676,8 +2676,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;
>  
> @@ -2692,6 +2694,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)++;

The actual patch didn't end up with the right tags. I can send a v2 for
clarity. Otherwise consider the tags from the associated cover letter:

[SRU][Jammy/oem-5.17][Focal/oem-5.14][PATCH 1/1]
diff mbox series

Patch

diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 19aa994f5d2c..96bad1e38f7d 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2676,8 +2676,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;
 
@@ -2692,6 +2694,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)++;