* [PATCH 1/7] netfilter: nf_tables: meter: pick a set backend that supports updates
2018-03-24 20:34 [PATCH 0/7] Netfilter fixes for net Pablo Neira Ayuso
@ 2018-03-24 20:34 ` Pablo Neira Ayuso
2018-03-24 20:34 ` [PATCH 2/7] netfilter: nf_tables: permit second nat hook if colliding hook is going away Pablo Neira Ayuso
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2018-03-24 20:34 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
From: Florian Westphal <fw@strlen.de>
in nftables, 'meter' can be used to instantiate a hash-table at run
time:
rule add filter forward iif "internal" meter hostacct { ip saddr counter}
nft list meter ip filter hostacct
table ip filter {
meter hostacct {
type ipv4_addr
elements = { 192.168.0.1 : counter packets 8 bytes 2672, ..
because elemets get added on the fly, the kernel must chose a set
backend type that implements the ->update() function, otherwise
rule insertion fails with EOPNOTSUPP.
Therefore, skip set types that lack ->update, and also
make sure we do not discard a (bad) candidate when we did yet
find any candidate at all. This could happen when userspace prefers
low memory footprint -- the set implementation currently checked might
not be a fit at all. Make sure we pick it anyway (!bops). In
case next candidate is a better fix, it will be chosen instead.
But in case nothing else is found we at least have a non-ideal
match rather than no match at all.
Fixes: 6c03ae210ce3 ("netfilter: nft_set_hash: add non-resizable hashtable implementation")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_tables_api.c | 5 ++++-
net/netfilter/nft_set_hash.c | 2 +-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index c4acc7340eb1..36f69acaf51f 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -2446,6 +2446,9 @@ EXPORT_SYMBOL_GPL(nft_unregister_set);
static bool nft_set_ops_candidate(const struct nft_set_ops *ops, u32 flags)
{
+ if ((flags & NFT_SET_EVAL) && !ops->update)
+ return false;
+
return (flags & ops->features) == (flags & NFT_SET_FEATURES);
}
@@ -2510,7 +2513,7 @@ nft_select_set_ops(const struct nft_ctx *ctx,
if (est.space == best.space &&
est.lookup < best.lookup)
break;
- } else if (est.size < best.size) {
+ } else if (est.size < best.size || !bops) {
break;
}
continue;
diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
index d40591fe1b2f..fc9c6d5d64cd 100644
--- a/net/netfilter/nft_set_hash.c
+++ b/net/netfilter/nft_set_hash.c
@@ -674,7 +674,7 @@ static const struct nft_set_ops *
nft_hash_select_ops(const struct nft_ctx *ctx, const struct nft_set_desc *desc,
u32 flags)
{
- if (desc->size && !(flags & NFT_SET_TIMEOUT)) {
+ if (desc->size && !(flags & (NFT_SET_EVAL | NFT_SET_TIMEOUT))) {
switch (desc->klen) {
case 4:
return &nft_hash_fast_ops;
--
2.11.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/7] netfilter: nf_tables: permit second nat hook if colliding hook is going away
2018-03-24 20:34 [PATCH 0/7] Netfilter fixes for net Pablo Neira Ayuso
2018-03-24 20:34 ` [PATCH 1/7] netfilter: nf_tables: meter: pick a set backend that supports updates Pablo Neira Ayuso
@ 2018-03-24 20:34 ` Pablo Neira Ayuso
2018-03-24 20:34 ` [PATCH 3/7] netfilter: nf_tables: add missing netlink attrs to policies Pablo Neira Ayuso
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2018-03-24 20:34 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
From: Florian Westphal <fw@strlen.de>
Sergei Trofimovich reported that restoring an nft ruleset doesn't work
anymore unless old rule content is flushed first.
The problem stems from a recent change designed to prevent multiple nat
hooks at the same hook point locations and nftables transaction model.
A 'flush ruleset' won't take effect until the entire transaction has
completed.
So, if one has a nft.rules file that contains a 'flush ruleset',
followed by a nat hook register request, then 'nft -f file' will work,
but running 'nft -f file' again will fail with -EBUSY.
Reason is that nftables will place the flush/removal requests in the
transaction list, but it will not act on the removal until after all new
rules are in place.
The netfilter core will therefore get request to register a new nat
hook before the old one is removed -- this now fails as the netfilter
core can't know the existing hook is staged for removal.
To fix this, we can search the transaction log when a hook collision
is detected. The collision is okay if
1. there is a delete request pending for the nat hook that is already
registered.
2. there is no second add request for a matching nat hook.
This is required to only apply the exception once.
Fixes: f92b40a8b2645 ("netfilter: core: only allow one nat hook per hook point")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_tables_api.c | 64 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 36f69acaf51f..cc8ca00e6e6e 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -74,15 +74,77 @@ static void nft_trans_destroy(struct nft_trans *trans)
kfree(trans);
}
+/* removal requests are queued in the commit_list, but not acted upon
+ * until after all new rules are in place.
+ *
+ * Therefore, nf_register_net_hook(net, &nat_hook) runs before pending
+ * nf_unregister_net_hook().
+ *
+ * nf_register_net_hook thus fails if a nat hook is already in place
+ * even if the conflicting hook is about to be removed.
+ *
+ * If collision is detected, search commit_log for DELCHAIN matching
+ * the new nat hooknum; if we find one collision is temporary:
+ *
+ * Either transaction is aborted (new/colliding hook is removed), or
+ * transaction is committed (old hook is removed).
+ */
+static bool nf_tables_allow_nat_conflict(const struct net *net,
+ const struct nf_hook_ops *ops)
+{
+ const struct nft_trans *trans;
+ bool ret = false;
+
+ if (!ops->nat_hook)
+ return false;
+
+ list_for_each_entry(trans, &net->nft.commit_list, list) {
+ const struct nf_hook_ops *pending_ops;
+ const struct nft_chain *pending;
+
+ if (trans->msg_type != NFT_MSG_NEWCHAIN &&
+ trans->msg_type != NFT_MSG_DELCHAIN)
+ continue;
+
+ pending = trans->ctx.chain;
+ if (!nft_is_base_chain(pending))
+ continue;
+
+ pending_ops = &nft_base_chain(pending)->ops;
+ if (pending_ops->nat_hook &&
+ pending_ops->pf == ops->pf &&
+ pending_ops->hooknum == ops->hooknum) {
+ /* other hook registration already pending? */
+ if (trans->msg_type == NFT_MSG_NEWCHAIN)
+ return false;
+
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
static int nf_tables_register_hook(struct net *net,
const struct nft_table *table,
struct nft_chain *chain)
{
+ struct nf_hook_ops *ops;
+ int ret;
+
if (table->flags & NFT_TABLE_F_DORMANT ||
!nft_is_base_chain(chain))
return 0;
- return nf_register_net_hook(net, &nft_base_chain(chain)->ops);
+ ops = &nft_base_chain(chain)->ops;
+ ret = nf_register_net_hook(net, ops);
+ if (ret == -EBUSY && nf_tables_allow_nat_conflict(net, ops)) {
+ ops->nat_hook = false;
+ ret = nf_register_net_hook(net, ops);
+ ops->nat_hook = true;
+ }
+
+ return ret;
}
static void nf_tables_unregister_hook(struct net *net,
--
2.11.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/7] netfilter: nf_tables: add missing netlink attrs to policies
2018-03-24 20:34 [PATCH 0/7] Netfilter fixes for net Pablo Neira Ayuso
2018-03-24 20:34 ` [PATCH 1/7] netfilter: nf_tables: meter: pick a set backend that supports updates Pablo Neira Ayuso
2018-03-24 20:34 ` [PATCH 2/7] netfilter: nf_tables: permit second nat hook if colliding hook is going away Pablo Neira Ayuso
@ 2018-03-24 20:34 ` Pablo Neira Ayuso
2018-03-24 20:34 ` [PATCH 4/7] netfilter: drop template ct when conntrack is skipped Pablo Neira Ayuso
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2018-03-24 20:34 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
From: Florian Westphal <fw@strlen.de>
Fixes: 8aeff920dcc9 ("netfilter: nf_tables: add stateful object reference to set elements")
Fixes: f25ad2e907f1 ("netfilter: nf_tables: prepare for expressions associated to set elements")
Fixes: 1a94e38d254b ("netfilter: nf_tables: add NFTA_RULE_ID attribute")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_tables_api.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index cc8ca00e6e6e..14777c404071 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -1973,6 +1973,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
[NFTA_RULE_POSITION] = { .type = NLA_U64 },
[NFTA_RULE_USERDATA] = { .type = NLA_BINARY,
.len = NFT_USERDATA_MAXLEN },
+ [NFTA_RULE_ID] = { .type = NLA_U32 },
};
static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
@@ -3380,6 +3381,8 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
[NFTA_SET_ELEM_TIMEOUT] = { .type = NLA_U64 },
[NFTA_SET_ELEM_USERDATA] = { .type = NLA_BINARY,
.len = NFT_USERDATA_MAXLEN },
+ [NFTA_SET_ELEM_EXPR] = { .type = NLA_NESTED },
+ [NFTA_SET_ELEM_OBJREF] = { .type = NLA_STRING },
};
static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
--
2.11.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/7] netfilter: drop template ct when conntrack is skipped.
2018-03-24 20:34 [PATCH 0/7] Netfilter fixes for net Pablo Neira Ayuso
` (2 preceding siblings ...)
2018-03-24 20:34 ` [PATCH 3/7] netfilter: nf_tables: add missing netlink attrs to policies Pablo Neira Ayuso
@ 2018-03-24 20:34 ` Pablo Neira Ayuso
2018-03-24 20:34 ` [PATCH 5/7] netfilter: nf_tables: cache device name in flowtable object Pablo Neira Ayuso
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2018-03-24 20:34 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
From: Paolo Abeni <pabeni@redhat.com>
The ipv4 nf_ct code currently skips the nf_conntrak_in() call
for fragmented packets. As a results later matches/target can end
up manipulating template ct entry instead of 'real' ones.
Exploiting the above, syzbot found a way to trigger the following
splat:
WARNING: CPU: 1 PID: 4242 at net/netfilter/xt_cluster.c:55
xt_cluster_mt+0x6c1/0x840 net/netfilter/xt_cluster.c:127
Kernel panic - not syncing: panic_on_warn set ...
CPU: 1 PID: 4242 Comm: syzkaller027971 Not tainted 4.16.0-rc2+ #243
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
Google 01/01/2011
Call Trace:
__dump_stack lib/dump_stack.c:17 [inline]
dump_stack+0x194/0x24d lib/dump_stack.c:53
panic+0x1e4/0x41c kernel/panic.c:183
__warn+0x1dc/0x200 kernel/panic.c:547
report_bug+0x211/0x2d0 lib/bug.c:184
fixup_bug.part.11+0x37/0x80 arch/x86/kernel/traps.c:178
fixup_bug arch/x86/kernel/traps.c:247 [inline]
do_error_trap+0x2d7/0x3e0 arch/x86/kernel/traps.c:296
do_invalid_op+0x1b/0x20 arch/x86/kernel/traps.c:315
invalid_op+0x58/0x80 arch/x86/entry/entry_64.S:957
RIP: 0010:xt_cluster_hash net/netfilter/xt_cluster.c:55 [inline]
RIP: 0010:xt_cluster_mt+0x6c1/0x840 net/netfilter/xt_cluster.c:127
RSP: 0018:ffff8801d2f6f2d0 EFLAGS: 00010293
RAX: ffff8801af700540 RBX: 0000000000000000 RCX: ffffffff84a2d1e1
RDX: 0000000000000000 RSI: ffff8801d2f6f478 RDI: ffff8801cafd336a
RBP: ffff8801d2f6f2e8 R08: 0000000000000000 R09: 0000000000000001
R10: 0000000000000000 R11: 0000000000000000 R12: ffff8801b03b3d18
R13: ffff8801cafd3300 R14: dffffc0000000000 R15: ffff8801d2f6f478
ipt_do_table+0xa91/0x19b0 net/ipv4/netfilter/ip_tables.c:296
iptable_filter_hook+0x65/0x80 net/ipv4/netfilter/iptable_filter.c:41
nf_hook_entry_hookfn include/linux/netfilter.h:120 [inline]
nf_hook_slow+0xba/0x1a0 net/netfilter/core.c:483
nf_hook include/linux/netfilter.h:243 [inline]
NF_HOOK include/linux/netfilter.h:286 [inline]
raw_send_hdrinc.isra.17+0xf39/0x1880 net/ipv4/raw.c:432
raw_sendmsg+0x14cd/0x26b0 net/ipv4/raw.c:669
inet_sendmsg+0x11f/0x5e0 net/ipv4/af_inet.c:763
sock_sendmsg_nosec net/socket.c:629 [inline]
sock_sendmsg+0xca/0x110 net/socket.c:639
SYSC_sendto+0x361/0x5c0 net/socket.c:1748
SyS_sendto+0x40/0x50 net/socket.c:1716
do_syscall_64+0x280/0x940 arch/x86/entry/common.c:287
entry_SYSCALL_64_after_hwframe+0x42/0xb7
RIP: 0033:0x441b49
RSP: 002b:00007ffff5ca8b18 EFLAGS: 00000216 ORIG_RAX: 000000000000002c
RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 0000000000441b49
RDX: 0000000000000030 RSI: 0000000020ff7000 RDI: 0000000000000003
RBP: 00000000006cc018 R08: 000000002066354c R09: 0000000000000010
R10: 0000000000000000 R11: 0000000000000216 R12: 0000000000403470
R13: 0000000000403500 R14: 0000000000000000 R15: 0000000000000000
Dumping ftrace buffer:
(ftrace buffer empty)
Kernel Offset: disabled
Rebooting in 86400 seconds..
Instead of adding checks for template ct on every target/match
manipulating skb->_nfct, simply drop the template ct when skipping
nf_conntrack_in().
Fixes: 7b4fdf77a450ec ("netfilter: don't track fragmented packets")
Reported-and-tested-by: syzbot+0346441ae0545cfcea3a@syzkaller.appspotmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Acked-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index b50721d9d30e..9db988f9a4d7 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -154,8 +154,20 @@ static unsigned int ipv4_conntrack_local(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
- if (ip_is_fragment(ip_hdr(skb))) /* IP_NODEFRAG setsockopt set */
+ if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *tmpl;
+
+ tmpl = nf_ct_get(skb, &ctinfo);
+ if (tmpl && nf_ct_is_template(tmpl)) {
+ /* when skipping ct, clear templates to avoid fooling
+ * later targets/matches
+ */
+ skb->_nfct = 0;
+ nf_ct_put(tmpl);
+ }
return NF_ACCEPT;
+ }
return nf_conntrack_in(state->net, PF_INET, state->hook, skb);
}
--
2.11.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/7] netfilter: nf_tables: cache device name in flowtable object
2018-03-24 20:34 [PATCH 0/7] Netfilter fixes for net Pablo Neira Ayuso
` (3 preceding siblings ...)
2018-03-24 20:34 ` [PATCH 4/7] netfilter: drop template ct when conntrack is skipped Pablo Neira Ayuso
@ 2018-03-24 20:34 ` Pablo Neira Ayuso
2018-03-24 20:34 ` [PATCH 6/7] netfilter: nf_tables: do not hold reference on netdevice from preparation phase Pablo Neira Ayuso
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2018-03-24 20:34 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
Devices going away have to grab the nfnl_lock from the netdev event path
to avoid races with control plane updates.
However, netlink dumps in netfilter do not hold nfnl_lock mutex. Cache
the device name into the objects to avoid an use-after-free situation
for a device that is going away.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_tables.h | 4 ++++
net/netfilter/nf_tables_api.c | 15 +++++++++------
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 663b015dace5..30eb0652b025 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1068,6 +1068,8 @@ struct nft_object_ops {
int nft_register_obj(struct nft_object_type *obj_type);
void nft_unregister_obj(struct nft_object_type *obj_type);
+#define NFT_FLOWTABLE_DEVICE_MAX 8
+
/**
* struct nft_flowtable - nf_tables flow table
*
@@ -1080,6 +1082,7 @@ void nft_unregister_obj(struct nft_object_type *obj_type);
* @genmask: generation mask
* @use: number of references to this flow table
* @handle: unique object handle
+ * @dev_name: array of device names
* @data: rhashtable and garbage collector
* @ops: array of hooks
*/
@@ -1093,6 +1096,7 @@ struct nft_flowtable {
u32 genmask:2,
use:30;
u64 handle;
+ char *dev_name[NFT_FLOWTABLE_DEVICE_MAX];
/* runtime data below here */
struct nf_hook_ops *ops ____cacheline_aligned;
struct nf_flowtable data;
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 14777c404071..977d43e00f98 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -4932,8 +4932,6 @@ nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
return ERR_PTR(-ENOENT);
}
-#define NFT_FLOWTABLE_DEVICE_MAX 8
-
static int nf_tables_parse_devices(const struct nft_ctx *ctx,
const struct nlattr *attr,
struct net_device *dev_array[], int *len)
@@ -5006,7 +5004,7 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
err = nf_tables_parse_devices(ctx, tb[NFTA_FLOWTABLE_HOOK_DEVS],
dev_array, &n);
if (err < 0)
- goto err1;
+ return err;
ops = kzalloc(sizeof(struct nf_hook_ops) * n, GFP_KERNEL);
if (!ops) {
@@ -5026,6 +5024,8 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
flowtable->ops[i].priv = &flowtable->data.rhashtable;
flowtable->ops[i].hook = flowtable->data.type->hook;
flowtable->ops[i].dev = dev_array[i];
+ flowtable->dev_name[i] = kstrdup(dev_array[i]->name,
+ GFP_KERNEL);
}
err = 0;
@@ -5203,8 +5203,10 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
err5:
i = flowtable->ops_len;
err4:
- for (k = i - 1; k >= 0; k--)
+ for (k = i - 1; k >= 0; k--) {
+ kfree(flowtable->dev_name[k]);
nf_unregister_net_hook(net, &flowtable->ops[k]);
+ }
kfree(flowtable->ops);
err3:
@@ -5294,9 +5296,9 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
goto nla_put_failure;
for (i = 0; i < flowtable->ops_len; i++) {
- if (flowtable->ops[i].dev &&
+ if (flowtable->dev_name[i][0] &&
nla_put_string(skb, NFTA_DEVICE_NAME,
- flowtable->ops[i].dev->name))
+ flowtable->dev_name[i]))
goto nla_put_failure;
}
nla_nest_end(skb, nest_devs);
@@ -5538,6 +5540,7 @@ static void nft_flowtable_event(unsigned long event, struct net_device *dev,
continue;
nf_unregister_net_hook(dev_net(dev), &flowtable->ops[i]);
+ flowtable->dev_name[i][0] = '\0';
flowtable->ops[i].dev = NULL;
break;
}
--
2.11.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6/7] netfilter: nf_tables: do not hold reference on netdevice from preparation phase
2018-03-24 20:34 [PATCH 0/7] Netfilter fixes for net Pablo Neira Ayuso
` (4 preceding siblings ...)
2018-03-24 20:34 ` [PATCH 5/7] netfilter: nf_tables: cache device name in flowtable object Pablo Neira Ayuso
@ 2018-03-24 20:34 ` Pablo Neira Ayuso
2018-03-24 20:34 ` [PATCH 7/7] netfilter: nf_socket: Fix out of bounds access in nf_sk_lookup_slow_v{4,6} Pablo Neira Ayuso
2018-03-24 21:10 ` [PATCH 0/7] Netfilter fixes for net David Miller
7 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2018-03-24 20:34 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
The netfilter netdevice event handler hold the nfnl_lock mutex, this
avoids races with a device going away while such device is being
attached to hooks from the netlink control plane. Therefore, either
control plane bails out with ENOENT or netdevice event path waits until
the hook that is attached to net_device is registered.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_tables_api.c | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 977d43e00f98..530e12ae52d7 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -1288,8 +1288,6 @@ static void nf_tables_chain_destroy(struct nft_chain *chain)
free_percpu(basechain->stats);
if (basechain->stats)
static_branch_dec(&nft_counters_enabled);
- if (basechain->ops.dev != NULL)
- dev_put(basechain->ops.dev);
kfree(chain->name);
kfree(basechain);
} else {
@@ -1356,7 +1354,7 @@ static int nft_chain_parse_hook(struct net *net,
}
nla_strlcpy(ifname, ha[NFTA_HOOK_DEV], IFNAMSIZ);
- dev = dev_get_by_name(net, ifname);
+ dev = __dev_get_by_name(net, ifname);
if (!dev) {
module_put(type->owner);
return -ENOENT;
@@ -1373,8 +1371,6 @@ static int nft_chain_parse_hook(struct net *net,
static void nft_chain_release_hook(struct nft_chain_hook *hook)
{
module_put(hook->type->owner);
- if (hook->dev != NULL)
- dev_put(hook->dev);
}
static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
@@ -4948,7 +4944,7 @@ static int nf_tables_parse_devices(const struct nft_ctx *ctx,
}
nla_strlcpy(ifname, tmp, IFNAMSIZ);
- dev = dev_get_by_name(ctx->net, ifname);
+ dev = __dev_get_by_name(ctx->net, ifname);
if (!dev) {
err = -ENOENT;
goto err1;
@@ -5007,10 +5003,8 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
return err;
ops = kzalloc(sizeof(struct nf_hook_ops) * n, GFP_KERNEL);
- if (!ops) {
- err = -ENOMEM;
- goto err1;
- }
+ if (!ops)
+ return -ENOMEM;
flowtable->hooknum = hooknum;
flowtable->priority = priority;
@@ -5028,11 +5022,6 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
GFP_KERNEL);
}
- err = 0;
-err1:
- for (i = 0; i < n; i++)
- dev_put(dev_array[i]);
-
return err;
}
--
2.11.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 7/7] netfilter: nf_socket: Fix out of bounds access in nf_sk_lookup_slow_v{4,6}
2018-03-24 20:34 [PATCH 0/7] Netfilter fixes for net Pablo Neira Ayuso
` (5 preceding siblings ...)
2018-03-24 20:34 ` [PATCH 6/7] netfilter: nf_tables: do not hold reference on netdevice from preparation phase Pablo Neira Ayuso
@ 2018-03-24 20:34 ` Pablo Neira Ayuso
2018-03-24 21:10 ` [PATCH 0/7] Netfilter fixes for net David Miller
7 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2018-03-24 20:34 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
From: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
skb_header_pointer will copy data into a buffer if data is non linear,
otherwise it will return a pointer in the linear section of the data.
nf_sk_lookup_slow_v{4,6} always copies data of size udphdr but later
accesses memory within the size of tcphdr (th->doff) in case of TCP
packets. This causes a crash when running with KASAN with the following
call stack -
BUG: KASAN: stack-out-of-bounds in xt_socket_lookup_slow_v4+0x524/0x718
net/netfilter/xt_socket.c:178
Read of size 2 at addr ffffffe3d417a87c by task syz-executor/28971
CPU: 2 PID: 28971 Comm: syz-executor Tainted: G B W O 4.9.65+ #1
Call trace:
[<ffffff9467e8d390>] dump_backtrace+0x0/0x428 arch/arm64/kernel/traps.c:76
[<ffffff9467e8d7e0>] show_stack+0x28/0x38 arch/arm64/kernel/traps.c:226
[<ffffff946842d9b8>] __dump_stack lib/dump_stack.c:15 [inline]
[<ffffff946842d9b8>] dump_stack+0xd4/0x124 lib/dump_stack.c:51
[<ffffff946811d4b0>] print_address_description+0x68/0x258 mm/kasan/report.c:248
[<ffffff946811d8c8>] kasan_report_error mm/kasan/report.c:347 [inline]
[<ffffff946811d8c8>] kasan_report.part.2+0x228/0x2f0 mm/kasan/report.c:371
[<ffffff946811df44>] kasan_report+0x5c/0x70 mm/kasan/report.c:372
[<ffffff946811bebc>] check_memory_region_inline mm/kasan/kasan.c:308 [inline]
[<ffffff946811bebc>] __asan_load2+0x84/0x98 mm/kasan/kasan.c:739
[<ffffff94694d6f04>] __tcp_hdrlen include/linux/tcp.h:35 [inline]
[<ffffff94694d6f04>] xt_socket_lookup_slow_v4+0x524/0x718 net/netfilter/xt_socket.c:178
Fix this by copying data into appropriate size headers based on protocol.
Fixes: a583636a83ea ("inet: refactor inet[6]_lookup functions to take skb")
Signed-off-by: Tejaswi Tanikella <tejaswit@codeaurora.org>
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/netfilter/nf_socket_ipv4.c | 6 ++++--
net/ipv6/netfilter/nf_socket_ipv6.c | 6 ++++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/netfilter/nf_socket_ipv4.c b/net/ipv4/netfilter/nf_socket_ipv4.c
index e9293bdebba0..4824b1e183a1 100644
--- a/net/ipv4/netfilter/nf_socket_ipv4.c
+++ b/net/ipv4/netfilter/nf_socket_ipv4.c
@@ -108,10 +108,12 @@ struct sock *nf_sk_lookup_slow_v4(struct net *net, const struct sk_buff *skb,
int doff = 0;
if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
- struct udphdr _hdr, *hp;
+ struct tcphdr _hdr;
+ struct udphdr *hp;
hp = skb_header_pointer(skb, ip_hdrlen(skb),
- sizeof(_hdr), &_hdr);
+ iph->protocol == IPPROTO_UDP ?
+ sizeof(*hp) : sizeof(_hdr), &_hdr);
if (hp == NULL)
return NULL;
diff --git a/net/ipv6/netfilter/nf_socket_ipv6.c b/net/ipv6/netfilter/nf_socket_ipv6.c
index ebb2bf84232a..f14de4b6d639 100644
--- a/net/ipv6/netfilter/nf_socket_ipv6.c
+++ b/net/ipv6/netfilter/nf_socket_ipv6.c
@@ -116,9 +116,11 @@ struct sock *nf_sk_lookup_slow_v6(struct net *net, const struct sk_buff *skb,
}
if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
- struct udphdr _hdr, *hp;
+ struct tcphdr _hdr;
+ struct udphdr *hp;
- hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
+ hp = skb_header_pointer(skb, thoff, tproto == IPPROTO_UDP ?
+ sizeof(*hp) : sizeof(_hdr), &_hdr);
if (hp == NULL)
return NULL;
--
2.11.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 0/7] Netfilter fixes for net
2018-03-24 20:34 [PATCH 0/7] Netfilter fixes for net Pablo Neira Ayuso
` (6 preceding siblings ...)
2018-03-24 20:34 ` [PATCH 7/7] netfilter: nf_socket: Fix out of bounds access in nf_sk_lookup_slow_v{4,6} Pablo Neira Ayuso
@ 2018-03-24 21:10 ` David Miller
7 siblings, 0 replies; 9+ messages in thread
From: David Miller @ 2018-03-24 21:10 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, netdev
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Sat, 24 Mar 2018 21:34:16 +0100
> The following patchset contains Netfilter fixes for your net tree,
> they are:
...
> You can pull these changes from:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git
Pulled, thank you.
^ permalink raw reply [flat|nested] 9+ messages in thread