Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
d050de607f
1 changed files with 23 additions and 26 deletions
|
@ -66,20 +66,6 @@ struct nft_jumpstack {
|
||||||
int rulenum;
|
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 {
|
enum nft_trace {
|
||||||
NFT_TRACE_RULE,
|
NFT_TRACE_RULE,
|
||||||
NFT_TRACE_RETURN,
|
NFT_TRACE_RETURN,
|
||||||
|
@ -117,13 +103,14 @@ static void nft_trace_packet(const struct nft_pktinfo *pkt,
|
||||||
unsigned int
|
unsigned int
|
||||||
nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
|
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_rule *rule;
|
||||||
const struct nft_expr *expr, *last;
|
const struct nft_expr *expr, *last;
|
||||||
struct nft_data data[NFT_REG_MAX + 1];
|
struct nft_data data[NFT_REG_MAX + 1];
|
||||||
unsigned int stackptr = 0;
|
unsigned int stackptr = 0;
|
||||||
struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
|
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
|
* Cache cursor to avoid problems in case that the cursor is updated
|
||||||
* while traversing the ruleset.
|
* 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);
|
unsigned int gencursor = ACCESS_ONCE(chain->net->nft.gencursor);
|
||||||
|
|
||||||
do_chain:
|
do_chain:
|
||||||
|
rulenum = 0;
|
||||||
rule = list_entry(&chain->rules, struct nft_rule, list);
|
rule = list_entry(&chain->rules, struct nft_rule, list);
|
||||||
next_rule:
|
next_rule:
|
||||||
data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
|
data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
|
||||||
|
@ -156,8 +144,10 @@ next_rule:
|
||||||
switch (data[NFT_REG_VERDICT].verdict) {
|
switch (data[NFT_REG_VERDICT].verdict) {
|
||||||
case NFT_BREAK:
|
case NFT_BREAK:
|
||||||
data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
|
data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
|
||||||
/* fall through */
|
continue;
|
||||||
case NFT_CONTINUE:
|
case NFT_CONTINUE:
|
||||||
|
if (unlikely(pkt->skb->nf_trace))
|
||||||
|
nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -183,37 +173,44 @@ next_rule:
|
||||||
jumpstack[stackptr].rule = rule;
|
jumpstack[stackptr].rule = rule;
|
||||||
jumpstack[stackptr].rulenum = rulenum;
|
jumpstack[stackptr].rulenum = rulenum;
|
||||||
stackptr++;
|
stackptr++;
|
||||||
/* fall through */
|
chain = data[NFT_REG_VERDICT].chain;
|
||||||
|
goto do_chain;
|
||||||
case NFT_GOTO:
|
case NFT_GOTO:
|
||||||
|
if (unlikely(pkt->skb->nf_trace))
|
||||||
|
nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
|
||||||
|
|
||||||
chain = data[NFT_REG_VERDICT].chain;
|
chain = data[NFT_REG_VERDICT].chain;
|
||||||
goto do_chain;
|
goto do_chain;
|
||||||
case NFT_RETURN:
|
case NFT_RETURN:
|
||||||
if (unlikely(pkt->skb->nf_trace))
|
if (unlikely(pkt->skb->nf_trace))
|
||||||
nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
|
nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
|
||||||
|
break;
|
||||||
/* fall through */
|
|
||||||
case NFT_CONTINUE:
|
case NFT_CONTINUE:
|
||||||
|
if (unlikely(pkt->skb->nf_trace && !(chain->flags & NFT_BASE_CHAIN)))
|
||||||
|
nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackptr > 0) {
|
if (stackptr > 0) {
|
||||||
if (unlikely(pkt->skb->nf_trace))
|
|
||||||
nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN);
|
|
||||||
|
|
||||||
stackptr--;
|
stackptr--;
|
||||||
chain = jumpstack[stackptr].chain;
|
chain = jumpstack[stackptr].chain;
|
||||||
rule = jumpstack[stackptr].rule;
|
rule = jumpstack[stackptr].rule;
|
||||||
rulenum = jumpstack[stackptr].rulenum;
|
rulenum = jumpstack[stackptr].rulenum;
|
||||||
goto next_rule;
|
goto next_rule;
|
||||||
}
|
}
|
||||||
nft_chain_stats(chain, pkt, jumpstack, stackptr);
|
|
||||||
|
|
||||||
if (unlikely(pkt->skb->nf_trace))
|
if (unlikely(pkt->skb->nf_trace))
|
||||||
nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_POLICY);
|
nft_trace_packet(pkt, basechain, -1, NFT_TRACE_POLICY);
|
||||||
|
|
||||||
return nft_base_chain(chain)->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(basechain)->policy;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nft_do_chain);
|
EXPORT_SYMBOL_GPL(nft_do_chain);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue