Skip to content

Commit 4d89ac2

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter/IPVS/OVS fixes for net The following patchset contains a rather large batch of Netfilter, IPVS and OVS fixes for your net tree. This includes fixes for ctnetlink, the userspace conntrack helper infrastructure, conntrack OVS support, ebtables DNAT target, several leaks in error path among other. More specifically, they are: 1) Fix reference count leak in the CT target error path, from Gao Feng. 2) Remove conntrack entry clashing with a matching expectation, patch from Jarno Rajahalme. 3) Fix bogus EEXIST when registering two different userspace helpers, from Liping Zhang. 4) Don't leak dummy elements in the new bitmap set type in nf_tables, from Liping Zhang. 5) Get rid of module autoload from conntrack update path in ctnetlink, we don't need autoload at this late stage and it is happening with rcu read lock held which is not good. From Liping Zhang. 6) Fix deadlock due to double-acquire of the expect_lock from conntrack update path, this fixes a bug that was introduced when the central spinlock got removed. Again from Liping Zhang. 7) Safe ct->status update from ctnetlink path, from Liping. The expect_lock protection that was selected when the central spinlock was removed was not really protecting anything at all. 8) Protect sequence adjustment under ct->lock. 9) Missing socket match with IPv6, from Peter Tirsek. 10) Adjust skb->pkt_type of DNAT'ed frames from ebtables, from Linus Luessing. 11) Don't give up on evaluating the expression on new entries added via dynset expression in nf_tables, from Liping Zhang. 12) Use skb_checksum() when mangling icmpv6 in IPv6 NAT as this deals with non-linear skbuffs. 13) Don't allow IPv6 service in IPVS if no IPv6 support is available, from Paolo Abeni. 14) Missing mutex release in error path of xt_find_table_lock(), from Dan Carpenter. 15) Update maintainers files, Netfilter section. Add Florian to the file, refer to nftables.org and change project status from Supported to Maintained. 16) Bail out on mismatching extensions in element updates in nf_tables. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents ab71632 + 9744a6f commit 4d89ac2

File tree

14 files changed

+174
-64
lines changed

14 files changed

+174
-64
lines changed

MAINTAINERS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8747,14 +8747,16 @@ F: drivers/net/ethernet/neterion/
87478747
NETFILTER
87488748
M: Pablo Neira Ayuso <pablo@netfilter.org>
87498749
M: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
8750+
M: Florian Westphal <fw@strlen.de>
87508751
L: netfilter-devel@vger.kernel.org
87518752
L: coreteam@netfilter.org
87528753
W: http://www.netfilter.org/
87538754
W: http://www.iptables.org/
8755+
W: http://www.nftables.org/
87548756
Q: http://patchwork.ozlabs.org/project/netfilter-devel/list/
87558757
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git
87568758
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git
8757-
S: Supported
8759+
S: Maintained
87588760
F: include/linux/netfilter*
87598761
F: include/linux/netfilter/
87608762
F: include/net/netfilter/

include/uapi/linux/netfilter/nf_conntrack_common.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,6 @@ enum ip_conntrack_status {
8484
IPS_DYING_BIT = 9,
8585
IPS_DYING = (1 << IPS_DYING_BIT),
8686

87-
/* Bits that cannot be altered from userland. */
88-
IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
89-
IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING),
90-
9187
/* Connection has fixed timeout. */
9288
IPS_FIXED_TIMEOUT_BIT = 10,
9389
IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
@@ -103,6 +99,15 @@ enum ip_conntrack_status {
10399
/* Conntrack got a helper explicitly attached via CT target. */
104100
IPS_HELPER_BIT = 13,
105101
IPS_HELPER = (1 << IPS_HELPER_BIT),
102+
103+
/* Be careful here, modifying these bits can make things messy,
104+
* so don't let users modify them directly.
105+
*/
106+
IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
107+
IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING |
108+
IPS_SEQ_ADJUST | IPS_TEMPLATE),
109+
110+
__IPS_MAX_BIT = 14,
106111
};
107112

108113
/* Connection tracking event types */

net/bridge/netfilter/ebt_dnat.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010
#include <linux/module.h>
1111
#include <net/sock.h>
12+
#include "../br_private.h"
1213
#include <linux/netfilter.h>
1314
#include <linux/netfilter/x_tables.h>
1415
#include <linux/netfilter_bridge/ebtables.h>
@@ -18,11 +19,30 @@ static unsigned int
1819
ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par)
1920
{
2021
const struct ebt_nat_info *info = par->targinfo;
22+
struct net_device *dev;
2123

2224
if (!skb_make_writable(skb, 0))
2325
return EBT_DROP;
2426

2527
ether_addr_copy(eth_hdr(skb)->h_dest, info->mac);
28+
29+
if (is_multicast_ether_addr(info->mac)) {
30+
if (is_broadcast_ether_addr(info->mac))
31+
skb->pkt_type = PACKET_BROADCAST;
32+
else
33+
skb->pkt_type = PACKET_MULTICAST;
34+
} else {
35+
if (xt_hooknum(par) != NF_BR_BROUTING)
36+
dev = br_port_get_rcu(xt_in(par))->br->dev;
37+
else
38+
dev = xt_in(par);
39+
40+
if (ether_addr_equal(info->mac, dev->dev_addr))
41+
skb->pkt_type = PACKET_HOST;
42+
else
43+
skb->pkt_type = PACKET_OTHERHOST;
44+
}
45+
2646
return info->target;
2747
}
2848

net/ipv6/netfilter/nf_nat_l3proto_ipv6.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ int nf_nat_icmpv6_reply_translation(struct sk_buff *skb,
235235
inside->icmp6.icmp6_cksum =
236236
csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
237237
skb->len - hdrlen, IPPROTO_ICMPV6,
238-
csum_partial(&inside->icmp6,
238+
skb_checksum(skb, hdrlen,
239239
skb->len - hdrlen, 0));
240240
}
241241

net/netfilter/ipvs/ip_vs_ctl.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3078,6 +3078,17 @@ static int ip_vs_genl_dump_services(struct sk_buff *skb,
30783078
return skb->len;
30793079
}
30803080

3081+
static bool ip_vs_is_af_valid(int af)
3082+
{
3083+
if (af == AF_INET)
3084+
return true;
3085+
#ifdef CONFIG_IP_VS_IPV6
3086+
if (af == AF_INET6 && ipv6_mod_enabled())
3087+
return true;
3088+
#endif
3089+
return false;
3090+
}
3091+
30813092
static int ip_vs_genl_parse_service(struct netns_ipvs *ipvs,
30823093
struct ip_vs_service_user_kern *usvc,
30833094
struct nlattr *nla, int full_entry,
@@ -3105,11 +3116,7 @@ static int ip_vs_genl_parse_service(struct netns_ipvs *ipvs,
31053116
memset(usvc, 0, sizeof(*usvc));
31063117

31073118
usvc->af = nla_get_u16(nla_af);
3108-
#ifdef CONFIG_IP_VS_IPV6
3109-
if (usvc->af != AF_INET && usvc->af != AF_INET6)
3110-
#else
3111-
if (usvc->af != AF_INET)
3112-
#endif
3119+
if (!ip_vs_is_af_valid(usvc->af))
31133120
return -EAFNOSUPPORT;
31143121

31153122
if (nla_fwmark) {
@@ -3612,6 +3619,11 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
36123619
if (udest.af == 0)
36133620
udest.af = svc->af;
36143621

3622+
if (!ip_vs_is_af_valid(udest.af)) {
3623+
ret = -EAFNOSUPPORT;
3624+
goto out;
3625+
}
3626+
36153627
if (udest.af != svc->af && cmd != IPVS_CMD_DEL_DEST) {
36163628
/* The synchronization protocol is incompatible
36173629
* with mixed family services

net/netfilter/nf_conntrack_helper.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
385385
struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
386386
unsigned int h = helper_hash(&me->tuple);
387387
struct nf_conntrack_helper *cur;
388-
int ret = 0;
388+
int ret = 0, i;
389389

390390
BUG_ON(me->expect_policy == NULL);
391391
BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
@@ -395,10 +395,26 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
395395
return -EINVAL;
396396

397397
mutex_lock(&nf_ct_helper_mutex);
398-
hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) {
399-
if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple, &mask)) {
400-
ret = -EEXIST;
401-
goto out;
398+
for (i = 0; i < nf_ct_helper_hsize; i++) {
399+
hlist_for_each_entry(cur, &nf_ct_helper_hash[i], hnode) {
400+
if (!strcmp(cur->name, me->name) &&
401+
(cur->tuple.src.l3num == NFPROTO_UNSPEC ||
402+
cur->tuple.src.l3num == me->tuple.src.l3num) &&
403+
cur->tuple.dst.protonum == me->tuple.dst.protonum) {
404+
ret = -EEXIST;
405+
goto out;
406+
}
407+
}
408+
}
409+
410+
/* avoid unpredictable behaviour for auto_assign_helper */
411+
if (!(me->flags & NF_CT_HELPER_F_USERSPACE)) {
412+
hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) {
413+
if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple,
414+
&mask)) {
415+
ret = -EEXIST;
416+
goto out;
417+
}
402418
}
403419
}
404420
hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);

net/netfilter/nf_conntrack_netlink.c

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -417,24 +417,28 @@ dump_ct_seq_adj(struct sk_buff *skb, const struct nf_ct_seqadj *seq, int type)
417417
return -1;
418418
}
419419

420-
static int ctnetlink_dump_ct_seq_adj(struct sk_buff *skb,
421-
const struct nf_conn *ct)
420+
static int ctnetlink_dump_ct_seq_adj(struct sk_buff *skb, struct nf_conn *ct)
422421
{
423422
struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
424423
struct nf_ct_seqadj *seq;
425424

426425
if (!(ct->status & IPS_SEQ_ADJUST) || !seqadj)
427426
return 0;
428427

428+
spin_lock_bh(&ct->lock);
429429
seq = &seqadj->seq[IP_CT_DIR_ORIGINAL];
430430
if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_ORIG) == -1)
431-
return -1;
431+
goto err;
432432

433433
seq = &seqadj->seq[IP_CT_DIR_REPLY];
434434
if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_REPLY) == -1)
435-
return -1;
435+
goto err;
436436

437+
spin_unlock_bh(&ct->lock);
437438
return 0;
439+
err:
440+
spin_unlock_bh(&ct->lock);
441+
return -1;
438442
}
439443

440444
static int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
@@ -1417,6 +1421,24 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
14171421
}
14181422
#endif
14191423

1424+
static void
1425+
__ctnetlink_change_status(struct nf_conn *ct, unsigned long on,
1426+
unsigned long off)
1427+
{
1428+
unsigned int bit;
1429+
1430+
/* Ignore these unchangable bits */
1431+
on &= ~IPS_UNCHANGEABLE_MASK;
1432+
off &= ~IPS_UNCHANGEABLE_MASK;
1433+
1434+
for (bit = 0; bit < __IPS_MAX_BIT; bit++) {
1435+
if (on & (1 << bit))
1436+
set_bit(bit, &ct->status);
1437+
else if (off & (1 << bit))
1438+
clear_bit(bit, &ct->status);
1439+
}
1440+
}
1441+
14201442
static int
14211443
ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
14221444
{
@@ -1436,10 +1458,7 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
14361458
/* ASSURED bit can only be set */
14371459
return -EBUSY;
14381460

1439-
/* Be careful here, modifying NAT bits can screw up things,
1440-
* so don't let users modify them directly if they don't pass
1441-
* nf_nat_range. */
1442-
ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
1461+
__ctnetlink_change_status(ct, status, 0);
14431462
return 0;
14441463
}
14451464

@@ -1508,23 +1527,11 @@ static int ctnetlink_change_helper(struct nf_conn *ct,
15081527
return 0;
15091528
}
15101529

1530+
rcu_read_lock();
15111531
helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
15121532
nf_ct_protonum(ct));
15131533
if (helper == NULL) {
1514-
#ifdef CONFIG_MODULES
1515-
spin_unlock_bh(&nf_conntrack_expect_lock);
1516-
1517-
if (request_module("nfct-helper-%s", helpname) < 0) {
1518-
spin_lock_bh(&nf_conntrack_expect_lock);
1519-
return -EOPNOTSUPP;
1520-
}
1521-
1522-
spin_lock_bh(&nf_conntrack_expect_lock);
1523-
helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
1524-
nf_ct_protonum(ct));
1525-
if (helper)
1526-
return -EAGAIN;
1527-
#endif
1534+
rcu_read_unlock();
15281535
return -EOPNOTSUPP;
15291536
}
15301537

@@ -1533,13 +1540,16 @@ static int ctnetlink_change_helper(struct nf_conn *ct,
15331540
/* update private helper data if allowed. */
15341541
if (helper->from_nlattr)
15351542
helper->from_nlattr(helpinfo, ct);
1536-
return 0;
1543+
err = 0;
15371544
} else
1538-
return -EBUSY;
1545+
err = -EBUSY;
1546+
} else {
1547+
/* we cannot set a helper for an existing conntrack */
1548+
err = -EOPNOTSUPP;
15391549
}
15401550

1541-
/* we cannot set a helper for an existing conntrack */
1542-
return -EOPNOTSUPP;
1551+
rcu_read_unlock();
1552+
return err;
15431553
}
15441554

15451555
static int ctnetlink_change_timeout(struct nf_conn *ct,
@@ -1630,25 +1640,30 @@ ctnetlink_change_seq_adj(struct nf_conn *ct,
16301640
if (!seqadj)
16311641
return 0;
16321642

1643+
spin_lock_bh(&ct->lock);
16331644
if (cda[CTA_SEQ_ADJ_ORIG]) {
16341645
ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_ORIGINAL],
16351646
cda[CTA_SEQ_ADJ_ORIG]);
16361647
if (ret < 0)
1637-
return ret;
1648+
goto err;
16381649

1639-
ct->status |= IPS_SEQ_ADJUST;
1650+
set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
16401651
}
16411652

16421653
if (cda[CTA_SEQ_ADJ_REPLY]) {
16431654
ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_REPLY],
16441655
cda[CTA_SEQ_ADJ_REPLY]);
16451656
if (ret < 0)
1646-
return ret;
1657+
goto err;
16471658

1648-
ct->status |= IPS_SEQ_ADJUST;
1659+
set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
16491660
}
16501661

1662+
spin_unlock_bh(&ct->lock);
16511663
return 0;
1664+
err:
1665+
spin_unlock_bh(&ct->lock);
1666+
return ret;
16521667
}
16531668

16541669
static int
@@ -1959,9 +1974,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
19591974
err = -EEXIST;
19601975
ct = nf_ct_tuplehash_to_ctrack(h);
19611976
if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
1962-
spin_lock_bh(&nf_conntrack_expect_lock);
19631977
err = ctnetlink_change_conntrack(ct, cda);
1964-
spin_unlock_bh(&nf_conntrack_expect_lock);
19651978
if (err == 0) {
19661979
nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
19671980
(1 << IPCT_ASSURED) |
@@ -2294,10 +2307,10 @@ ctnetlink_update_status(struct nf_conn *ct, const struct nlattr * const cda[])
22942307
/* This check is less strict than ctnetlink_change_status()
22952308
* because callers often flip IPS_EXPECTED bits when sending
22962309
* an NFQA_CT attribute to the kernel. So ignore the
2297-
* unchangeable bits but do not error out.
2310+
* unchangeable bits but do not error out. Also user programs
2311+
* are allowed to clear the bits that they are allowed to change.
22982312
*/
2299-
ct->status = (status & ~IPS_UNCHANGEABLE_MASK) |
2300-
(ct->status & IPS_UNCHANGEABLE_MASK);
2313+
__ctnetlink_change_status(ct, status, ~status);
23012314
return 0;
23022315
}
23032316

@@ -2351,11 +2364,7 @@ ctnetlink_glue_parse(const struct nlattr *attr, struct nf_conn *ct)
23512364
if (ret < 0)
23522365
return ret;
23532366

2354-
spin_lock_bh(&nf_conntrack_expect_lock);
2355-
ret = ctnetlink_glue_parse_ct((const struct nlattr **)cda, ct);
2356-
spin_unlock_bh(&nf_conntrack_expect_lock);
2357-
2358-
return ret;
2367+
return ctnetlink_glue_parse_ct((const struct nlattr **)cda, ct);
23592368
}
23602369

23612370
static int ctnetlink_glue_exp_parse(const struct nlattr * const *cda,

net/netfilter/nf_tables_api.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3778,6 +3778,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
37783778
err = set->ops->insert(ctx->net, set, &elem, &ext2);
37793779
if (err) {
37803780
if (err == -EEXIST) {
3781+
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) ^
3782+
nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) ||
3783+
nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) ^
3784+
nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF))
3785+
return -EBUSY;
37813786
if ((nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
37823787
nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) &&
37833788
memcmp(nft_set_ext_data(ext),

net/netfilter/nft_dynset.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ static void nft_dynset_eval(const struct nft_expr *expr,
8282
nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
8383
timeout = priv->timeout ? : set->timeout;
8484
*nft_set_ext_expiration(ext) = jiffies + timeout;
85-
} else if (sexpr == NULL)
86-
goto out;
85+
}
8786

8887
if (sexpr != NULL)
8988
sexpr->ops->eval(sexpr, regs, pkt);
@@ -92,7 +91,7 @@ static void nft_dynset_eval(const struct nft_expr *expr,
9291
regs->verdict.code = NFT_BREAK;
9392
return;
9493
}
95-
out:
94+
9695
if (!priv->invert)
9796
regs->verdict.code = NFT_BREAK;
9897
}

0 commit comments

Comments
 (0)