forked from Minki/linux
netfilter: nfnetlink_acct: fix race between nfacct del and xt_nfacct destroy
Suppose that we input the following commands at first: # nfacct add test # iptables -A INPUT -m nfacct --nfacct-name test And now "test" acct's refcnt is 2, but later when we try to delete the "test" nfacct and the related iptables rule at the same time, race maybe happen: CPU0 CPU1 nfnl_acct_try_del nfnl_acct_put atomic_dec_and_test //ref=1,testfail - - atomic_dec_and_test //ref=0,testok - kfree_rcu atomic_inc //ref=1 - So after the rcu grace period, nf_acct will be freed but it is still linked in the nfnl_acct_list, and we can access it later, then oops will happen. Convert atomic_dec_and_test and atomic_inc combinaiton to one atomic operation atomic_cmpxchg here to fix this problem. Signed-off-by: Liping Zhang <liping.zhang@spreadtrum.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
dcbe35909c
commit
12be15dd5a
@ -326,14 +326,14 @@ static int nfnl_acct_try_del(struct nf_acct *cur)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* we want to avoid races with nfnl_acct_find_get. */
|
||||
if (atomic_dec_and_test(&cur->refcnt)) {
|
||||
/* We want to avoid races with nfnl_acct_put. So only when the current
|
||||
* refcnt is 1, we decrease it to 0.
|
||||
*/
|
||||
if (atomic_cmpxchg(&cur->refcnt, 1, 0) == 1) {
|
||||
/* We are protected by nfnl mutex. */
|
||||
list_del_rcu(&cur->head);
|
||||
kfree_rcu(cur, rcu_head);
|
||||
} else {
|
||||
/* still in use, restore reference counter. */
|
||||
atomic_inc(&cur->refcnt);
|
||||
ret = -EBUSY;
|
||||
}
|
||||
return ret;
|
||||
|
Loading…
Reference in New Issue
Block a user