Skip to content

Commit f4c13c8

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for your net tree, they are: 1) Missing TCP header sanity check in TCPMSS target, from Eric Dumazet. 2) Incorrect event message type for related conntracks created via ctnetlink, from Liping Zhang. 3) Fix incorrect rcu locking when handling helpers from ctnetlink, from Gao feng. 4) Fix missing rcu locking when updating helper, from Liping Zhang. 5) Fix missing read_lock_bh when iterating over list of device addresses from TPROXY and redirect, also from Liping. 6) Fix crash when trying to dump expectations from conntrack with no helper via ctnetlink, from Liping. 7) Missing RCU protection to expecation list update given ctnetlink iterates over the list under rcu read lock side, from Liping too. 8) Don't dump autogenerated seed in nft_hash to userspace, this is very confusing to the user, again from Liping. 9) Fix wrong conntrack netns module refcount in ipt_CLUSTERIP, from Gao feng. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 14cf4a7 + fe50543 commit f4c13c8

File tree

8 files changed

+62
-25
lines changed

8 files changed

+62
-25
lines changed

net/ipv4/netfilter/ipt_CLUSTERIP.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
461461

462462
clusterip_config_put(cipinfo->config);
463463

464-
nf_ct_netns_get(par->net, par->family);
464+
nf_ct_netns_put(par->net, par->family);
465465
}
466466

467467
#ifdef CONFIG_COMPAT

net/netfilter/nf_conntrack_expect.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
5757
hlist_del_rcu(&exp->hnode);
5858
net->ct.expect_count--;
5959

60-
hlist_del(&exp->lnode);
60+
hlist_del_rcu(&exp->lnode);
6161
master_help->expecting[exp->class]--;
6262

6363
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)
363363
/* two references : one for hash insert, one for the timer */
364364
atomic_add(2, &exp->use);
365365

366-
hlist_add_head(&exp->lnode, &master_help->expectations);
366+
hlist_add_head_rcu(&exp->lnode, &master_help->expectations);
367367
master_help->expecting[exp->class]++;
368368

369369
hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);

net/netfilter/nf_conntrack_helper.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,25 @@ nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
158158
{
159159
struct nf_conntrack_helper *h;
160160

161+
rcu_read_lock();
162+
161163
h = __nf_conntrack_helper_find(name, l3num, protonum);
162164
#ifdef CONFIG_MODULES
163165
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();
165169
h = __nf_conntrack_helper_find(name, l3num, protonum);
170+
} else {
171+
return h;
172+
}
166173
}
167174
#endif
168175
if (h != NULL && !try_module_get(h->me))
169176
h = NULL;
170177

178+
rcu_read_unlock();
179+
171180
return h;
172181
}
173182
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)
311320
}
312321
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);
313322

323+
/* Caller should hold the rcu lock */
314324
struct nf_ct_helper_expectfn *
315325
nf_ct_helper_expectfn_find_by_name(const char *name)
316326
{
317327
struct nf_ct_helper_expectfn *cur;
318328
bool found = false;
319329

320-
rcu_read_lock();
321330
list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
322331
if (!strcmp(cur->name, name)) {
323332
found = true;
324333
break;
325334
}
326335
}
327-
rcu_read_unlock();
328336
return found ? cur : NULL;
329337
}
330338
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name);
331339

340+
/* Caller should hold the rcu lock */
332341
struct nf_ct_helper_expectfn *
333342
nf_ct_helper_expectfn_find_by_symbol(const void *symbol)
334343
{
335344
struct nf_ct_helper_expectfn *cur;
336345
bool found = false;
337346

338-
rcu_read_lock();
339347
list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
340348
if (cur->expectfn == symbol) {
341349
found = true;
342350
break;
343351
}
344352
}
345-
rcu_read_unlock();
346353
return found ? cur : NULL;
347354
}
348355
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);

net/netfilter/nf_conntrack_netlink.c

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,11 +1488,16 @@ static int ctnetlink_change_helper(struct nf_conn *ct,
14881488
* treat the second attempt as a no-op instead of returning
14891489
* an error.
14901490
*/
1491-
if (help && help->helper &&
1492-
!strcmp(help->helper->name, helpname))
1493-
return 0;
1494-
else
1495-
return -EBUSY;
1491+
err = -EBUSY;
1492+
if (help) {
1493+
rcu_read_lock();
1494+
helper = rcu_dereference(help->helper);
1495+
if (helper && !strcmp(helper->name, helpname))
1496+
err = 0;
1497+
rcu_read_unlock();
1498+
}
1499+
1500+
return err;
14961501
}
14971502

14981503
if (!strcmp(helpname, "")) {
@@ -1929,9 +1934,9 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
19291934

19301935
err = 0;
19311936
if (test_bit(IPS_EXPECTED_BIT, &ct->status))
1932-
events = IPCT_RELATED;
1937+
events = 1 << IPCT_RELATED;
19331938
else
1934-
events = IPCT_NEW;
1939+
events = 1 << IPCT_NEW;
19351940

19361941
if (cda[CTA_LABELS] &&
19371942
ctnetlink_attach_labels(ct, cda) == 0)
@@ -2675,8 +2680,8 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
26752680
last = (struct nf_conntrack_expect *)cb->args[1];
26762681
for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
26772682
restart:
2678-
hlist_for_each_entry(exp, &nf_ct_expect_hash[cb->args[0]],
2679-
hnode) {
2683+
hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]],
2684+
hnode) {
26802685
if (l3proto && exp->tuple.src.l3num != l3proto)
26812686
continue;
26822687

@@ -2727,7 +2732,7 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
27272732
rcu_read_lock();
27282733
last = (struct nf_conntrack_expect *)cb->args[1];
27292734
restart:
2730-
hlist_for_each_entry(exp, &help->expectations, lnode) {
2735+
hlist_for_each_entry_rcu(exp, &help->expectations, lnode) {
27312736
if (l3proto && exp->tuple.src.l3num != l3proto)
27322737
continue;
27332738
if (cb->args[1]) {
@@ -2789,6 +2794,12 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
27892794
return -ENOENT;
27902795

27912796
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+
27922803
c.data = ct;
27932804

27942805
err = netlink_dump_start(ctnl, skb, nlh, &c);
@@ -3133,23 +3144,27 @@ ctnetlink_create_expect(struct net *net,
31333144
return -ENOENT;
31343145
ct = nf_ct_tuplehash_to_ctrack(h);
31353146

3147+
rcu_read_lock();
31363148
if (cda[CTA_EXPECT_HELP_NAME]) {
31373149
const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
31383150

31393151
helper = __nf_conntrack_helper_find(helpname, u3,
31403152
nf_ct_protonum(ct));
31413153
if (helper == NULL) {
3154+
rcu_read_unlock();
31423155
#ifdef CONFIG_MODULES
31433156
if (request_module("nfct-helper-%s", helpname) < 0) {
31443157
err = -EOPNOTSUPP;
31453158
goto err_ct;
31463159
}
3160+
rcu_read_lock();
31473161
helper = __nf_conntrack_helper_find(helpname, u3,
31483162
nf_ct_protonum(ct));
31493163
if (helper) {
31503164
err = -EAGAIN;
3151-
goto err_ct;
3165+
goto err_rcu;
31523166
}
3167+
rcu_read_unlock();
31533168
#endif
31543169
err = -EOPNOTSUPP;
31553170
goto err_ct;
@@ -3159,11 +3174,13 @@ ctnetlink_create_expect(struct net *net,
31593174
exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
31603175
if (IS_ERR(exp)) {
31613176
err = PTR_ERR(exp);
3162-
goto err_ct;
3177+
goto err_rcu;
31633178
}
31643179

31653180
err = nf_ct_expect_related_report(exp, portid, report);
31663181
nf_ct_expect_put(exp);
3182+
err_rcu:
3183+
rcu_read_unlock();
31673184
err_ct:
31683185
nf_ct_put(ct);
31693186
return err;

net/netfilter/nf_nat_redirect.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,13 @@ nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range *range,
101101
rcu_read_lock();
102102
idev = __in6_dev_get(skb->dev);
103103
if (idev != NULL) {
104+
read_lock_bh(&idev->lock);
104105
list_for_each_entry(ifa, &idev->addr_list, if_list) {
105106
newdst = ifa->addr;
106107
addr = true;
107108
break;
108109
}
110+
read_unlock_bh(&idev->lock);
109111
}
110112
rcu_read_unlock();
111113

net/netfilter/nft_hash.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct nft_hash {
2121
enum nft_registers sreg:8;
2222
enum nft_registers dreg:8;
2323
u8 len;
24+
bool autogen_seed:1;
2425
u32 modulus;
2526
u32 seed;
2627
u32 offset;
@@ -82,10 +83,12 @@ static int nft_hash_init(const struct nft_ctx *ctx,
8283
if (priv->offset + priv->modulus - 1 < priv->offset)
8384
return -EOVERFLOW;
8485

85-
if (tb[NFTA_HASH_SEED])
86+
if (tb[NFTA_HASH_SEED]) {
8687
priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED]));
87-
else
88+
} else {
89+
priv->autogen_seed = true;
8890
get_random_bytes(&priv->seed, sizeof(priv->seed));
91+
}
8992

9093
return nft_validate_register_load(priv->sreg, len) &&
9194
nft_validate_register_store(ctx, priv->dreg, NULL,
@@ -105,7 +108,8 @@ static int nft_hash_dump(struct sk_buff *skb,
105108
goto nla_put_failure;
106109
if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus)))
107110
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)))
109113
goto nla_put_failure;
110114
if (priv->offset != 0)
111115
if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))

net/netfilter/xt_TCPMSS.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ tcpmss_mangle_packet(struct sk_buff *skb,
104104
tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
105105
tcp_hdrlen = tcph->doff * 4;
106106

107-
if (len < tcp_hdrlen)
107+
if (len < tcp_hdrlen || tcp_hdrlen < sizeof(struct tcphdr))
108108
return -1;
109109

110110
if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
@@ -152,6 +152,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
152152
if (len > tcp_hdrlen)
153153
return 0;
154154

155+
/* tcph->doff has 4 bits, do not wrap it to 0 */
156+
if (tcp_hdrlen >= 15 * 4)
157+
return 0;
158+
155159
/*
156160
* MSS Option not found ?! add it..
157161
*/

net/netfilter/xt_TPROXY.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,14 +393,17 @@ tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr,
393393

394394
rcu_read_lock();
395395
indev = __in6_dev_get(skb->dev);
396-
if (indev)
396+
if (indev) {
397+
read_lock_bh(&indev->lock);
397398
list_for_each_entry(ifa, &indev->addr_list, if_list) {
398399
if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
399400
continue;
400401

401402
laddr = &ifa->addr;
402403
break;
403404
}
405+
read_unlock_bh(&indev->lock);
406+
}
404407
rcu_read_unlock();
405408

406409
return laddr ? laddr : daddr;

0 commit comments

Comments
 (0)