diff options
author | David S. Miller <davem@davemloft.net> | 2014-10-27 18:47:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-10-27 18:47:40 -0400 |
commit | 5d26b1f50a610fb28700cdc3446590495a5f607c (patch) | |
tree | f937c9e7f4d0eabeed93dce93a21020c1fb164e5 /net | |
parent | 93a35f59f1b13a02674877e3efdf07ae47e34052 (diff) | |
parent | 7965ee93719921ea5978f331da653dfa2d7b99f5 (diff) |
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) Allow to recycle a TCP port in conntrack when the change role from
server to client, from Marcelo Leitner.
2) Fix possible off by one access in ip_set_nfnl_get_byindex(), patch
from Dan Carpenter.
3) alloc_percpu returns NULL on error, no need for IS_ERR() in nf_tables
chain statistic updates. From Sabrina Dubroca.
4) Don't compile ip options in bridge netfilter, this mangles the packet
and bridge should not alter layer >= 3 headers when forwarding packets.
Patch from Herbert Xu and tested by Florian Westphal.
5) Account the final NLMSG_DONE message when calculating the size of the
nflog netlink batches. Patch from Florian Westphal.
6) Fix a possible netlink attribute length overflow with large packets.
Again from Florian Westphal.
7) Release the skbuff if nfnetlink_log fails to put the final
NLMSG_DONE message. This fixes a leak on error. This shouldn't ever
happen though, otherwise this means we miscalculate the netlink batch
size, so spot a warning if this ever happens so we can track down the
problem. This patch from Houcheng Lin.
8) Look at the right list when recycling targets in the nft_compat,
patch from Arturo Borrero.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/bridge/br_netfilter.c | 24 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_core.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_tcp.c | 4 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 4 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_log.c | 31 | ||||
-rw-r--r-- | net/netfilter/nft_compat.c | 2 |
6 files changed, 27 insertions, 40 deletions
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 1bada53bb195..1a4f32c09ad5 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -192,7 +192,6 @@ static inline void nf_bridge_save_header(struct sk_buff *skb) | |||
192 | 192 | ||
193 | static int br_parse_ip_options(struct sk_buff *skb) | 193 | static int br_parse_ip_options(struct sk_buff *skb) |
194 | { | 194 | { |
195 | struct ip_options *opt; | ||
196 | const struct iphdr *iph; | 195 | const struct iphdr *iph; |
197 | struct net_device *dev = skb->dev; | 196 | struct net_device *dev = skb->dev; |
198 | u32 len; | 197 | u32 len; |
@@ -201,7 +200,6 @@ static int br_parse_ip_options(struct sk_buff *skb) | |||
201 | goto inhdr_error; | 200 | goto inhdr_error; |
202 | 201 | ||
203 | iph = ip_hdr(skb); | 202 | iph = ip_hdr(skb); |
204 | opt = &(IPCB(skb)->opt); | ||
205 | 203 | ||
206 | /* Basic sanity checks */ | 204 | /* Basic sanity checks */ |
207 | if (iph->ihl < 5 || iph->version != 4) | 205 | if (iph->ihl < 5 || iph->version != 4) |
@@ -227,23 +225,11 @@ static int br_parse_ip_options(struct sk_buff *skb) | |||
227 | } | 225 | } |
228 | 226 | ||
229 | memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); | 227 | memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); |
230 | if (iph->ihl == 5) | 228 | /* We should really parse IP options here but until |
231 | return 0; | 229 | * somebody who actually uses IP options complains to |
232 | 230 | * us we'll just silently ignore the options because | |
233 | opt->optlen = iph->ihl*4 - sizeof(struct iphdr); | 231 | * we're lazy! |
234 | if (ip_options_compile(dev_net(dev), opt, skb)) | 232 | */ |
235 | goto inhdr_error; | ||
236 | |||
237 | /* Check correct handling of SRR option */ | ||
238 | if (unlikely(opt->srr)) { | ||
239 | struct in_device *in_dev = __in_dev_get_rcu(dev); | ||
240 | if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev)) | ||
241 | goto drop; | ||
242 | |||
243 | if (ip_options_rcv_srr(skb)) | ||
244 | goto drop; | ||
245 | } | ||
246 | |||
247 | return 0; | 233 | return 0; |
248 | 234 | ||
249 | inhdr_error: | 235 | inhdr_error: |
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 912e5a05b79d..86f9d76b1464 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
@@ -659,7 +659,7 @@ ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index) | |||
659 | struct ip_set *set; | 659 | struct ip_set *set; |
660 | struct ip_set_net *inst = ip_set_pernet(net); | 660 | struct ip_set_net *inst = ip_set_pernet(net); |
661 | 661 | ||
662 | if (index > inst->ip_set_max) | 662 | if (index >= inst->ip_set_max) |
663 | return IPSET_INVALID_ID; | 663 | return IPSET_INVALID_ID; |
664 | 664 | ||
665 | nfnl_lock(NFNL_SUBSYS_IPSET); | 665 | nfnl_lock(NFNL_SUBSYS_IPSET); |
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 44d1ea32570a..d87b6423ffb2 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -213,7 +213,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { | |||
213 | { | 213 | { |
214 | /* REPLY */ | 214 | /* REPLY */ |
215 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 215 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
216 | /*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sS2 }, | 216 | /*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sSS, sIV, sS2 }, |
217 | /* | 217 | /* |
218 | * sNO -> sIV Never reached. | 218 | * sNO -> sIV Never reached. |
219 | * sSS -> sS2 Simultaneous open | 219 | * sSS -> sS2 Simultaneous open |
@@ -223,7 +223,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { | |||
223 | * sFW -> sIV | 223 | * sFW -> sIV |
224 | * sCW -> sIV | 224 | * sCW -> sIV |
225 | * sLA -> sIV | 225 | * sLA -> sIV |
226 | * sTW -> sIV Reopened connection, but server may not do it. | 226 | * sTW -> sSS Reopened connection, but server may have switched role |
227 | * sCL -> sIV | 227 | * sCL -> sIV |
228 | */ | 228 | */ |
229 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 229 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 65eb2a1160d5..11ab4b078f3b 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -1328,10 +1328,10 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
1328 | basechain->stats = stats; | 1328 | basechain->stats = stats; |
1329 | } else { | 1329 | } else { |
1330 | stats = netdev_alloc_pcpu_stats(struct nft_stats); | 1330 | stats = netdev_alloc_pcpu_stats(struct nft_stats); |
1331 | if (IS_ERR(stats)) { | 1331 | if (stats == NULL) { |
1332 | module_put(type->owner); | 1332 | module_put(type->owner); |
1333 | kfree(basechain); | 1333 | kfree(basechain); |
1334 | return PTR_ERR(stats); | 1334 | return -ENOMEM; |
1335 | } | 1335 | } |
1336 | rcu_assign_pointer(basechain->stats, stats); | 1336 | rcu_assign_pointer(basechain->stats, stats); |
1337 | } | 1337 | } |
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index b1e3a0579416..5f1be5ba3559 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
@@ -43,7 +43,8 @@ | |||
43 | #define NFULNL_NLBUFSIZ_DEFAULT NLMSG_GOODSIZE | 43 | #define NFULNL_NLBUFSIZ_DEFAULT NLMSG_GOODSIZE |
44 | #define NFULNL_TIMEOUT_DEFAULT 100 /* every second */ | 44 | #define NFULNL_TIMEOUT_DEFAULT 100 /* every second */ |
45 | #define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */ | 45 | #define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */ |
46 | #define NFULNL_COPY_RANGE_MAX 0xFFFF /* max packet size is limited by 16-bit struct nfattr nfa_len field */ | 46 | /* max packet size is limited by 16-bit struct nfattr nfa_len field */ |
47 | #define NFULNL_COPY_RANGE_MAX (0xFFFF - NLA_HDRLEN) | ||
47 | 48 | ||
48 | #define PRINTR(x, args...) do { if (net_ratelimit()) \ | 49 | #define PRINTR(x, args...) do { if (net_ratelimit()) \ |
49 | printk(x, ## args); } while (0); | 50 | printk(x, ## args); } while (0); |
@@ -252,6 +253,8 @@ nfulnl_set_mode(struct nfulnl_instance *inst, u_int8_t mode, | |||
252 | 253 | ||
253 | case NFULNL_COPY_PACKET: | 254 | case NFULNL_COPY_PACKET: |
254 | inst->copy_mode = mode; | 255 | inst->copy_mode = mode; |
256 | if (range == 0) | ||
257 | range = NFULNL_COPY_RANGE_MAX; | ||
255 | inst->copy_range = min_t(unsigned int, | 258 | inst->copy_range = min_t(unsigned int, |
256 | range, NFULNL_COPY_RANGE_MAX); | 259 | range, NFULNL_COPY_RANGE_MAX); |
257 | break; | 260 | break; |
@@ -343,26 +346,25 @@ nfulnl_alloc_skb(struct net *net, u32 peer_portid, unsigned int inst_size, | |||
343 | return skb; | 346 | return skb; |
344 | } | 347 | } |
345 | 348 | ||
346 | static int | 349 | static void |
347 | __nfulnl_send(struct nfulnl_instance *inst) | 350 | __nfulnl_send(struct nfulnl_instance *inst) |
348 | { | 351 | { |
349 | int status = -1; | ||
350 | |||
351 | if (inst->qlen > 1) { | 352 | if (inst->qlen > 1) { |
352 | struct nlmsghdr *nlh = nlmsg_put(inst->skb, 0, 0, | 353 | struct nlmsghdr *nlh = nlmsg_put(inst->skb, 0, 0, |
353 | NLMSG_DONE, | 354 | NLMSG_DONE, |
354 | sizeof(struct nfgenmsg), | 355 | sizeof(struct nfgenmsg), |
355 | 0); | 356 | 0); |
356 | if (!nlh) | 357 | if (WARN_ONCE(!nlh, "bad nlskb size: %u, tailroom %d\n", |
358 | inst->skb->len, skb_tailroom(inst->skb))) { | ||
359 | kfree_skb(inst->skb); | ||
357 | goto out; | 360 | goto out; |
361 | } | ||
358 | } | 362 | } |
359 | status = nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid, | 363 | nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid, |
360 | MSG_DONTWAIT); | 364 | MSG_DONTWAIT); |
361 | 365 | out: | |
362 | inst->qlen = 0; | 366 | inst->qlen = 0; |
363 | inst->skb = NULL; | 367 | inst->skb = NULL; |
364 | out: | ||
365 | return status; | ||
366 | } | 368 | } |
367 | 369 | ||
368 | static void | 370 | static void |
@@ -649,7 +651,8 @@ nfulnl_log_packet(struct net *net, | |||
649 | + nla_total_size(sizeof(u_int32_t)) /* gid */ | 651 | + nla_total_size(sizeof(u_int32_t)) /* gid */ |
650 | + nla_total_size(plen) /* prefix */ | 652 | + nla_total_size(plen) /* prefix */ |
651 | + nla_total_size(sizeof(struct nfulnl_msg_packet_hw)) | 653 | + nla_total_size(sizeof(struct nfulnl_msg_packet_hw)) |
652 | + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp)); | 654 | + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp)) |
655 | + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */ | ||
653 | 656 | ||
654 | if (in && skb_mac_header_was_set(skb)) { | 657 | if (in && skb_mac_header_was_set(skb)) { |
655 | size += nla_total_size(skb->dev->hard_header_len) | 658 | size += nla_total_size(skb->dev->hard_header_len) |
@@ -678,8 +681,7 @@ nfulnl_log_packet(struct net *net, | |||
678 | break; | 681 | break; |
679 | 682 | ||
680 | case NFULNL_COPY_PACKET: | 683 | case NFULNL_COPY_PACKET: |
681 | if (inst->copy_range == 0 | 684 | if (inst->copy_range > skb->len) |
682 | || inst->copy_range > skb->len) | ||
683 | data_len = skb->len; | 685 | data_len = skb->len; |
684 | else | 686 | else |
685 | data_len = inst->copy_range; | 687 | data_len = inst->copy_range; |
@@ -692,8 +694,7 @@ nfulnl_log_packet(struct net *net, | |||
692 | goto unlock_and_release; | 694 | goto unlock_and_release; |
693 | } | 695 | } |
694 | 696 | ||
695 | if (inst->skb && | 697 | if (inst->skb && size > skb_tailroom(inst->skb)) { |
696 | size > skb_tailroom(inst->skb) - sizeof(struct nfgenmsg)) { | ||
697 | /* either the queue len is too high or we don't have | 698 | /* either the queue len is too high or we don't have |
698 | * enough room in the skb left. flush to userspace. */ | 699 | * enough room in the skb left. flush to userspace. */ |
699 | __nfulnl_flush(inst); | 700 | __nfulnl_flush(inst); |
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 0480f57a4eb6..9d6d6f60a80f 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c | |||
@@ -672,7 +672,7 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
672 | family = ctx->afi->family; | 672 | family = ctx->afi->family; |
673 | 673 | ||
674 | /* Re-use the existing target if it's already loaded. */ | 674 | /* Re-use the existing target if it's already loaded. */ |
675 | list_for_each_entry(nft_target, &nft_match_list, head) { | 675 | list_for_each_entry(nft_target, &nft_target_list, head) { |
676 | struct xt_target *target = nft_target->ops.data; | 676 | struct xt_target *target = nft_target->ops.data; |
677 | 677 | ||
678 | if (strcmp(target->name, tg_name) == 0 && | 678 | if (strcmp(target->name, tg_name) == 0 && |