Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d050de60 authored by David S. Miller's avatar David S. Miller
Browse files


Pablo Neira Ayuso says:

====================
Netfilter/nftables fixes for net

The following patchset contains nftables fixes for your net tree, they
are:

1) Fix crash when using the goto action in a rule by making sure that
   we always fall back on the base chain. Otherwise, this may try to
   access the counter memory area of non-base chains, which does not
   exists.

2) Fix several aspects of the rule tracing that are currently broken:

   * Reset rule number counter after goto/jump action, otherwise the
     tracing reports a bogus rule number.
   * Fix tracing of the goto action.
   * Fix bogus rule number counter after goto.
   * Fix missing return trace after finishing the walk through the
     non-base chain.
   * Fix missing trace when matching non-terminal rule.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e1618d46 3b084e99
Loading
Loading
Loading
Loading
+23 −26
Original line number Diff line number Diff line
@@ -66,20 +66,6 @@ struct nft_jumpstack {
	int			rulenum;
};

static inline void
nft_chain_stats(const struct nft_chain *this, const struct nft_pktinfo *pkt,
		struct nft_jumpstack *jumpstack, unsigned int stackptr)
{
	struct nft_stats __percpu *stats;
	const struct nft_chain *chain = stackptr ? jumpstack[0].chain : this;

	rcu_read_lock_bh();
	stats = rcu_dereference(nft_base_chain(chain)->stats);
	__this_cpu_inc(stats->pkts);
	__this_cpu_add(stats->bytes, pkt->skb->len);
	rcu_read_unlock_bh();
}

enum nft_trace {
	NFT_TRACE_RULE,
	NFT_TRACE_RETURN,
@@ -117,13 +103,14 @@ static void nft_trace_packet(const struct nft_pktinfo *pkt,
unsigned int
nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
{
	const struct nft_chain *chain = ops->priv;
	const struct nft_chain *chain = ops->priv, *basechain = chain;
	const struct nft_rule *rule;
	const struct nft_expr *expr, *last;
	struct nft_data data[NFT_REG_MAX + 1];
	unsigned int stackptr = 0;
	struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
	int rulenum = 0;
	struct nft_stats __percpu *stats;
	int rulenum;
	/*
	 * Cache cursor to avoid problems in case that the cursor is updated
	 * while traversing the ruleset.
@@ -131,6 +118,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
	unsigned int gencursor = ACCESS_ONCE(chain->net->nft.gencursor);

do_chain:
	rulenum = 0;
	rule = list_entry(&chain->rules, struct nft_rule, list);
next_rule:
	data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
@@ -156,8 +144,10 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
		switch (data[NFT_REG_VERDICT].verdict) {
		case NFT_BREAK:
			data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
			/* fall through */
			continue;
		case NFT_CONTINUE:
			if (unlikely(pkt->skb->nf_trace))
				nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
			continue;
		}
		break;
@@ -183,37 +173,44 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
		jumpstack[stackptr].rule  = rule;
		jumpstack[stackptr].rulenum = rulenum;
		stackptr++;
		/* fall through */
		chain = data[NFT_REG_VERDICT].chain;
		goto do_chain;
	case NFT_GOTO:
		if (unlikely(pkt->skb->nf_trace))
			nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);

		chain = data[NFT_REG_VERDICT].chain;
		goto do_chain;
	case NFT_RETURN:
		if (unlikely(pkt->skb->nf_trace))
			nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);

		/* fall through */
		break;
	case NFT_CONTINUE:
		if (unlikely(pkt->skb->nf_trace && !(chain->flags & NFT_BASE_CHAIN)))
			nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN);
		break;
	default:
		WARN_ON(1);
	}

	if (stackptr > 0) {
		if (unlikely(pkt->skb->nf_trace))
			nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN);

		stackptr--;
		chain = jumpstack[stackptr].chain;
		rule  = jumpstack[stackptr].rule;
		rulenum = jumpstack[stackptr].rulenum;
		goto next_rule;
	}
	nft_chain_stats(chain, pkt, jumpstack, stackptr);

	if (unlikely(pkt->skb->nf_trace))
		nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_POLICY);
		nft_trace_packet(pkt, basechain, -1, NFT_TRACE_POLICY);

	rcu_read_lock_bh();
	stats = rcu_dereference(nft_base_chain(basechain)->stats);
	__this_cpu_inc(stats->pkts);
	__this_cpu_add(stats->bytes, pkt->skb->len);
	rcu_read_unlock_bh();

	return nft_base_chain(chain)->policy;
	return nft_base_chain(basechain)->policy;
}
EXPORT_SYMBOL_GPL(nft_do_chain);