nfqnl_recv_verdict() checks the verdict sender using NETLINK_CB(skb).portid, but nfqnl_ct_parse() passes NETLINK_CB(entry->skb).portid to attach_expect(). The latter skb holds the queued network packet, not the Netlink verdict. Its control buffer does not identify the sender of the verdict. Pass the verdict sender's portid to nfqnl_ct_parse() and use it for expectation events. Do not change the queued packet's control buffer. Fixes: b7bd1809e078 ("netfilter: nfnetlink_queue: get rid of nfnetlink_queue_ct.c") Signed-off-by: Baek Kyu, Kim --- Tested under arm64 QEMU/KVM with SIP and registered userspace conntrack helpers. With conntrack events enabled, NFQA_CT/NFQA_EXP verdicts with NLM_F_ECHO panicked on the original kernel. The changed kernel delivered the UDP packet, created an expectation, and sent the event to the requester. Both kernels completed without echo. With the default event setting, a multicast subscriber also reproduced the original panic. No deployed NFQUEUE program was tested. net/netfilter/nfnetlink_queue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 90d887546f7db..9fe2e85a2b3e0 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -1771,6 +1771,7 @@ static struct nf_conn *nfqnl_ct_parse(const struct nfnl_ct_hook *nfnl_ct, const struct nlmsghdr *nlh, const struct nlattr * const nfqa[], struct nf_queue_entry *entry, + u32 portid, enum ip_conntrack_info *ctinfo) { #if IS_ENABLED(CONFIG_NF_CONNTRACK) @@ -1785,7 +1786,7 @@ static struct nf_conn *nfqnl_ct_parse(const struct nfnl_ct_hook *nfnl_ct, if (nfqa[NFQA_EXP]) nfnl_ct->attach_expect(nfqa[NFQA_EXP], ct, - NETLINK_CB(entry->skb).portid, + portid, nlmsg_report(nlh)); return ct; #else @@ -1863,6 +1864,7 @@ static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info, if (nfqa[NFQA_CT]) { if (nfnl_ct != NULL) ct = nfqnl_ct_parse(nfnl_ct, info->nlh, nfqa, entry, + NETLINK_CB(skb).portid, &ctinfo); }