diff options
-rw-r--r-- | net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 4 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_helper.c | 17 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 41 | ||||
-rw-r--r-- | net/netfilter/nf_nat_redirect.c | 2 | ||||
-rw-r--r-- | net/netfilter/nft_hash.c | 10 | ||||
-rw-r--r-- | net/netfilter/xt_TCPMSS.c | 6 | ||||
-rw-r--r-- | net/netfilter/xt_TPROXY.c | 5 |
8 files changed, 62 insertions, 25 deletions
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 52f26459efc3..9b8841316e7b 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c | |||
@@ -461,7 +461,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par) | |||
461 | 461 | ||
462 | clusterip_config_put(cipinfo->config); | 462 | clusterip_config_put(cipinfo->config); |
463 | 463 | ||
464 | nf_ct_netns_get(par->net, par->family); | 464 | nf_ct_netns_put(par->net, par->family); |
465 | } | 465 | } |
466 | 466 | ||
467 | #ifdef CONFIG_COMPAT | 467 | #ifdef CONFIG_COMPAT |
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 4b2e1fb28bb4..d80073037856 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -57,7 +57,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp, | |||
57 | hlist_del_rcu(&exp->hnode); | 57 | hlist_del_rcu(&exp->hnode); |
58 | net->ct.expect_count--; | 58 | net->ct.expect_count--; |
59 | 59 | ||
60 | hlist_del(&exp->lnode); | 60 | hlist_del_rcu(&exp->lnode); |
61 | master_help->expecting[exp->class]--; | 61 | master_help->expecting[exp->class]--; |
62 | 62 | ||
63 | nf_ct_expect_event_report(IPEXP_DESTROY, exp, portid, report); | 63 | nf_ct_expect_event_report(IPEXP_DESTROY, exp, portid, report); |
@@ -363,7 +363,7 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) | |||
363 | /* two references : one for hash insert, one for the timer */ | 363 | /* two references : one for hash insert, one for the timer */ |
364 | atomic_add(2, &exp->use); | 364 | atomic_add(2, &exp->use); |
365 | 365 | ||
366 | hlist_add_head(&exp->lnode, &master_help->expectations); | 366 | hlist_add_head_rcu(&exp->lnode, &master_help->expectations); |
367 | master_help->expecting[exp->class]++; | 367 | master_help->expecting[exp->class]++; |
368 | 368 | ||
369 | hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]); | 369 | hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]); |
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 908d858034e4..dc7dfd68fafe 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -1488,11 +1488,16 @@ static int ctnetlink_change_helper(struct nf_conn *ct, | |||
1488 | * treat the second attempt as a no-op instead of returning | 1488 | * treat the second attempt as a no-op instead of returning |
1489 | * an error. | 1489 | * an error. |
1490 | */ | 1490 | */ |
1491 | if (help && help->helper && | 1491 | err = -EBUSY; |
1492 | !strcmp(help->helper->name, helpname)) | 1492 | if (help) { |
1493 | return 0; | 1493 | rcu_read_lock(); |
1494 | else | 1494 | helper = rcu_dereference(help->helper); |
1495 | return -EBUSY; | 1495 | if (helper && !strcmp(helper->name, helpname)) |
1496 | err = 0; | ||
1497 | rcu_read_unlock(); | ||
1498 | } | ||
1499 | |||
1500 | return err; | ||
1496 | } | 1501 | } |
1497 | 1502 | ||
1498 | if (!strcmp(helpname, "")) { | 1503 | if (!strcmp(helpname, "")) { |
@@ -1929,9 +1934,9 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl, | |||
1929 | 1934 | ||
1930 | err = 0; | 1935 | err = 0; |
1931 | if (test_bit(IPS_EXPECTED_BIT, &ct->status)) | 1936 | if (test_bit(IPS_EXPECTED_BIT, &ct->status)) |
1932 | events = IPCT_RELATED; | 1937 | events = 1 << IPCT_RELATED; |
1933 | else | 1938 | else |
1934 | events = IPCT_NEW; | 1939 | events = 1 << IPCT_NEW; |
1935 | 1940 | ||
1936 | if (cda[CTA_LABELS] && | 1941 | if (cda[CTA_LABELS] && |
1937 | ctnetlink_attach_labels(ct, cda) == 0) | 1942 | ctnetlink_attach_labels(ct, cda) == 0) |
@@ -2675,8 +2680,8 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | |||
2675 | last = (struct nf_conntrack_expect *)cb->args[1]; | 2680 | last = (struct nf_conntrack_expect *)cb->args[1]; |
2676 | for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) { | 2681 | for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) { |
2677 | restart: | 2682 | restart: |
2678 | hlist_for_each_entry(exp, &nf_ct_expect_hash[cb->args[0]], | 2683 | hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]], |
2679 | hnode) { | 2684 | hnode) { |
2680 | if (l3proto && exp->tuple.src.l3num != l3proto) | 2685 | if (l3proto && exp->tuple.src.l3num != l3proto) |
2681 | continue; | 2686 | continue; |
2682 | 2687 | ||
@@ -2727,7 +2732,7 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | |||
2727 | rcu_read_lock(); | 2732 | rcu_read_lock(); |
2728 | last = (struct nf_conntrack_expect *)cb->args[1]; | 2733 | last = (struct nf_conntrack_expect *)cb->args[1]; |
2729 | restart: | 2734 | restart: |
2730 | hlist_for_each_entry(exp, &help->expectations, lnode) { | 2735 | hlist_for_each_entry_rcu(exp, &help->expectations, lnode) { |
2731 | if (l3proto && exp->tuple.src.l3num != l3proto) | 2736 | if (l3proto && exp->tuple.src.l3num != l3proto) |
2732 | continue; | 2737 | continue; |
2733 | if (cb->args[1]) { | 2738 | if (cb->args[1]) { |
@@ -2789,6 +2794,12 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl, | |||
2789 | return -ENOENT; | 2794 | return -ENOENT; |
2790 | 2795 | ||
2791 | ct = nf_ct_tuplehash_to_ctrack(h); | 2796 | ct = nf_ct_tuplehash_to_ctrack(h); |
2797 | /* No expectation linked to this connection tracking. */ | ||
2798 | if (!nfct_help(ct)) { | ||
2799 | nf_ct_put(ct); | ||
2800 | return 0; | ||
2801 | } | ||
2802 | |||
2792 | c.data = ct; | 2803 | c.data = ct; |
2793 | 2804 | ||
2794 | err = netlink_dump_start(ctnl, skb, nlh, &c); | 2805 | err = netlink_dump_start(ctnl, skb, nlh, &c); |
@@ -3133,23 +3144,27 @@ ctnetlink_create_expect(struct net *net, | |||
3133 | return -ENOENT; | 3144 | return -ENOENT; |
3134 | ct = nf_ct_tuplehash_to_ctrack(h); | 3145 | ct = nf_ct_tuplehash_to_ctrack(h); |
3135 | 3146 | ||
3147 | rcu_read_lock(); | ||
3136 | if (cda[CTA_EXPECT_HELP_NAME]) { | 3148 | if (cda[CTA_EXPECT_HELP_NAME]) { |
3137 | const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); | 3149 | const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); |
3138 | 3150 | ||
3139 | helper = __nf_conntrack_helper_find(helpname, u3, | 3151 | helper = __nf_conntrack_helper_find(helpname, u3, |
3140 | nf_ct_protonum(ct)); | 3152 | nf_ct_protonum(ct)); |
3141 | if (helper == NULL) { | 3153 | if (helper == NULL) { |
3154 | rcu_read_unlock(); | ||
3142 | #ifdef CONFIG_MODULES | 3155 | #ifdef CONFIG_MODULES |
3143 | if (request_module("nfct-helper-%s", helpname) < 0) { | 3156 | if (request_module("nfct-helper-%s", helpname) < 0) { |
3144 | err = -EOPNOTSUPP; | 3157 | err = -EOPNOTSUPP; |
3145 | goto err_ct; | 3158 | goto err_ct; |
3146 | } | 3159 | } |
3160 | rcu_read_lock(); | ||
3147 | helper = __nf_conntrack_helper_find(helpname, u3, | 3161 | helper = __nf_conntrack_helper_find(helpname, u3, |
3148 | nf_ct_protonum(ct)); | 3162 | nf_ct_protonum(ct)); |
3149 | if (helper) { | 3163 | if (helper) { |
3150 | err = -EAGAIN; | 3164 | err = -EAGAIN; |
3151 | goto err_ct; | 3165 | goto err_rcu; |
3152 | } | 3166 | } |
3167 | rcu_read_unlock(); | ||
3153 | #endif | 3168 | #endif |
3154 | err = -EOPNOTSUPP; | 3169 | err = -EOPNOTSUPP; |
3155 | goto err_ct; | 3170 | goto err_ct; |
@@ -3159,11 +3174,13 @@ ctnetlink_create_expect(struct net *net, | |||
3159 | exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask); | 3174 | exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask); |
3160 | if (IS_ERR(exp)) { | 3175 | if (IS_ERR(exp)) { |
3161 | err = PTR_ERR(exp); | 3176 | err = PTR_ERR(exp); |
3162 | goto err_ct; | 3177 | goto err_rcu; |
3163 | } | 3178 | } |
3164 | 3179 | ||
3165 | err = nf_ct_expect_related_report(exp, portid, report); | 3180 | err = nf_ct_expect_related_report(exp, portid, report); |
3166 | nf_ct_expect_put(exp); | 3181 | nf_ct_expect_put(exp); |
3182 | err_rcu: | ||
3183 | rcu_read_unlock(); | ||
3167 | err_ct: | 3184 | err_ct: |
3168 | nf_ct_put(ct); | 3185 | nf_ct_put(ct); |
3169 | return err; | 3186 | return err; |
diff --git a/net/netfilter/nf_nat_redirect.c b/net/netfilter/nf_nat_redirect.c index d43869879fcf..86067560a318 100644 --- a/net/netfilter/nf_nat_redirect.c +++ b/net/netfilter/nf_nat_redirect.c | |||
@@ -101,11 +101,13 @@ nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range *range, | |||
101 | rcu_read_lock(); | 101 | rcu_read_lock(); |
102 | idev = __in6_dev_get(skb->dev); | 102 | idev = __in6_dev_get(skb->dev); |
103 | if (idev != NULL) { | 103 | if (idev != NULL) { |
104 | read_lock_bh(&idev->lock); | ||
104 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 105 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
105 | newdst = ifa->addr; | 106 | newdst = ifa->addr; |
106 | addr = true; | 107 | addr = true; |
107 | break; | 108 | break; |
108 | } | 109 | } |
110 | read_unlock_bh(&idev->lock); | ||
109 | } | 111 | } |
110 | rcu_read_unlock(); | 112 | rcu_read_unlock(); |
111 | 113 | ||
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index eb2721af898d..c4dad1254ead 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c | |||
@@ -21,6 +21,7 @@ struct nft_hash { | |||
21 | enum nft_registers sreg:8; | 21 | enum nft_registers sreg:8; |
22 | enum nft_registers dreg:8; | 22 | enum nft_registers dreg:8; |
23 | u8 len; | 23 | u8 len; |
24 | bool autogen_seed:1; | ||
24 | u32 modulus; | 25 | u32 modulus; |
25 | u32 seed; | 26 | u32 seed; |
26 | u32 offset; | 27 | u32 offset; |
@@ -82,10 +83,12 @@ static int nft_hash_init(const struct nft_ctx *ctx, | |||
82 | if (priv->offset + priv->modulus - 1 < priv->offset) | 83 | if (priv->offset + priv->modulus - 1 < priv->offset) |
83 | return -EOVERFLOW; | 84 | return -EOVERFLOW; |
84 | 85 | ||
85 | if (tb[NFTA_HASH_SEED]) | 86 | if (tb[NFTA_HASH_SEED]) { |
86 | priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED])); | 87 | priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED])); |
87 | else | 88 | } else { |
89 | priv->autogen_seed = true; | ||
88 | get_random_bytes(&priv->seed, sizeof(priv->seed)); | 90 | get_random_bytes(&priv->seed, sizeof(priv->seed)); |
91 | } | ||
89 | 92 | ||
90 | return nft_validate_register_load(priv->sreg, len) && | 93 | return nft_validate_register_load(priv->sreg, len) && |
91 | nft_validate_register_store(ctx, priv->dreg, NULL, | 94 | nft_validate_register_store(ctx, priv->dreg, NULL, |
@@ -105,7 +108,8 @@ static int nft_hash_dump(struct sk_buff *skb, | |||
105 | goto nla_put_failure; | 108 | goto nla_put_failure; |
106 | if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus))) | 109 | if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus))) |
107 | goto nla_put_failure; | 110 | goto nla_put_failure; |
108 | if (nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed))) | 111 | if (!priv->autogen_seed && |
112 | nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed))) | ||
109 | goto nla_put_failure; | 113 | goto nla_put_failure; |
110 | if (priv->offset != 0) | 114 | if (priv->offset != 0) |
111 | if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset))) | 115 | if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset))) |
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 27241a767f17..c64aca611ac5 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c | |||
@@ -104,7 +104,7 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
104 | tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); | 104 | tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); |
105 | tcp_hdrlen = tcph->doff * 4; | 105 | tcp_hdrlen = tcph->doff * 4; |
106 | 106 | ||
107 | if (len < tcp_hdrlen) | 107 | if (len < tcp_hdrlen || tcp_hdrlen < sizeof(struct tcphdr)) |
108 | return -1; | 108 | return -1; |
109 | 109 | ||
110 | if (info->mss == XT_TCPMSS_CLAMP_PMTU) { | 110 | if (info->mss == XT_TCPMSS_CLAMP_PMTU) { |
@@ -152,6 +152,10 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
152 | if (len > tcp_hdrlen) | 152 | if (len > tcp_hdrlen) |
153 | return 0; | 153 | return 0; |
154 | 154 | ||
155 | /* tcph->doff has 4 bits, do not wrap it to 0 */ | ||
156 | if (tcp_hdrlen >= 15 * 4) | ||
157 | return 0; | ||
158 | |||
155 | /* | 159 | /* |
156 | * MSS Option not found ?! add it.. | 160 | * MSS Option not found ?! add it.. |
157 | */ | 161 | */ |
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c index 80cb7babeb64..df7f1df00330 100644 --- a/net/netfilter/xt_TPROXY.c +++ b/net/netfilter/xt_TPROXY.c | |||
@@ -393,7 +393,8 @@ tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr, | |||
393 | 393 | ||
394 | rcu_read_lock(); | 394 | rcu_read_lock(); |
395 | indev = __in6_dev_get(skb->dev); | 395 | indev = __in6_dev_get(skb->dev); |
396 | if (indev) | 396 | if (indev) { |
397 | read_lock_bh(&indev->lock); | ||
397 | list_for_each_entry(ifa, &indev->addr_list, if_list) { | 398 | list_for_each_entry(ifa, &indev->addr_list, if_list) { |
398 | if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) | 399 | if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) |
399 | continue; | 400 | continue; |
@@ -401,6 +402,8 @@ tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr, | |||
401 | laddr = &ifa->addr; | 402 | laddr = &ifa->addr; |
402 | break; | 403 | break; |
403 | } | 404 | } |
405 | read_unlock_bh(&indev->lock); | ||
406 | } | ||
404 | rcu_read_unlock(); | 407 | rcu_read_unlock(); |
405 | 408 | ||
406 | return laddr ? laddr : daddr; | 409 | return laddr ? laddr : daddr; |