summaryrefslogtreecommitdiff
path: root/net/netfilter/nf_tables_api.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2019-05-13 08:55:15 -0700
committerDavid S. Miller <davem@davemloft.net>2019-05-13 08:55:15 -0700
commit3ebb41bf47865842f4153b855fe2551fef78fbd1 (patch)
tree62f4376ad72d0d50ca55d3c11db20f63ac6de8c5 /net/netfilter/nf_tables_api.c
parent3ee9ae74ba4a85c3b378a0e49ec1481655f54500 (diff)
parent92285a079eedfe104a773a7c4293f77a01f456fb (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 net: 1) Postpone chain policy update to drop after transaction is complete, from Florian Westphal. 2) Add entry to flowtable after confirmation to fix UDP flows with packets going in one single direction. 3) Reference count leak in dst object, from Taehee Yoo. 4) Check for TTL field in flowtable datapath, from Taehee Yoo. 5) Fix h323 conntrack helper due to incorrect boundary check, from Jakub Jankowski. 6) Fix incorrect rcu dereference when fetching basechain stats, from Florian Westphal. 7) Missing error check when adding new entries to flowtable, from Taehee Yoo. 8) Use version field in nfnetlink message to honor the nfgen_family field, from Kristian Evensen. 9) Remove incorrect configuration check for CONFIG_NF_CONNTRACK_IPV6, from Subash Abhinov Kasiviswanathan. 10) Prevent dying entries from being added to the flowtable, from Taehee Yoo. 11) Don't hit WARN_ON() with malformed blob in ebtables with trailing data after last rule, reported by syzbot, patch from Florian Westphal. 12) Remove NFT_CT_TIMEOUT enumeration, never used in the kernel code. 13) Fix incorrect definition for NFT_LOGLEVEL_MAX, from Florian Westphal. This batch comes with a conflict that can be fixed with this patch: diff --cc include/uapi/linux/netfilter/nf_tables.h index 7bdb234f3d8c,f0cf7b0f4f35..505393c6e959 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@@ -966,6 -966,8 +966,7 @@@ enum nft_socket_keys * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address) * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address) * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address) - * @NFT_CT_TIMEOUT: connection tracking timeout policy assigned to conntrack + * @NFT_CT_ID: conntrack id */ enum nft_ct_keys { NFT_CT_STATE, @@@ -991,6 -993,8 +992,7 @@@ NFT_CT_DST_IP, NFT_CT_SRC_IP6, NFT_CT_DST_IP6, - NFT_CT_TIMEOUT, + NFT_CT_ID, __NFT_CT_MAX }; #define NFT_CT_MAX (__NFT_CT_MAX - 1) That replaces the unused NFT_CT_TIMEOUT definition by NFT_CT_ID. If you prefer, I can also solve this conflict here, just let me know. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netfilter/nf_tables_api.c')
-rw-r--r--net/netfilter/nf_tables_api.c59
1 files changed, 46 insertions, 13 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index d98416e83d4e..28241e82fd15 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -213,33 +213,33 @@ static int nft_deltable(struct nft_ctx *ctx)
return err;
}
-static int nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
+static struct nft_trans *nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
{
struct nft_trans *trans;
trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_chain));
if (trans == NULL)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
if (msg_type == NFT_MSG_NEWCHAIN)
nft_activate_next(ctx->net, ctx->chain);
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
- return 0;
+ return trans;
}
static int nft_delchain(struct nft_ctx *ctx)
{
- int err;
+ struct nft_trans *trans;
- err = nft_trans_chain_add(ctx, NFT_MSG_DELCHAIN);
- if (err < 0)
- return err;
+ trans = nft_trans_chain_add(ctx, NFT_MSG_DELCHAIN);
+ if (IS_ERR(trans))
+ return PTR_ERR(trans);
ctx->table->use--;
nft_deactivate_next(ctx->net, ctx->chain);
- return err;
+ return 0;
}
static void nft_rule_expr_activate(const struct nft_ctx *ctx,
@@ -1189,6 +1189,9 @@ static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
u64 pkts, bytes;
int cpu;
+ if (!stats)
+ return 0;
+
memset(&total, 0, sizeof(total));
for_each_possible_cpu(cpu) {
cpu_stats = per_cpu_ptr(stats, cpu);
@@ -1246,6 +1249,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
if (nft_is_base_chain(chain)) {
const struct nft_base_chain *basechain = nft_base_chain(chain);
const struct nf_hook_ops *ops = &basechain->ops;
+ struct nft_stats __percpu *stats;
struct nlattr *nest;
nest = nla_nest_start_noflag(skb, NFTA_CHAIN_HOOK);
@@ -1267,8 +1271,9 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name))
goto nla_put_failure;
- if (rcu_access_pointer(basechain->stats) &&
- nft_dump_stats(skb, rcu_dereference(basechain->stats)))
+ stats = rcu_dereference_check(basechain->stats,
+ lockdep_commit_lock_is_held(net));
+ if (nft_dump_stats(skb, stats))
goto nla_put_failure;
}
@@ -1615,6 +1620,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
struct nft_base_chain *basechain;
struct nft_stats __percpu *stats;
struct net *net = ctx->net;
+ struct nft_trans *trans;
struct nft_chain *chain;
struct nft_rule **rules;
int err;
@@ -1662,7 +1668,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
ops->dev = hook.dev;
chain->flags |= NFT_BASE_CHAIN;
- basechain->policy = policy;
+ basechain->policy = NF_ACCEPT;
} else {
chain = kzalloc(sizeof(*chain), GFP_KERNEL);
if (chain == NULL)
@@ -1698,13 +1704,18 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
if (err)
goto err2;
- err = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN);
- if (err < 0) {
+ trans = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN);
+ if (IS_ERR(trans)) {
+ err = PTR_ERR(trans);
rhltable_remove(&table->chains_ht, &chain->rhlhead,
nft_chain_ht_params);
goto err2;
}
+ nft_trans_chain_policy(trans) = -1;
+ if (nft_is_base_chain(chain))
+ nft_trans_chain_policy(trans) = policy;
+
table->use++;
list_add_tail_rcu(&chain->list, &table->chains);
@@ -6310,6 +6321,27 @@ static int nf_tables_validate(struct net *net)
return 0;
}
+/* a drop policy has to be deferred until all rules have been activated,
+ * otherwise a large ruleset that contains a drop-policy base chain will
+ * cause all packets to get dropped until the full transaction has been
+ * processed.
+ *
+ * We defer the drop policy until the transaction has been finalized.
+ */
+static void nft_chain_commit_drop_policy(struct nft_trans *trans)
+{
+ struct nft_base_chain *basechain;
+
+ if (nft_trans_chain_policy(trans) != NF_DROP)
+ return;
+
+ if (!nft_is_base_chain(trans->ctx.chain))
+ return;
+
+ basechain = nft_base_chain(trans->ctx.chain);
+ basechain->policy = NF_DROP;
+}
+
static void nft_chain_commit_update(struct nft_trans *trans)
{
struct nft_base_chain *basechain;
@@ -6631,6 +6663,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN);
/* trans destroyed after rcu grace period */
} else {
+ nft_chain_commit_drop_policy(trans);
nft_clear(net, trans->ctx.chain);
nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN);
nft_trans_destroy(trans);