Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_conntrack: use rcu accessors where needed

Sparse complains about direct access to the 'helper' and timeout members.
Both have __rcu annotation, so use the accessors.

xt_CT is fine, accesses occur before the structure is visible to other
cpus. Switch to rcu accessors there as well to reduce noise.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
e14575fa 6976890e

+57 -16
+5 -1
net/netfilter/nf_conntrack_broadcast.c
··· 20 20 enum ip_conntrack_info ctinfo, 21 21 unsigned int timeout) 22 22 { 23 + const struct nf_conntrack_helper *helper; 23 24 struct nf_conntrack_expect *exp; 24 25 struct iphdr *iph = ip_hdr(skb); 25 26 struct rtable *rt = skb_rtable(skb); ··· 59 58 goto out; 60 59 61 60 exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; 62 - exp->tuple.src.u.udp.port = help->helper->tuple.src.u.udp.port; 61 + 62 + helper = rcu_dereference(help->helper); 63 + if (helper) 64 + exp->tuple.src.u.udp.port = helper->tuple.src.u.udp.port; 63 65 64 66 exp->mask.src.u3.ip = mask; 65 67 exp->mask.src.u.udp.port = htons(0xFFFF);
+1 -1
net/netfilter/nf_conntrack_helper.c
··· 249 249 if (tmpl != NULL) { 250 250 help = nfct_help(tmpl); 251 251 if (help != NULL) { 252 - helper = help->helper; 252 + helper = rcu_dereference(help->helper); 253 253 set_bit(IPS_HELPER_BIT, &ct->status); 254 254 } 255 255 }
+7 -2
net/netfilter/nf_conntrack_netlink.c
··· 2004 2004 } 2005 2005 2006 2006 if (help) { 2007 - if (help->helper == helper) { 2007 + if (rcu_access_pointer(help->helper) == helper) { 2008 2008 /* update private helper data if allowed. */ 2009 2009 if (helper->from_nlattr) 2010 2010 helper->from_nlattr(helpinfo, ct); ··· 3412 3412 3413 3413 static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data) 3414 3414 { 3415 + struct nf_conntrack_helper *helper; 3415 3416 const struct nf_conn_help *m_help; 3416 3417 const char *name = data; 3417 3418 3418 3419 m_help = nfct_help(exp->master); 3419 3420 3420 - return strcmp(m_help->helper->name, name) == 0; 3421 + helper = rcu_dereference(m_help->helper); 3422 + if (!helper) 3423 + return false; 3424 + 3425 + return strcmp(helper->name, name) == 0; 3421 3426 } 3422 3427 3423 3428 static bool expect_iter_all(struct nf_conntrack_expect *exp, void *data)
+6 -1
net/netfilter/nf_conntrack_sip.c
··· 1229 1229 struct nf_conntrack_expect *exp; 1230 1230 union nf_inet_addr *saddr, daddr; 1231 1231 const struct nf_nat_sip_hooks *hooks; 1232 + struct nf_conntrack_helper *helper; 1232 1233 __be16 port; 1233 1234 u8 proto; 1234 1235 unsigned int expires = 0; ··· 1290 1289 if (sip_direct_signalling) 1291 1290 saddr = &ct->tuplehash[!dir].tuple.src.u3; 1292 1291 1292 + helper = rcu_dereference(nfct_help(ct)->helper); 1293 + if (!helper) 1294 + return NF_DROP; 1295 + 1293 1296 nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), 1294 1297 saddr, &daddr, proto, NULL, &port); 1295 1298 exp->timeout.expires = sip_timeout * HZ; 1296 - exp->helper = nfct_help(ct)->helper; 1299 + exp->helper = helper; 1297 1300 exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; 1298 1301 1299 1302 hooks = rcu_dereference(nf_nat_sip_hooks);
+13 -3
net/netfilter/nf_conntrack_timeout.c
··· 29 29 { 30 30 struct nf_conn_timeout *timeout_ext = nf_ct_timeout_find(ct); 31 31 32 - if (timeout_ext && (!timeout || timeout_ext->timeout == timeout)) 33 - RCU_INIT_POINTER(timeout_ext->timeout, NULL); 32 + if (timeout_ext) { 33 + const struct nf_ct_timeout *t; 34 + 35 + t = rcu_access_pointer(timeout_ext->timeout); 36 + 37 + if (!timeout || t == timeout) 38 + RCU_INIT_POINTER(timeout_ext->timeout, NULL); 39 + } 34 40 35 41 /* We are not intended to delete this conntrack. */ 36 42 return 0; ··· 133 127 if (h) { 134 128 timeout_ext = nf_ct_timeout_find(ct); 135 129 if (timeout_ext) { 136 - h->timeout_put(timeout_ext->timeout); 130 + struct nf_ct_timeout *t; 131 + 132 + t = rcu_dereference(timeout_ext->timeout); 133 + if (t) 134 + h->timeout_put(t); 137 135 RCU_INIT_POINTER(timeout_ext->timeout, NULL); 138 136 } 139 137 }
+18 -5
net/netfilter/xt_CT.c
··· 96 96 return -ENOMEM; 97 97 } 98 98 99 - help->helper = helper; 99 + rcu_assign_pointer(help->helper, helper); 100 100 return 0; 101 101 } 102 102 ··· 134 134 default: 135 135 return NF_CT_DEFAULT_ZONE_DIR; 136 136 } 137 + } 138 + 139 + static void xt_ct_put_helper(struct nf_conn_help *help) 140 + { 141 + struct nf_conntrack_helper *helper; 142 + 143 + if (!help) 144 + return; 145 + 146 + /* not yet exposed to other cpus, or ruleset 147 + * already detached (post-replacement). 148 + */ 149 + helper = rcu_dereference_raw(help->helper); 150 + if (helper) 151 + nf_conntrack_helper_put(helper); 137 152 } 138 153 139 154 static int xt_ct_tg_check(const struct xt_tgchk_param *par, ··· 222 207 223 208 err4: 224 209 help = nfct_help(ct); 225 - if (help) 226 - nf_conntrack_helper_put(help->helper); 210 + xt_ct_put_helper(help); 227 211 err3: 228 212 nf_ct_tmpl_free(ct); 229 213 err2: ··· 284 270 285 271 if (ct) { 286 272 help = nfct_help(ct); 287 - if (help) 288 - nf_conntrack_helper_put(help->helper); 273 + xt_ct_put_helper(help); 289 274 290 275 nf_ct_netns_put(par->net, par->family); 291 276