diff options
author | Gao Feng <fgao@ikuai8.com> | 2017-03-29 07:11:27 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2017-04-08 17:52:15 -0400 |
commit | 8b5995d0633b04f9a0d321a7cc77e386440730cf (patch) | |
tree | d495422d1ce9a6b03ba312921d2b4b9ad90779d8 /net | |
parent | 97aae0df1de4d7dd80905fb067e28b032a132995 (diff) |
netfilter: helper: Add the rcu lock when call __nf_conntrack_helper_find
When invoke __nf_conntrack_helper_find, it needs the rcu lock to
protect the helper module which would not be unloaded.
Now there are two caller nf_conntrack_helper_try_module_get and
ctnetlink_create_expect which don't hold rcu lock. And the other
callers left like ctnetlink_change_helper, ctnetlink_create_conntrack,
and ctnetlink_glue_attach_expect, they already hold the rcu lock
or spin_lock_bh.
Remove the rcu lock in functions nf_ct_helper_expectfn_find_by_name
and nf_ct_helper_expectfn_find_by_symbol. Because they return one pointer
which needs rcu lock, so their caller should hold the rcu lock, not in
these two functions.
Signed-off-by: Gao Feng <fgao@ikuai8.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_conntrack_helper.c | 17 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 10 |
2 files changed, 20 insertions, 7 deletions
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 6dc44d9b4190..4eeb3418366a 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -158,16 +158,25 @@ nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum) | |||
158 | { | 158 | { |
159 | struct nf_conntrack_helper *h; | 159 | struct nf_conntrack_helper *h; |
160 | 160 | ||
161 | rcu_read_lock(); | ||
162 | |||
161 | h = __nf_conntrack_helper_find(name, l3num, protonum); | 163 | h = __nf_conntrack_helper_find(name, l3num, protonum); |
162 | #ifdef CONFIG_MODULES | 164 | #ifdef CONFIG_MODULES |
163 | if (h == NULL) { | 165 | if (h == NULL) { |
164 | if (request_module("nfct-helper-%s", name) == 0) | 166 | rcu_read_unlock(); |
167 | if (request_module("nfct-helper-%s", name) == 0) { | ||
168 | rcu_read_lock(); | ||
165 | h = __nf_conntrack_helper_find(name, l3num, protonum); | 169 | h = __nf_conntrack_helper_find(name, l3num, protonum); |
170 | } else { | ||
171 | return h; | ||
172 | } | ||
166 | } | 173 | } |
167 | #endif | 174 | #endif |
168 | if (h != NULL && !try_module_get(h->me)) | 175 | if (h != NULL && !try_module_get(h->me)) |
169 | h = NULL; | 176 | h = NULL; |
170 | 177 | ||
178 | rcu_read_unlock(); | ||
179 | |||
171 | return h; | 180 | return h; |
172 | } | 181 | } |
173 | EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get); | 182 | EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get); |
@@ -311,38 +320,36 @@ void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) | |||
311 | } | 320 | } |
312 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); | 321 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); |
313 | 322 | ||
323 | /* Caller should hold the rcu lock */ | ||
314 | struct nf_ct_helper_expectfn * | 324 | struct nf_ct_helper_expectfn * |
315 | nf_ct_helper_expectfn_find_by_name(const char *name) | 325 | nf_ct_helper_expectfn_find_by_name(const char *name) |
316 | { | 326 | { |
317 | struct nf_ct_helper_expectfn *cur; | 327 | struct nf_ct_helper_expectfn *cur; |
318 | bool found = false; | 328 | bool found = false; |
319 | 329 | ||
320 | rcu_read_lock(); | ||
321 | list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) { | 330 | list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) { |
322 | if (!strcmp(cur->name, name)) { | 331 | if (!strcmp(cur->name, name)) { |
323 | found = true; | 332 | found = true; |
324 | break; | 333 | break; |
325 | } | 334 | } |
326 | } | 335 | } |
327 | rcu_read_unlock(); | ||
328 | return found ? cur : NULL; | 336 | return found ? cur : NULL; |
329 | } | 337 | } |
330 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name); | 338 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name); |
331 | 339 | ||
340 | /* Caller should hold the rcu lock */ | ||
332 | struct nf_ct_helper_expectfn * | 341 | struct nf_ct_helper_expectfn * |
333 | nf_ct_helper_expectfn_find_by_symbol(const void *symbol) | 342 | nf_ct_helper_expectfn_find_by_symbol(const void *symbol) |
334 | { | 343 | { |
335 | struct nf_ct_helper_expectfn *cur; | 344 | struct nf_ct_helper_expectfn *cur; |
336 | bool found = false; | 345 | bool found = false; |
337 | 346 | ||
338 | rcu_read_lock(); | ||
339 | list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) { | 347 | list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) { |
340 | if (cur->expectfn == symbol) { | 348 | if (cur->expectfn == symbol) { |
341 | found = true; | 349 | found = true; |
342 | break; | 350 | break; |
343 | } | 351 | } |
344 | } | 352 | } |
345 | rcu_read_unlock(); | ||
346 | return found ? cur : NULL; | 353 | return found ? cur : NULL; |
347 | } | 354 | } |
348 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol); | 355 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol); |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 59ee27deb9a0..06d28ac663df 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -3133,23 +3133,27 @@ ctnetlink_create_expect(struct net *net, | |||
3133 | return -ENOENT; | 3133 | return -ENOENT; |
3134 | ct = nf_ct_tuplehash_to_ctrack(h); | 3134 | ct = nf_ct_tuplehash_to_ctrack(h); |
3135 | 3135 | ||
3136 | rcu_read_lock(); | ||
3136 | if (cda[CTA_EXPECT_HELP_NAME]) { | 3137 | if (cda[CTA_EXPECT_HELP_NAME]) { |
3137 | const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); | 3138 | const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); |
3138 | 3139 | ||
3139 | helper = __nf_conntrack_helper_find(helpname, u3, | 3140 | helper = __nf_conntrack_helper_find(helpname, u3, |
3140 | nf_ct_protonum(ct)); | 3141 | nf_ct_protonum(ct)); |
3141 | if (helper == NULL) { | 3142 | if (helper == NULL) { |
3143 | rcu_read_unlock(); | ||
3142 | #ifdef CONFIG_MODULES | 3144 | #ifdef CONFIG_MODULES |
3143 | if (request_module("nfct-helper-%s", helpname) < 0) { | 3145 | if (request_module("nfct-helper-%s", helpname) < 0) { |
3144 | err = -EOPNOTSUPP; | 3146 | err = -EOPNOTSUPP; |
3145 | goto err_ct; | 3147 | goto err_ct; |
3146 | } | 3148 | } |
3149 | rcu_read_lock(); | ||
3147 | helper = __nf_conntrack_helper_find(helpname, u3, | 3150 | helper = __nf_conntrack_helper_find(helpname, u3, |
3148 | nf_ct_protonum(ct)); | 3151 | nf_ct_protonum(ct)); |
3149 | if (helper) { | 3152 | if (helper) { |
3150 | err = -EAGAIN; | 3153 | err = -EAGAIN; |
3151 | goto err_ct; | 3154 | goto err_rcu; |
3152 | } | 3155 | } |
3156 | rcu_read_unlock(); | ||
3153 | #endif | 3157 | #endif |
3154 | err = -EOPNOTSUPP; | 3158 | err = -EOPNOTSUPP; |
3155 | goto err_ct; | 3159 | goto err_ct; |
@@ -3159,11 +3163,13 @@ ctnetlink_create_expect(struct net *net, | |||
3159 | exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask); | 3163 | exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask); |
3160 | if (IS_ERR(exp)) { | 3164 | if (IS_ERR(exp)) { |
3161 | err = PTR_ERR(exp); | 3165 | err = PTR_ERR(exp); |
3162 | goto err_ct; | 3166 | goto err_rcu; |
3163 | } | 3167 | } |
3164 | 3168 | ||
3165 | err = nf_ct_expect_related_report(exp, portid, report); | 3169 | err = nf_ct_expect_related_report(exp, portid, report); |
3166 | nf_ct_expect_put(exp); | 3170 | nf_ct_expect_put(exp); |
3171 | err_rcu: | ||
3172 | rcu_read_unlock(); | ||
3167 | err_ct: | 3173 | err_ct: |
3168 | nf_ct_put(ct); | 3174 | nf_ct_put(ct); |
3169 | return err; | 3175 | return err; |