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>
This commit is contained in:
David S. Miller 2014-10-27 18:47:40 -04:00
commit 5d26b1f50a
6 changed files with 27 additions and 40 deletions

View file

@ -192,7 +192,6 @@ static inline void nf_bridge_save_header(struct sk_buff *skb)
static int br_parse_ip_options(struct sk_buff *skb) static int br_parse_ip_options(struct sk_buff *skb)
{ {
struct ip_options *opt;
const struct iphdr *iph; const struct iphdr *iph;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
u32 len; u32 len;
@ -201,7 +200,6 @@ static int br_parse_ip_options(struct sk_buff *skb)
goto inhdr_error; goto inhdr_error;
iph = ip_hdr(skb); iph = ip_hdr(skb);
opt = &(IPCB(skb)->opt);
/* Basic sanity checks */ /* Basic sanity checks */
if (iph->ihl < 5 || iph->version != 4) if (iph->ihl < 5 || iph->version != 4)
@ -227,23 +225,11 @@ static int br_parse_ip_options(struct sk_buff *skb)
} }
memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
if (iph->ihl == 5) /* We should really parse IP options here but until
return 0; * somebody who actually uses IP options complains to
* us we'll just silently ignore the options because
opt->optlen = iph->ihl*4 - sizeof(struct iphdr); * we're lazy!
if (ip_options_compile(dev_net(dev), opt, skb)) */
goto inhdr_error;
/* Check correct handling of SRR option */
if (unlikely(opt->srr)) {
struct in_device *in_dev = __in_dev_get_rcu(dev);
if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev))
goto drop;
if (ip_options_rcv_srr(skb))
goto drop;
}
return 0; return 0;
inhdr_error: inhdr_error:

View file

@ -659,7 +659,7 @@ ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index)
struct ip_set *set; struct ip_set *set;
struct ip_set_net *inst = ip_set_pernet(net); struct ip_set_net *inst = ip_set_pernet(net);
if (index > inst->ip_set_max) if (index >= inst->ip_set_max)
return IPSET_INVALID_ID; return IPSET_INVALID_ID;
nfnl_lock(NFNL_SUBSYS_IPSET); nfnl_lock(NFNL_SUBSYS_IPSET);

View file

@ -213,7 +213,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
{ {
/* REPLY */ /* REPLY */
/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */
/*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sS2 }, /*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sSS, sIV, sS2 },
/* /*
* sNO -> sIV Never reached. * sNO -> sIV Never reached.
* sSS -> sS2 Simultaneous open * sSS -> sS2 Simultaneous open
@ -223,7 +223,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
* sFW -> sIV * sFW -> sIV
* sCW -> sIV * sCW -> sIV
* sLA -> sIV * sLA -> sIV
* sTW -> sIV Reopened connection, but server may not do it. * sTW -> sSS Reopened connection, but server may have switched role
* sCL -> sIV * sCL -> sIV
*/ */
/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */

View file

@ -1328,10 +1328,10 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
basechain->stats = stats; basechain->stats = stats;
} else { } else {
stats = netdev_alloc_pcpu_stats(struct nft_stats); stats = netdev_alloc_pcpu_stats(struct nft_stats);
if (IS_ERR(stats)) { if (stats == NULL) {
module_put(type->owner); module_put(type->owner);
kfree(basechain); kfree(basechain);
return PTR_ERR(stats); return -ENOMEM;
} }
rcu_assign_pointer(basechain->stats, stats); rcu_assign_pointer(basechain->stats, stats);
} }

View file

@ -43,7 +43,8 @@
#define NFULNL_NLBUFSIZ_DEFAULT NLMSG_GOODSIZE #define NFULNL_NLBUFSIZ_DEFAULT NLMSG_GOODSIZE
#define NFULNL_TIMEOUT_DEFAULT 100 /* every second */ #define NFULNL_TIMEOUT_DEFAULT 100 /* every second */
#define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */ #define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */
#define NFULNL_COPY_RANGE_MAX 0xFFFF /* max packet size is limited by 16-bit struct nfattr nfa_len field */ /* max packet size is limited by 16-bit struct nfattr nfa_len field */
#define NFULNL_COPY_RANGE_MAX (0xFFFF - NLA_HDRLEN)
#define PRINTR(x, args...) do { if (net_ratelimit()) \ #define PRINTR(x, args...) do { if (net_ratelimit()) \
printk(x, ## args); } while (0); printk(x, ## args); } while (0);
@ -252,6 +253,8 @@ nfulnl_set_mode(struct nfulnl_instance *inst, u_int8_t mode,
case NFULNL_COPY_PACKET: case NFULNL_COPY_PACKET:
inst->copy_mode = mode; inst->copy_mode = mode;
if (range == 0)
range = NFULNL_COPY_RANGE_MAX;
inst->copy_range = min_t(unsigned int, inst->copy_range = min_t(unsigned int,
range, NFULNL_COPY_RANGE_MAX); range, NFULNL_COPY_RANGE_MAX);
break; break;
@ -343,26 +346,25 @@ nfulnl_alloc_skb(struct net *net, u32 peer_portid, unsigned int inst_size,
return skb; return skb;
} }
static int static void
__nfulnl_send(struct nfulnl_instance *inst) __nfulnl_send(struct nfulnl_instance *inst)
{ {
int status = -1;
if (inst->qlen > 1) { if (inst->qlen > 1) {
struct nlmsghdr *nlh = nlmsg_put(inst->skb, 0, 0, struct nlmsghdr *nlh = nlmsg_put(inst->skb, 0, 0,
NLMSG_DONE, NLMSG_DONE,
sizeof(struct nfgenmsg), sizeof(struct nfgenmsg),
0); 0);
if (!nlh) if (WARN_ONCE(!nlh, "bad nlskb size: %u, tailroom %d\n",
inst->skb->len, skb_tailroom(inst->skb))) {
kfree_skb(inst->skb);
goto out; goto out;
}
} }
status = nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid, nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid,
MSG_DONTWAIT); MSG_DONTWAIT);
out:
inst->qlen = 0; inst->qlen = 0;
inst->skb = NULL; inst->skb = NULL;
out:
return status;
} }
static void static void
@ -649,7 +651,8 @@ nfulnl_log_packet(struct net *net,
+ nla_total_size(sizeof(u_int32_t)) /* gid */ + nla_total_size(sizeof(u_int32_t)) /* gid */
+ nla_total_size(plen) /* prefix */ + nla_total_size(plen) /* prefix */
+ nla_total_size(sizeof(struct nfulnl_msg_packet_hw)) + nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
+ nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp)); + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp))
+ nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
if (in && skb_mac_header_was_set(skb)) { if (in && skb_mac_header_was_set(skb)) {
size += nla_total_size(skb->dev->hard_header_len) size += nla_total_size(skb->dev->hard_header_len)
@ -678,8 +681,7 @@ nfulnl_log_packet(struct net *net,
break; break;
case NFULNL_COPY_PACKET: case NFULNL_COPY_PACKET:
if (inst->copy_range == 0 if (inst->copy_range > skb->len)
|| inst->copy_range > skb->len)
data_len = skb->len; data_len = skb->len;
else else
data_len = inst->copy_range; data_len = inst->copy_range;
@ -692,8 +694,7 @@ nfulnl_log_packet(struct net *net,
goto unlock_and_release; goto unlock_and_release;
} }
if (inst->skb && if (inst->skb && size > skb_tailroom(inst->skb)) {
size > skb_tailroom(inst->skb) - sizeof(struct nfgenmsg)) {
/* either the queue len is too high or we don't have /* either the queue len is too high or we don't have
* enough room in the skb left. flush to userspace. */ * enough room in the skb left. flush to userspace. */
__nfulnl_flush(inst); __nfulnl_flush(inst);

View file

@ -672,7 +672,7 @@ nft_target_select_ops(const struct nft_ctx *ctx,
family = ctx->afi->family; family = ctx->afi->family;
/* Re-use the existing target if it's already loaded. */ /* Re-use the existing target if it's already loaded. */
list_for_each_entry(nft_target, &nft_match_list, head) { list_for_each_entry(nft_target, &nft_target_list, head) {
struct xt_target *target = nft_target->ops.data; struct xt_target *target = nft_target->ops.data;
if (strcmp(target->name, tg_name) == 0 && if (strcmp(target->name, tg_name) == 0 &&