@@ -1539,6 +1539,7 @@ struct nft_trans_rule {
struct nft_rule *rule;
struct nft_flow_rule *flow;
u32 rule_id;
+ bool chain_hw_offloaded;
};
#define nft_trans_rule(trans) \
@@ -1547,6 +1548,8 @@ struct nft_trans_rule {
(((struct nft_trans_rule *)trans->data)->flow)
#define nft_trans_rule_id(trans) \
(((struct nft_trans_rule *)trans->data)->rule_id)
+#define nft_trans_rule_chain_hw_offloaded(trans) \
+ (((struct nft_trans_rule *)trans->data)->chain_hw_offloaded)
struct nft_trans_set {
struct nft_set *set;
@@ -8465,7 +8465,7 @@ static void nft_commit_release(struct nft_trans *trans)
nf_tables_chain_destroy(&trans->ctx);
break;
case NFT_MSG_DELRULE:
- if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
+ if (nft_trans_rule_chain_hw_offloaded(trans))
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
@@ -8966,6 +8966,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_trans_destroy(trans);
break;
case NFT_MSG_DELRULE:
+ if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
+ nft_trans_rule_chain_hw_offloaded(trans) = true;
list_del_rcu(&nft_trans_rule(trans)->list);
nf_tables_rule_notify(&trans->ctx,
nft_trans_rule(trans),
syzbot found following KASAN splat: use-after-free in nft_commit_release net/netfilter/nf_tables_api.c:8467 [inline] This is the ctx.chain-> deref: case NFT_MSG_DELRULE: if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD) in nft_commit_release. That function runs asynchonously after the commit mutex has been released. In the syzbot case, chain has already been released from netdev notifier chain: kfree+0xe2/0x580 mm/slub.c:4567 nf_tables_chain_destroy+0x4ec/0x640 net/netfilter/nf_tables_api.c:1889 __nft_release_table+0x96c/0xcd0 net/netfilter/nf_tables_api.c:9996 nft_rcv_nl_event+0x3f6/0x5b0 net/netfilter/nf_tables_api.c:10047 notifier_call_chain+0xb5/0x200 kernel/notifier.c:87 Fix this by stashing the "is offloaded" information in the transaction object while we're still in the transaction mutex protected code and then use it in the async part. Reported-by: syzbot+8f747f62763bc6c32916@syzkaller.appspotmail.com Fixes: 9dd732e0bdf5 ("netfilter: nf_tables: memleak flow rule from commit path") Signed-off-by: Florian Westphal <fw@strlen.de> --- include/net/netfilter/nf_tables.h | 3 +++ net/netfilter/nf_tables_api.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-)