Commit 40451fd0 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following patchset contains Netfilter updates for net-next.
Basically, more incremental updates for br_netfilter from Florian
Westphal, small nf_tables updates (including one fix for rb-tree
locking) and small two-liner to add extra validation for the REJECT6
target.

More specifically, they are:

1) Use the conntrack status flags from br_netfilter to know that DNAT is
   happening. Patch for Florian Westphal.

2) nf_bridge->physoutdev == NULL already indicates that the traffic is
   bridged, so let's get rid of the BRNF_BRIDGED flag. Also from Florian.

3) Another patch to prepare voidization of seq_printf/seq_puts/seq_putc,
   from Joe Perches.

4) Consolidation of nf_tables_newtable() error path.

5) Kill nf_bridge_pad used by br_netfilter from ip_fragment(),
   from Florian Westphal.

6) Access rb-tree root node inside the lock and remove unnecessary
   locking from the get path (we already hold nfnl_lock there), from
   Patrick McHardy.

7) You cannot use a NFT_SET_ELEM_INTERVAL_END when the set doesn't
   support interval, also from Patrick.

8) Enforce IP6T_F_PROTO from ip6t_REJECT to make sure the core is
   actually restricting matches to TCP.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 682f048b e35158e4
...@@ -19,23 +19,10 @@ enum nf_br_hook_priorities { ...@@ -19,23 +19,10 @@ enum nf_br_hook_priorities {
#define BRNF_PKT_TYPE 0x01 #define BRNF_PKT_TYPE 0x01
#define BRNF_BRIDGED_DNAT 0x02 #define BRNF_BRIDGED_DNAT 0x02
#define BRNF_BRIDGED 0x04
#define BRNF_NF_BRIDGE_PREROUTING 0x08 #define BRNF_NF_BRIDGE_PREROUTING 0x08
#define BRNF_8021Q 0x10 #define BRNF_8021Q 0x10
#define BRNF_PPPoE 0x20 #define BRNF_PPPoE 0x20
static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb)
{
switch (skb->protocol) {
case __cpu_to_be16(ETH_P_8021Q):
return VLAN_HLEN;
case __cpu_to_be16(ETH_P_PPP_SES):
return PPPOE_SES_HLEN;
default:
return 0;
}
}
static inline unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb) static inline unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb)
{ {
if (unlikely(skb->nf_bridge->mask & BRNF_PPPoE)) if (unlikely(skb->nf_bridge->mask & BRNF_PPPoE))
...@@ -45,21 +32,6 @@ static inline unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb) ...@@ -45,21 +32,6 @@ static inline unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb)
int br_handle_frame_finish(struct sk_buff *skb); int br_handle_frame_finish(struct sk_buff *skb);
/* This is called by the IP fragmenting code and it ensures there is
* enough room for the encapsulating header (if there is one). */
static inline unsigned int nf_bridge_pad(const struct sk_buff *skb)
{
if (skb->nf_bridge)
return nf_bridge_encap_header_len(skb);
return 0;
}
struct bridge_skb_cb {
union {
__be32 ipv4;
} daddr;
};
static inline void br_drop_fake_rtable(struct sk_buff *skb) static inline void br_drop_fake_rtable(struct sk_buff *skb)
{ {
struct dst_entry *dst = skb_dst(skb); struct dst_entry *dst = skb_dst(skb);
...@@ -69,7 +41,6 @@ static inline void br_drop_fake_rtable(struct sk_buff *skb) ...@@ -69,7 +41,6 @@ static inline void br_drop_fake_rtable(struct sk_buff *skb)
} }
#else #else
#define nf_bridge_pad(skb) (0)
#define br_drop_fake_rtable(skb) do { } while (0) #define br_drop_fake_rtable(skb) do { } while (0)
#endif /* CONFIG_BRIDGE_NETFILTER */ #endif /* CONFIG_BRIDGE_NETFILTER */
......
...@@ -37,17 +37,16 @@ ...@@ -37,17 +37,16 @@
#include <net/route.h> #include <net/route.h>
#include <net/netfilter/br_netfilter.h> #include <net/netfilter/br_netfilter.h>
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
#include <net/netfilter/nf_conntrack.h>
#endif
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "br_private.h" #include "br_private.h"
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
#include <linux/sysctl.h> #include <linux/sysctl.h>
#endif #endif
#define skb_origaddr(skb) (((struct bridge_skb_cb *) \
(skb->nf_bridge->data))->daddr.ipv4)
#define store_orig_dstaddr(skb) (skb_origaddr(skb) = ip_hdr(skb)->daddr)
#define dnat_took_place(skb) (skb_origaddr(skb) != ip_hdr(skb)->daddr)
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static struct ctl_table_header *brnf_sysctl_header; static struct ctl_table_header *brnf_sysctl_header;
static int brnf_call_iptables __read_mostly = 1; static int brnf_call_iptables __read_mostly = 1;
...@@ -154,6 +153,18 @@ static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb) ...@@ -154,6 +153,18 @@ static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb)
return nf_bridge; return nf_bridge;
} }
static unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb)
{
switch (skb->protocol) {
case __cpu_to_be16(ETH_P_8021Q):
return VLAN_HLEN;
case __cpu_to_be16(ETH_P_PPP_SES):
return PPPOE_SES_HLEN;
default:
return 0;
}
}
static inline void nf_bridge_push_encap_header(struct sk_buff *skb) static inline void nf_bridge_push_encap_header(struct sk_buff *skb)
{ {
unsigned int len = nf_bridge_encap_header_len(skb); unsigned int len = nf_bridge_encap_header_len(skb);
...@@ -322,6 +333,22 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) ...@@ -322,6 +333,22 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
return 0; return 0;
} }
static bool dnat_took_place(const struct sk_buff *skb)
{
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
enum ip_conntrack_info ctinfo;
struct nf_conn *ct;
ct = nf_ct_get(skb, &ctinfo);
if (!ct || nf_ct_is_untracked(ct))
return false;
return test_bit(IPS_DST_NAT_BIT, &ct->status);
#else
return false;
#endif
}
/* This requires some explaining. If DNAT has taken place, /* This requires some explaining. If DNAT has taken place,
* we will need to fix up the destination Ethernet address. * we will need to fix up the destination Ethernet address.
* *
...@@ -625,7 +652,7 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops, ...@@ -625,7 +652,7 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops,
return NF_DROP; return NF_DROP;
if (!setup_pre_routing(skb)) if (!setup_pre_routing(skb))
return NF_DROP; return NF_DROP;
store_orig_dstaddr(skb);
skb->protocol = htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
...@@ -721,8 +748,6 @@ static unsigned int br_nf_forward_ip(const struct nf_hook_ops *ops, ...@@ -721,8 +748,6 @@ static unsigned int br_nf_forward_ip(const struct nf_hook_ops *ops,
if (pf == NFPROTO_IPV4 && br_parse_ip_options(skb)) if (pf == NFPROTO_IPV4 && br_parse_ip_options(skb))
return NF_DROP; return NF_DROP;
/* The physdev module checks on this */
nf_bridge->mask |= BRNF_BRIDGED;
nf_bridge->physoutdev = skb->dev; nf_bridge->physoutdev = skb->dev;
if (pf == NFPROTO_IPV4) if (pf == NFPROTO_IPV4)
skb->protocol = htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
...@@ -842,7 +867,12 @@ static unsigned int br_nf_post_routing(const struct nf_hook_ops *ops, ...@@ -842,7 +867,12 @@ static unsigned int br_nf_post_routing(const struct nf_hook_ops *ops,
struct net_device *realoutdev = bridge_parent(skb->dev); struct net_device *realoutdev = bridge_parent(skb->dev);
u_int8_t pf; u_int8_t pf;
if (!nf_bridge || !(nf_bridge->mask & BRNF_BRIDGED)) /* if nf_bridge is set, but ->physoutdev is NULL, this packet came in
* on a bridge, but was delivered locally and is now being routed:
*
* POST_ROUTING was already invoked from the ip stack.
*/
if (!nf_bridge || !nf_bridge->physoutdev)
return NF_ACCEPT; return NF_ACCEPT;
if (!realoutdev) if (!realoutdev)
......
...@@ -636,10 +636,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) ...@@ -636,10 +636,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
left = skb->len - hlen; /* Space per frame */ left = skb->len - hlen; /* Space per frame */
ptr = hlen; /* Where to start from */ ptr = hlen; /* Where to start from */
/* for bridged IP traffic encapsulated inside f.e. a vlan header, ll_rs = LL_RESERVED_SPACE(rt->dst.dev);
* we need to make room for the encapsulating header
*/
ll_rs = LL_RESERVED_SPACE_EXTRA(rt->dst.dev, nf_bridge_pad(skb));
/* /*
* Fragment the datagram. * Fragment the datagram.
......
...@@ -300,7 +300,9 @@ static int exp_seq_show(struct seq_file *s, void *v) ...@@ -300,7 +300,9 @@ static int exp_seq_show(struct seq_file *s, void *v)
__nf_ct_l3proto_find(exp->tuple.src.l3num), __nf_ct_l3proto_find(exp->tuple.src.l3num),
__nf_ct_l4proto_find(exp->tuple.src.l3num, __nf_ct_l4proto_find(exp->tuple.src.l3num,
exp->tuple.dst.protonum)); exp->tuple.dst.protonum));
return seq_putc(s, '\n'); seq_putc(s, '\n');
return 0;
} }
static const struct seq_operations exp_seq_ops = { static const struct seq_operations exp_seq_ops = {
......
...@@ -83,7 +83,8 @@ static int reject_tg6_check(const struct xt_tgchk_param *par) ...@@ -83,7 +83,8 @@ static int reject_tg6_check(const struct xt_tgchk_param *par)
return -EINVAL; return -EINVAL;
} else if (rejinfo->with == IP6T_TCP_RESET) { } else if (rejinfo->with == IP6T_TCP_RESET) {
/* Must specify that it's a TCP packet */ /* Must specify that it's a TCP packet */
if (e->ipv6.proto != IPPROTO_TCP || if (!(e->ipv6.flags & IP6T_F_PROTO) ||
e->ipv6.proto != IPPROTO_TCP ||
(e->ipv6.invflags & XT_INV_PROTO)) { (e->ipv6.invflags & XT_INV_PROTO)) {
pr_info("TCP_RESET illegal for non-tcp\n"); pr_info("TCP_RESET illegal for non-tcp\n");
return -EINVAL; return -EINVAL;
......
...@@ -47,9 +47,11 @@ seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir) ...@@ -47,9 +47,11 @@ seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir)
return 0; return 0;
counter = acct->counter; counter = acct->counter;
return seq_printf(s, "packets=%llu bytes=%llu ", seq_printf(s, "packets=%llu bytes=%llu ",
(unsigned long long)atomic64_read(&counter[dir].packets), (unsigned long long)atomic64_read(&counter[dir].packets),
(unsigned long long)atomic64_read(&counter[dir].bytes)); (unsigned long long)atomic64_read(&counter[dir].bytes));
return 0;
}; };
EXPORT_SYMBOL_GPL(seq_print_acct); EXPORT_SYMBOL_GPL(seq_print_acct);
......
...@@ -561,7 +561,9 @@ static int exp_seq_show(struct seq_file *s, void *v) ...@@ -561,7 +561,9 @@ static int exp_seq_show(struct seq_file *s, void *v)
helper->expect_policy[expect->class].name); helper->expect_policy[expect->class].name);
} }
return seq_putc(s, '\n'); seq_putc(s, '\n');
return 0;
} }
static const struct seq_operations exp_seq_ops = { static const struct seq_operations exp_seq_ops = {
......
...@@ -687,11 +687,10 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, ...@@ -687,11 +687,10 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
if (!try_module_get(afi->owner)) if (!try_module_get(afi->owner))
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
err = -ENOMEM;
table = kzalloc(sizeof(*table), GFP_KERNEL); table = kzalloc(sizeof(*table), GFP_KERNEL);
if (table == NULL) { if (table == NULL)
module_put(afi->owner); goto err1;
return -ENOMEM;
}
nla_strlcpy(table->name, name, NFT_TABLE_MAXNAMELEN); nla_strlcpy(table->name, name, NFT_TABLE_MAXNAMELEN);
INIT_LIST_HEAD(&table->chains); INIT_LIST_HEAD(&table->chains);
...@@ -700,13 +699,16 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, ...@@ -700,13 +699,16 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla); nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE); err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
if (err < 0) { if (err < 0)
kfree(table); goto err2;
module_put(afi->owner);
return err;
}
list_add_tail_rcu(&table->list, &afi->tables); list_add_tail_rcu(&table->list, &afi->tables);
return 0; return 0;
err2:
kfree(table);
err1:
module_put(afi->owner);
return err;
} }
static int nft_flush_table(struct nft_ctx *ctx) static int nft_flush_table(struct nft_ctx *ctx)
...@@ -3136,6 +3138,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -3136,6 +3138,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS])); elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS]));
if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END) if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END)
return -EINVAL; return -EINVAL;
if (!(set->flags & NFT_SET_INTERVAL) &&
elem.flags & NFT_SET_ELEM_INTERVAL_END)
return -EINVAL;
} }
if (set->flags & NFT_SET_MAP) { if (set->flags & NFT_SET_MAP) {
......
...@@ -998,11 +998,13 @@ static int seq_show(struct seq_file *s, void *v) ...@@ -998,11 +998,13 @@ static int seq_show(struct seq_file *s, void *v)
{ {
const struct nfulnl_instance *inst = v; const struct nfulnl_instance *inst = v;
return seq_printf(s, "%5d %6d %5d %1d %5d %6d %2d\n", seq_printf(s, "%5d %6d %5d %1d %5d %6d %2d\n",
inst->group_num, inst->group_num,
inst->peer_portid, inst->qlen, inst->peer_portid, inst->qlen,
inst->copy_mode, inst->copy_range, inst->copy_mode, inst->copy_range,
inst->flushtimeout, atomic_read(&inst->use)); inst->flushtimeout, atomic_read(&inst->use));
return 0;
} }
static const struct seq_operations nful_seq_ops = { static const struct seq_operations nful_seq_ops = {
......
...@@ -37,10 +37,11 @@ static bool nft_rbtree_lookup(const struct nft_set *set, ...@@ -37,10 +37,11 @@ static bool nft_rbtree_lookup(const struct nft_set *set,
{ {
const struct nft_rbtree *priv = nft_set_priv(set); const struct nft_rbtree *priv = nft_set_priv(set);
const struct nft_rbtree_elem *rbe, *interval = NULL; const struct nft_rbtree_elem *rbe, *interval = NULL;
const struct rb_node *parent = priv->root.rb_node; const struct rb_node *parent;
int d; int d;
spin_lock_bh(&nft_rbtree_lock); spin_lock_bh(&nft_rbtree_lock);
parent = priv->root.rb_node;
while (parent != NULL) { while (parent != NULL) {
rbe = rb_entry(parent, struct nft_rbtree_elem, node); rbe = rb_entry(parent, struct nft_rbtree_elem, node);
...@@ -158,7 +159,6 @@ static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem) ...@@ -158,7 +159,6 @@ static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem)
struct nft_rbtree_elem *rbe; struct nft_rbtree_elem *rbe;
int d; int d;
spin_lock_bh(&nft_rbtree_lock);
while (parent != NULL) { while (parent != NULL) {
rbe = rb_entry(parent, struct nft_rbtree_elem, node); rbe = rb_entry(parent, struct nft_rbtree_elem, node);
...@@ -173,11 +173,9 @@ static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem) ...@@ -173,11 +173,9 @@ static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem)
!(rbe->flags & NFT_SET_ELEM_INTERVAL_END)) !(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
nft_data_copy(&elem->data, rbe->data); nft_data_copy(&elem->data, rbe->data);
elem->flags = rbe->flags; elem->flags = rbe->flags;
spin_unlock_bh(&nft_rbtree_lock);
return 0; return 0;
} }
} }
spin_unlock_bh(&nft_rbtree_lock);
return -ENOENT; return -ENOENT;
} }
......
...@@ -56,8 +56,7 @@ physdev_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -56,8 +56,7 @@ physdev_mt(const struct sk_buff *skb, struct xt_action_param *par)
/* This only makes sense in the FORWARD and POSTROUTING chains */ /* This only makes sense in the FORWARD and POSTROUTING chains */
if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) && if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
(!!(nf_bridge->mask & BRNF_BRIDGED) ^ (!!nf_bridge->physoutdev ^ !(info->invert & XT_PHYSDEV_OP_BRIDGED)))
!(info->invert & XT_PHYSDEV_OP_BRIDGED)))
return false; return false;
if ((info->bitmask & XT_PHYSDEV_OP_ISIN && if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment