Commit 9464d0b6 authored by Xin Long's avatar Xin Long Committed by Pablo Neira Ayuso

netfilter: conntrack: fix using __this_cpu_add in preemptible

Currently in nf_conntrack_hash_check_insert(), when it fails in
nf_ct_ext_valid_pre/post(), NF_CT_STAT_INC() will be called in the
preemptible context, a call trace can be triggered:

   BUG: using __this_cpu_add() in preemptible [00000000] code: conntrack/1636
   caller is nf_conntrack_hash_check_insert+0x45/0x430 [nf_conntrack]
   Call Trace:
    <TASK>
    dump_stack_lvl+0x33/0x46
    check_preemption_disabled+0xc3/0xf0
    nf_conntrack_hash_check_insert+0x45/0x430 [nf_conntrack]
    ctnetlink_create_conntrack+0x3cd/0x4e0 [nf_conntrack_netlink]
    ctnetlink_new_conntrack+0x1c0/0x450 [nf_conntrack_netlink]
    nfnetlink_rcv_msg+0x277/0x2f0 [nfnetlink]
    netlink_rcv_skb+0x50/0x100
    nfnetlink_rcv+0x65/0x144 [nfnetlink]
    netlink_unicast+0x1ae/0x290
    netlink_sendmsg+0x257/0x4f0
    sock_sendmsg+0x5f/0x70

This patch is to fix it by changing to use NF_CT_STAT_INC_ATOMIC() for
nf_ct_ext_valid_pre/post() check in nf_conntrack_hash_check_insert(),
as well as nf_ct_ext_valid_post() in __nf_conntrack_confirm().

Note that nf_ct_ext_valid_pre() check in __nf_conntrack_confirm() is
safe to use NF_CT_STAT_INC(), as it's under local_bh_disable().

Fixes: c56716c6 ("netfilter: extensions: introduce extension genid count")
Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent a8104715
...@@ -891,7 +891,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) ...@@ -891,7 +891,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
zone = nf_ct_zone(ct); zone = nf_ct_zone(ct);
if (!nf_ct_ext_valid_pre(ct->ext)) { if (!nf_ct_ext_valid_pre(ct->ext)) {
NF_CT_STAT_INC(net, insert_failed); NF_CT_STAT_INC_ATOMIC(net, insert_failed);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -938,7 +938,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) ...@@ -938,7 +938,7 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
if (!nf_ct_ext_valid_post(ct->ext)) { if (!nf_ct_ext_valid_post(ct->ext)) {
nf_ct_kill(ct); nf_ct_kill(ct);
NF_CT_STAT_INC(net, drop); NF_CT_STAT_INC_ATOMIC(net, drop);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -1275,7 +1275,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) ...@@ -1275,7 +1275,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
*/ */
if (!nf_ct_ext_valid_post(ct->ext)) { if (!nf_ct_ext_valid_post(ct->ext)) {
nf_ct_kill(ct); nf_ct_kill(ct);
NF_CT_STAT_INC(net, drop); NF_CT_STAT_INC_ATOMIC(net, drop);
return NF_DROP; return NF_DROP;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment