| From 55cd0dd0ad6dc1939429a68f3e54c0fe637f4adb Mon Sep 17 00:00:00 2001 |
| From: YueHaibing <yuehaibing@huawei.com> |
| Date: Mon, 23 Mar 2020 15:32:39 +0800 |
| Subject: [PATCH] xfrm: policy: Fix doulbe free in xfrm_policy_timer |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| commit 4c59406ed00379c8663f8663d82b2537467ce9d7 upstream. |
| |
| After xfrm_add_policy add a policy, its ref is 2, then |
| |
| xfrm_policy_timer |
| read_lock |
| xp->walk.dead is 0 |
| .... |
| mod_timer() |
| xfrm_policy_kill |
| policy->walk.dead = 1 |
| .... |
| del_timer(&policy->timer) |
| xfrm_pol_put //ref is 1 |
| xfrm_pol_put //ref is 0 |
| xfrm_policy_destroy |
| call_rcu |
| xfrm_pol_hold //ref is 1 |
| read_unlock |
| xfrm_pol_put //ref is 0 |
| xfrm_policy_destroy |
| call_rcu |
| |
| xfrm_policy_destroy is called twice, which may leads to |
| double free. |
| |
| Call Trace: |
| RIP: 0010:refcount_warn_saturate+0x161/0x210 |
| ... |
| xfrm_policy_timer+0x522/0x600 |
| call_timer_fn+0x1b3/0x5e0 |
| ? __xfrm_decode_session+0x2990/0x2990 |
| ? msleep+0xb0/0xb0 |
| ? _raw_spin_unlock_irq+0x24/0x40 |
| ? __xfrm_decode_session+0x2990/0x2990 |
| ? __xfrm_decode_session+0x2990/0x2990 |
| run_timer_softirq+0x5c5/0x10e0 |
| |
| Fix this by use write_lock_bh in xfrm_policy_kill. |
| |
| Fixes: ea2dea9dacc2 ("xfrm: remove policy lock when accessing policy->walk.dead") |
| Signed-off-by: YueHaibing <yuehaibing@huawei.com> |
| Acked-by: Timo Terรคs <timo.teras@iki.fi> |
| Acked-by: Herbert Xu <herbert@gondor.apana.org.au> |
| Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c |
| index 7c2fa80b20bd..96fc064ae24f 100644 |
| --- a/net/xfrm/xfrm_policy.c |
| +++ b/net/xfrm/xfrm_policy.c |
| @@ -431,7 +431,9 @@ EXPORT_SYMBOL(xfrm_policy_destroy); |
| |
| static void xfrm_policy_kill(struct xfrm_policy *policy) |
| { |
| + write_lock_bh(&policy->lock); |
| policy->walk.dead = 1; |
| + write_unlock_bh(&policy->lock); |
| |
| atomic_inc(&policy->genid); |
| |
| -- |
| 2.7.4 |
| |