net/xfrm/xfrm_policy.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-)
Fix the race by pruning the bin while still holding xfrm_policy_lock,
before dropping it. Use __xfrm_policy_inexact_prune_bin() directly since
the lock is already held. The wrapper xfrm_policy_inexact_prune_bin()
becomes unused and is removed.
Race:
CPU0 (XFRM_MSG_DELPOLICY) CPU1 (XFRM_MSG_NEWSPDINFO)
========================== ==========================
xfrm_policy_bysel_ctx():
spin_lock_bh(xfrm_policy_lock)
bin = xfrm_policy_inexact_lookup()
__xfrm_policy_unlink(pol)
spin_unlock_bh(xfrm_policy_lock)
xfrm_policy_kill(ret)
// wide window, lock not held
xfrm_hash_rebuild():
spin_lock_bh(xfrm_policy_lock)
__xfrm_policy_inexact_flush():
kfree_rcu(bin) // bin freed
spin_unlock_bh(xfrm_policy_lock)
xfrm_policy_inexact_prune_bin(bin)
// UAF: bin is freed
Fixes: 6be3b0db6db8 ("xfrm: policy: add inexact policy search tree infrastructure")
Signed-off-by: Sanghyun Park <sanghyun.park.cnu@gmail.com>
---
Changes in v2:
- Use the correct Fixes tag.
- Drop the extra ret condition and keep the original bin && delete
condition, only moving the prune before dropping xfrm_policy_lock.
- Trim reproduction and KASAN details from the changelog.
- Avoid whitespace damage.
net/xfrm/xfrm_policy.c | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index fca07f8e60..14fc87b2e7 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1156,15 +1156,6 @@ static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool
}
}
-static void xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b)
-{
- struct net *net = read_pnet(&b->k.net);
-
- spin_lock_bh(&net->xfrm.xfrm_policy_lock);
- __xfrm_policy_inexact_prune_bin(b, false);
- spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
-}
-
static void __xfrm_policy_inexact_flush(struct net *net)
{
struct xfrm_pol_inexact_bin *bin, *t;
@@ -1707,12 +1698,12 @@ xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id,
}
ret = pol;
}
+ if (bin && delete)
+ __xfrm_policy_inexact_prune_bin(bin, false);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (ret && delete)
xfrm_policy_kill(ret);
- if (bin && delete)
- xfrm_policy_inexact_prune_bin(bin);
return ret;
}
EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
On Tue, Jun 02, 2026 at 06:49:05PM +0900, Sanghyun Park wrote:
> Fix the race by pruning the bin while still holding xfrm_policy_lock,
> before dropping it. Use __xfrm_policy_inexact_prune_bin() directly since
> the lock is already held. The wrapper xfrm_policy_inexact_prune_bin()
> becomes unused and is removed.
>
> Race:
>
> CPU0 (XFRM_MSG_DELPOLICY) CPU1 (XFRM_MSG_NEWSPDINFO)
> ========================== ==========================
> xfrm_policy_bysel_ctx():
> spin_lock_bh(xfrm_policy_lock)
> bin = xfrm_policy_inexact_lookup()
> __xfrm_policy_unlink(pol)
> spin_unlock_bh(xfrm_policy_lock)
> xfrm_policy_kill(ret)
> // wide window, lock not held
> xfrm_hash_rebuild():
> spin_lock_bh(xfrm_policy_lock)
> __xfrm_policy_inexact_flush():
> kfree_rcu(bin) // bin freed
> spin_unlock_bh(xfrm_policy_lock)
> xfrm_policy_inexact_prune_bin(bin)
> // UAF: bin is freed
>
> Fixes: 6be3b0db6db8 ("xfrm: policy: add inexact policy search tree infrastructure")
> Signed-off-by: Sanghyun Park <sanghyun.park.cnu@gmail.com>
Applied, thanks a lot!
© 2016 - 2026 Red Hat, Inc.