Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_tables: fix crash when nf_trace is enabled

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>

authored by

Florian Westphal and committed by
Jakub Kicinski
399a14ec 2e64fe46

+10 -11
+10 -11
net/netfilter/nf_tables_core.c
··· 34 34 nft_trace_notify(info); 35 35 } 36 36 37 - static inline void nft_trace_packet(struct nft_traceinfo *info, 37 + static inline void nft_trace_packet(const struct nft_pktinfo *pkt, 38 + struct nft_traceinfo *info, 38 39 const struct nft_chain *chain, 39 40 const struct nft_rule_dp *rule, 40 41 enum nft_trace_types type) 41 42 { 42 43 if (static_branch_unlikely(&nft_trace_enabled)) { 43 - const struct nft_pktinfo *pkt = info->pkt; 44 - 45 44 info->nf_trace = pkt->skb->nf_trace; 46 45 info->rule = rule; 47 46 __nft_trace_packet(info, chain, type); 48 47 } 49 48 } 50 49 51 - static inline void nft_trace_copy_nftrace(struct nft_traceinfo *info) 50 + static inline void nft_trace_copy_nftrace(const struct nft_pktinfo *pkt, 51 + struct nft_traceinfo *info) 52 52 { 53 53 if (static_branch_unlikely(&nft_trace_enabled)) { 54 - const struct nft_pktinfo *pkt = info->pkt; 55 - 56 54 if (info->trace) 57 55 info->nf_trace = pkt->skb->nf_trace; 58 56 } ··· 94 96 const struct nft_chain *chain, 95 97 const struct nft_regs *regs) 96 98 { 97 - const struct nft_pktinfo *pkt = info->pkt; 98 99 enum nft_trace_types type; 99 100 100 101 switch (regs->verdict.code) { ··· 107 110 break; 108 111 default: 109 112 type = NFT_TRACETYPE_RULE; 110 - info->nf_trace = pkt->skb->nf_trace; 113 + 114 + if (info->trace) 115 + info->nf_trace = info->pkt->skb->nf_trace; 111 116 break; 112 117 } 113 118 ··· 270 271 switch (regs.verdict.code) { 271 272 case NFT_BREAK: 272 273 regs.verdict.code = NFT_CONTINUE; 273 - nft_trace_copy_nftrace(&info); 274 + nft_trace_copy_nftrace(pkt, &info); 274 275 continue; 275 276 case NFT_CONTINUE: 276 - nft_trace_packet(&info, chain, rule, 277 + nft_trace_packet(pkt, &info, chain, rule, 277 278 NFT_TRACETYPE_RULE); 278 279 continue; 279 280 } ··· 317 318 goto next_rule; 318 319 } 319 320 320 - nft_trace_packet(&info, basechain, NULL, NFT_TRACETYPE_POLICY); 321 + nft_trace_packet(pkt, &info, basechain, NULL, NFT_TRACETYPE_POLICY); 321 322 322 323 if (static_branch_unlikely(&nft_counters_enabled)) 323 324 nft_update_chain_stats(basechain, pkt);