netfilter: nf_tables: fix crash when nf_trace is enabled
authorFlorian Westphal <fw@strlen.de>
Thu, 4 Aug 2022 17:26:27 +0000 (19:26 +0200)
committerJakub Kicinski <kuba@kernel.org>
Sat, 6 Aug 2022 01:50:14 +0000 (18:50 -0700)
do not access info->pkt when info->trace is not 1.
nft_traceinfo is not initialized, except when tracing is enabled.

The 'nft_trace_enabled' static key cannot be used for this, we must
always check info->trace first.

Pass nft_pktinfo directly to avoid this.

Fixes: e34b9ed96ce3 ("netfilter: nf_tables: avoid skb access on nf_stolen")
Reported-by: Hangbin Liu <liuhangbin@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/netfilter/nf_tables_core.c

index 3ddce24..cee3e4e 100644 (file)
@@ -34,25 +34,23 @@ static noinline void __nft_trace_packet(struct nft_traceinfo *info,
        nft_trace_notify(info);
 }
 
-static inline void nft_trace_packet(struct nft_traceinfo *info,
+static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
+                                   struct nft_traceinfo *info,
                                    const struct nft_chain *chain,
                                    const struct nft_rule_dp *rule,
                                    enum nft_trace_types type)
 {
        if (static_branch_unlikely(&nft_trace_enabled)) {
-               const struct nft_pktinfo *pkt = info->pkt;
-
                info->nf_trace = pkt->skb->nf_trace;
                info->rule = rule;
                __nft_trace_packet(info, chain, type);
        }
 }
 
-static inline void nft_trace_copy_nftrace(struct nft_traceinfo *info)
+static inline void nft_trace_copy_nftrace(const struct nft_pktinfo *pkt,
+                                         struct nft_traceinfo *info)
 {
        if (static_branch_unlikely(&nft_trace_enabled)) {
-               const struct nft_pktinfo *pkt = info->pkt;
-
                if (info->trace)
                        info->nf_trace = pkt->skb->nf_trace;
        }
@@ -96,7 +94,6 @@ static noinline void __nft_trace_verdict(struct nft_traceinfo *info,
                                         const struct nft_chain *chain,
                                         const struct nft_regs *regs)
 {
-       const struct nft_pktinfo *pkt = info->pkt;
        enum nft_trace_types type;
 
        switch (regs->verdict.code) {
@@ -110,7 +107,9 @@ static noinline void __nft_trace_verdict(struct nft_traceinfo *info,
                break;
        default:
                type = NFT_TRACETYPE_RULE;
-               info->nf_trace = pkt->skb->nf_trace;
+
+               if (info->trace)
+                       info->nf_trace = info->pkt->skb->nf_trace;
                break;
        }
 
@@ -271,10 +270,10 @@ next_rule:
                switch (regs.verdict.code) {
                case NFT_BREAK:
                        regs.verdict.code = NFT_CONTINUE;
-                       nft_trace_copy_nftrace(&info);
+                       nft_trace_copy_nftrace(pkt, &info);
                        continue;
                case NFT_CONTINUE:
-                       nft_trace_packet(&info, chain, rule,
+                       nft_trace_packet(pkt, &info, chain, rule,
                                         NFT_TRACETYPE_RULE);
                        continue;
                }
@@ -318,7 +317,7 @@ next_rule:
                goto next_rule;
        }
 
-       nft_trace_packet(&info, basechain, NULL, NFT_TRACETYPE_POLICY);
+       nft_trace_packet(pkt, &info, basechain, NULL, NFT_TRACETYPE_POLICY);
 
        if (static_branch_unlikely(&nft_counters_enabled))
                nft_update_chain_stats(basechain, pkt);