From nobody Thu Sep 24 22:57:52 2026 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B953451DAFF; Fri, 18 Sep 2026 18:25:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789755921; cv=none; b=r03DPxOt5fKIehUHt7lnFXKOhPccHHQiSBcGNucZNpcJ8pqssNY09QaesDeKVgO9TQwRSmBzjfHmRDVw/HxuZP0AKOZ+CIrfym+dS4qDbVF44QLahVUCWBYiSr6XAn/QlayqCBLRPr2uJrnCNmDGBCAJywvqVHutabYR3zMSeTg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789755921; c=relaxed/simple; bh=xU97uUXSBagsr9GmQsHQZz14yy9MIHq+sTygSuX+pUo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rDFvIlhEY6X5gViEjn7QY9wT0jtmWqniUY/A9OOS4fpynsO0CoZ1HgNjj3BtudD93W+1cEfvUJziJn0y4J5FSa60NQaWlcNEibJXS671iFM/yRGLRqz903ZFyepVgUy76zABIf5zuzDTJN0TMhpTNuVkqeR2baHy+E4OxGrxp/c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=BkcygTY0; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="BkcygTY0" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id DF663C58475; Fri, 18 Sep 2026 18:26:02 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id F26DF60649; Fri, 18 Sep 2026 18:25:17 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 5BA4810329076; Fri, 18 Sep 2026 20:25:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1789755912; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=NQhcRprTw25ITjYAfpiTxCx6Y2AUlx+f46fkhpetZkc=; b=BkcygTY0+qVPb1X9zeEAOPT6Sl4tVSOo41ZSwGlMLE72kXVMv5xC/9d8RLnmrq0VGmHUZa HtB8rTlxIC29z6TKCb3+DKE6/GdhbEjrQlw669NSJgIoIldi+sXEAsHWdXuw/Hu0r6lvrX yHY3eORqIpb5Aw7YMMsEx9lvN9nVGKT5yY/YqzhOfy4OD//fZCjMKDUiPoiG2ebLKezoLX h2ABrvy66Jo6AMCtFliQtOMQwgGz5R30aiVSmg0pypfS5j6imNSATA7VMgBWv+LsHSBP8c G03WxM6E6NpC7Bqp5s3XjUIzAw0HEIU0wFYLSPvEe1anZgKQpKBMm9CDXz5j2Q== From: "Miguel Gazquez (Schneider Electric)" Date: Fri, 18 Sep 2026 20:24:53 +0200 Subject: [PATCH 6.1.y 1/3] netfilter: nf_conntrack_pptp: move GRE specific cleanup to GRE tracker Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260918-cve-2026-80668-6-1-v1-1-7a8667286d67@bootlin.com> References: <20260918-cve-2026-80668-6-1-v1-0-7a8667286d67@bootlin.com> In-Reply-To: <20260918-cve-2026-80668-6-1-v1-0-7a8667286d67@bootlin.com> To: stable@vger.kernel.org, Pablo Neira Ayuso , Jozsef Kadlecsik , Florian Westphal , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Hideaki YOSHIFUJI , David Ahern Cc: Benjamin Robin , netfilter-devel@vger.kernel.org, coreteam@netfilter.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, "Miguel Gazquez (Schneider Electric)" , Sasha Levin X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1789755899; l=6834; i=miguel.gazquez@bootlin.com; s=20250708; h=from:subject:message-id; bh=tbozF3pXafltgmdWVlAd94i6K9+Ap0Jr/y6XWjzrfW0=; b=B0UMV/Q+gXnLaxFgugVI99GqrKrfR2cY7Ucl8fpUskzaG3nfZgUVuK4BzueLiyQ0PtEXaKayx 8k90JCSoDbcDGdyTOX7SNgOLKh0SsX4N25+rFnK61qED09P7WqD8n/c X-Developer-Key: i=miguel.gazquez@bootlin.com; a=ed25519; pk=k/2KI9jkmayaF0ghZ8QYUH9Wm/kFHDhl8QoZ0RHbr4w= X-Last-TLS-Session-Version: TLSv1.3 From: Pablo Neira Ayuso [ Upstream commit fe97fd540a03034a780224f24b0b2f0e21c9c763 ] Move the GRE specific cleanup to nf_conntrack_proto_gre.c to ensure that the .destroy callback for the pptp helper is still reachable by existing conntrack entries while pptp module is being removed. This is a preparation patch, no functional changes are intended. Signed-off-by: Pablo Neira Ayuso Stable-dep-of: 979c13114c0b ("netfilter: nf_conntrack_expect: store master_= tuple in expectation") Signed-off-by: Sasha Levin Signed-off-by: Miguel Gazquez (Schneider Electric) --- include/net/netfilter/ipv4/nf_conntrack_ipv4.h | 4 ++ net/netfilter/nf_conntrack_pptp.c | 63 +---------------------= ---- net/netfilter/nf_conntrack_proto_gre.c | 61 ++++++++++++++++++++++= +++ 3 files changed, 67 insertions(+), 61 deletions(-) diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/n= etfilter/ipv4/nf_conntrack_ipv4.h index 2c8c2b023848..890fa73d96d8 100644 --- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h +++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h @@ -26,4 +26,8 @@ extern const struct nf_conntrack_l4proto nf_conntrack_l4p= roto_udplite; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_gre; #endif =20 +#if IS_ENABLED(CONFIG_NF_CONNTRACK_PPTP) +void gre_pptp_destroy_siblings(struct nf_conn *ct); +#endif + #endif /*_NF_CONNTRACK_IPV4_H*/ diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack= _pptp.c index 4c679638df06..759683d7de4f 100644 --- a/net/netfilter/nf_conntrack_pptp.c +++ b/net/netfilter/nf_conntrack_pptp.c @@ -124,65 +124,6 @@ static void pptp_expectfn(struct nf_conn *ct, } } =20 -static int destroy_sibling_or_exp(struct net *net, struct nf_conn *ct, - const struct nf_conntrack_tuple *t) -{ - const struct nf_conntrack_tuple_hash *h; - const struct nf_conntrack_zone *zone; - struct nf_conntrack_expect *exp; - struct nf_conn *sibling; - - pr_debug("trying to timeout ct or exp for tuple "); - nf_ct_dump_tuple(t); - - zone =3D nf_ct_zone(ct); - h =3D nf_conntrack_find_get(net, zone, t); - if (h) { - sibling =3D nf_ct_tuplehash_to_ctrack(h); - pr_debug("setting timeout of conntrack %p to 0\n", sibling); - sibling->proto.gre.timeout =3D 0; - sibling->proto.gre.stream_timeout =3D 0; - nf_ct_kill(sibling); - nf_ct_put(sibling); - return 1; - } else { - exp =3D nf_ct_expect_find_get(net, zone, t); - if (exp) { - pr_debug("unexpect_related of expect %p\n", exp); - nf_ct_unexpect_related(exp); - nf_ct_expect_put(exp); - return 1; - } - } - return 0; -} - -/* timeout GRE data connections */ -static void pptp_destroy_siblings(struct nf_conn *ct) -{ - struct net *net =3D nf_ct_net(ct); - const struct nf_ct_pptp_master *ct_pptp_info =3D nfct_help_data(ct); - struct nf_conntrack_tuple t; - - nf_ct_gre_keymap_destroy(ct); - - /* try original (pns->pac) tuple */ - memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); - t.dst.protonum =3D IPPROTO_GRE; - t.src.u.gre.key =3D ct_pptp_info->pns_call_id; - t.dst.u.gre.key =3D ct_pptp_info->pac_call_id; - if (!destroy_sibling_or_exp(net, ct, &t)) - pr_debug("failed to timeout original pns->pac ct/exp\n"); - - /* try reply (pac->pns) tuple */ - memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); - t.dst.protonum =3D IPPROTO_GRE; - t.src.u.gre.key =3D ct_pptp_info->pac_call_id; - t.dst.u.gre.key =3D ct_pptp_info->pns_call_id; - if (!destroy_sibling_or_exp(net, ct, &t)) - pr_debug("failed to timeout reply pac->pns ct/exp\n"); -} - /* expect GRE connections (PNS->PAC and PAC->PNS direction) */ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid) { @@ -347,7 +288,7 @@ pptp_inbound_pkt(struct sk_buff *skb, unsigned int prot= off, info->cstate =3D PPTP_CALL_NONE; =20 /* untrack this call id, unexpect GRE packets */ - pptp_destroy_siblings(ct); + gre_pptp_destroy_siblings(ct); break; =20 case PPTP_WAN_ERROR_NOTIFY: @@ -593,7 +534,7 @@ static struct nf_conntrack_helper pptp __read_mostly = =3D { .tuple.src.u.tcp.port =3D cpu_to_be16(PPTP_CONTROL_PORT), .tuple.dst.protonum =3D IPPROTO_TCP, .help =3D conntrack_pptp_help, - .destroy =3D pptp_destroy_siblings, + .destroy =3D gre_pptp_destroy_siblings, .expect_policy =3D &pptp_exp_policy, }; =20 diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conn= track_proto_gre.c index 728eeb0aea87..dcff889b574e 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -283,6 +283,67 @@ gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] =3D { }; #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ =20 +#if IS_ENABLED(CONFIG_NF_CONNTRACK_PPTP) +static int destroy_sibling_or_exp(struct net *net, struct nf_conn *ct, + const struct nf_conntrack_tuple *t) +{ + const struct nf_conntrack_tuple_hash *h; + const struct nf_conntrack_zone *zone; + struct nf_conntrack_expect *exp; + struct nf_conn *sibling; + + pr_debug("trying to timeout ct or exp for tuple "); + nf_ct_dump_tuple(t); + + zone =3D nf_ct_zone(ct); + h =3D nf_conntrack_find_get(net, zone, t); + if (h) { + sibling =3D nf_ct_tuplehash_to_ctrack(h); + pr_debug("setting timeout of conntrack %p to 0\n", sibling); + sibling->proto.gre.timeout =3D 0; + sibling->proto.gre.stream_timeout =3D 0; + nf_ct_kill(sibling); + nf_ct_put(sibling); + return 1; + } else { + exp =3D nf_ct_expect_find_get(net, zone, t); + if (exp) { + pr_debug("unexpect_related of expect %p\n", exp); + nf_ct_unexpect_related(exp); + nf_ct_expect_put(exp); + return 1; + } + } + return 0; +} + +void gre_pptp_destroy_siblings(struct nf_conn *ct) +{ + struct net *net =3D nf_ct_net(ct); + const struct nf_ct_pptp_master *ct_pptp_info =3D nfct_help_data(ct); + struct nf_conntrack_tuple t; + + nf_ct_gre_keymap_destroy(ct); + + /* try original (pns->pac) tuple */ + memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); + t.dst.protonum =3D IPPROTO_GRE; + t.src.u.gre.key =3D ct_pptp_info->pns_call_id; + t.dst.u.gre.key =3D ct_pptp_info->pac_call_id; + if (!destroy_sibling_or_exp(net, ct, &t)) + pr_debug("failed to timeout original pns->pac ct/exp\n"); + + /* try reply (pac->pns) tuple */ + memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); + t.dst.protonum =3D IPPROTO_GRE; + t.src.u.gre.key =3D ct_pptp_info->pac_call_id; + t.dst.u.gre.key =3D ct_pptp_info->pns_call_id; + if (!destroy_sibling_or_exp(net, ct, &t)) + pr_debug("failed to timeout reply pac->pns ct/exp\n"); +} +EXPORT_SYMBOL_GPL(gre_pptp_destroy_siblings); +#endif + void nf_conntrack_gre_init_net(struct net *net) { struct nf_gre_net *net_gre =3D gre_pernet(net); --=20 2.55.0 From nobody Thu Sep 24 22:57:52 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0971E52189E; Fri, 18 Sep 2026 18:25:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789755930; cv=none; b=eH1ieF/jsQbT44xaVJ0KsdB3gMNQ/tTAgzyFC9vnuiMx70pc1R7vyoOKaxEtMucj1gjc8OWedpIzLlgCJQ+DoiMeT3W4E1HJsN/EYTVGPiGa5C+vYqM+0wF4Oy65uqCZKxg16/1CNxcB0GwjbELLa1T6vor1Fx4vQzfoKWwJMgg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789755930; c=relaxed/simple; bh=eTZFUPAgXf9ixcPIOfSCsGlWndXD8MHKMQf9DV/ukYk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bJeCDBzkee7Nlh1lWT+33eai7+4HXTgTgCbbjG/5GZ6my+FT6FvjoMWsw+xb55agEm7vvYwK4kRleA/xuJQdlCet0A6kSwBDa7oLRDB/8G2WWuPcy3G4owhYlLMhyywPYYytUM/zTRoaKyhRzIf41P0NQV0cW1KgAjLYEdFZSkk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=xwEvp4EZ; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="xwEvp4EZ" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 9AE414E407BD; Fri, 18 Sep 2026 18:25:26 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 67BF060649; Fri, 18 Sep 2026 18:25:26 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 71D44103283A2; Fri, 18 Sep 2026 20:25:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1789755925; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=hY9CGJkwOV0jqm9ZrdaUlB8COeDxiaC7JvfTghhygK0=; b=xwEvp4EZyPja7Vp6PYQI1QVMKiRXRxooHr1h0DGT2BtxUzSwcWQTXz02J+2rY0D7+nZpf0 dIY19el9L+bJu6IKbktq5IrWEigsn8oPUS8KOAjJkegH++5k1G0rD5GqUE+Zay0tCvLwzc wpA5KChLuEbUKeHoqyjeb+uDqldg/GAi6nQPgewmnwovjR4M70ycKovxn1fAVA3OnLggE3 SHBYyjJ9rPHI2bLZVvEjtyTmO7xKIX4knDj6wEEM1HeikQ6jYJ/6Z7ihS3CaIXHdsjzraO 8dLpUpN9uK+3q/HIrTFqu4QeiK19q/hO0cRR6Ocs9HIk998QA8hax8zqf9KZqg== From: "Miguel Gazquez (Schneider Electric)" Date: Fri, 18 Sep 2026 20:24:54 +0200 Subject: [PATCH 6.1.y 2/3] netfilter: conntrack: check NULL when retrieving ct extension Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260918-cve-2026-80668-6-1-v1-2-7a8667286d67@bootlin.com> References: <20260918-cve-2026-80668-6-1-v1-0-7a8667286d67@bootlin.com> In-Reply-To: <20260918-cve-2026-80668-6-1-v1-0-7a8667286d67@bootlin.com> To: stable@vger.kernel.org, Pablo Neira Ayuso , Jozsef Kadlecsik , Florian Westphal , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Hideaki YOSHIFUJI , David Ahern Cc: Benjamin Robin , netfilter-devel@vger.kernel.org, coreteam@netfilter.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, "Miguel Gazquez (Schneider Electric)" , Sasha Levin X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1789755899; l=23999; i=miguel.gazquez@bootlin.com; s=20250708; h=from:subject:message-id; bh=Ox+UUQG9s5IMM2jF692BD/T3iml3gqTC4mG2g029tZI=; b=UmocVaghahkfb9qqhf6nSpAOnNHtG0DHHRFkUWLaWUjx2xKGUJ1RLEbYIggPQSmq0QSlUhotY lsPjZwJoZYsBYU/9wVj1GbuTgd8G1rjHvAajHPuqTrZA8l47OTQZjNJ X-Developer-Key: i=miguel.gazquez@bootlin.com; a=ed25519; pk=k/2KI9jkmayaF0ghZ8QYUH9Wm/kFHDhl8QoZ0RHbr4w= X-Last-TLS-Session-Version: TLSv1.3 From: Pablo Neira Ayuso [ Upstream commit e3cd138e560764299965fba5ec5240281a7faca2 ] nf_ct_ext_find() might return NULL if ct extension is not found. Add also the null checks to: - nfct_help() - nfct_help_data() - nfct_seqadj() - nfct_nat() This is defensive, for safety reasons. nf_ct_ext_find() used to return NULL if the extension is stale for unconfirmed conntracks if the genid validation fails. Skip NULL check in nf_nat_inet_fn() given this is valid to be NULL for non-initialized ct nat extensions. While at it, fetch ct helper area in nf_ct_expect_related_report() only once and pass it on to other ancilliary functions. Replace WARN_ON() by WARN_ON_ONCE() in nf_ct_unlink_expect_report(). Signed-off-by: Pablo Neira Ayuso Stable-dep-of: 979c13114c0b ("netfilter: nf_conntrack_expect: store master_= tuple in expectation") Signed-off-by: Sasha Levin --- include/net/netfilter/nf_conntrack_helper.h | 2 ++ net/ipv4/netfilter/nf_nat_h323.c | 12 +++++++++ net/ipv4/netfilter/nf_nat_pptp.c | 14 +++++++--- net/netfilter/nf_conntrack_broadcast.c | 3 +++ net/netfilter/nf_conntrack_expect.c | 33 ++++++++++++----------- net/netfilter/nf_conntrack_ftp.c | 6 +++++ net/netfilter/nf_conntrack_h323_main.c | 18 +++++++++++++ net/netfilter/nf_conntrack_pptp.c | 9 +++++++ net/netfilter/nf_conntrack_proto_gre.c | 10 +++++++ net/netfilter/nf_conntrack_sane.c | 3 +++ net/netfilter/nf_conntrack_seqadj.c | 17 ++++++++---- net/netfilter/nf_conntrack_sip.c | 41 +++++++++++++++++++++++++= ++-- net/netfilter/nf_nat_sip.c | 12 +++++++++ net/netfilter/nfnetlink_cthelper.c | 6 +++++ 14 files changed, 159 insertions(+), 27 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netf= ilter/nf_conntrack_helper.h index 2435039434ea..70fa6052d237 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -127,6 +127,8 @@ static inline void *nfct_help_data(const struct nf_conn= *ct) struct nf_conn_help *help; =20 help =3D nf_ct_ext_find(ct, NF_CT_EXT_HELPER); + if (!help) + return NULL; =20 return (void *)help->data; } diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h= 323.c index 10e1b0837731..183e8a3ff2ba 100644 --- a/net/ipv4/netfilter/nf_nat_h323.c +++ b/net/ipv4/netfilter/nf_nat_h323.c @@ -100,6 +100,9 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_= conn *ct, __be16 port; union nf_inet_addr addr; =20 + if (!info) + return -1; + for (i =3D 0; i < count; i++) { if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) { if (addr.ip =3D=3D ct->tuplehash[dir].tuple.src.u3.ip && @@ -184,6 +187,9 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_= conn *ct, int i; u_int16_t nated_port; =20 + if (!info) + return -1; + /* Set expectations for NAT */ rtp_exp->saved_proto.udp.port =3D rtp_exp->tuple.dst.u.udp.port; rtp_exp->expectfn =3D nf_nat_follow_master; @@ -325,6 +331,9 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn= *ct, int dir =3D CTINFO2DIR(ctinfo); u_int16_t nated_port =3D ntohs(port); =20 + if (!info) + return -1; + /* Set expectations for NAT */ exp->saved_proto.tcp.port =3D exp->tuple.dst.u.tcp.port; exp->expectfn =3D nf_nat_follow_master; @@ -404,6 +413,9 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn= *ct, u_int16_t nated_port =3D ntohs(port); union nf_inet_addr addr; =20 + if (!info) + return -1; + /* Set expectations for NAT */ exp->saved_proto.tcp.port =3D exp->tuple.dst.u.tcp.port; exp->expectfn =3D ip_nat_q931_expect; diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_p= ptp.c index fab357cc8559..fed5249001a4 100644 --- a/net/ipv4/netfilter/nf_nat_pptp.c +++ b/net/ipv4/netfilter/nf_nat_pptp.c @@ -53,11 +53,13 @@ static void pptp_nat_expected(struct nf_conn *ct, struct nf_conn_nat *nat; =20 nat =3D nf_ct_nat_ext_add(ct); - if (WARN_ON_ONCE(!nat)) + if (!nat) return; =20 nat_pptp_info =3D &nat->help.nat_pptp_info; ct_pptp_info =3D nfct_help_data(master); + if (!ct_pptp_info) + return; =20 /* And here goes the grand finale of corrosion... */ if (exp->dir =3D=3D IP_CT_DIR_ORIGINAL) { @@ -132,11 +134,13 @@ pptp_outbound_pkt(struct sk_buff *skb, __be16 new_callid; unsigned int cid_off; =20 - if (WARN_ON_ONCE(!nat)) + if (!nat) return NF_DROP; =20 nat_pptp_info =3D &nat->help.nat_pptp_info; ct_pptp_info =3D nfct_help_data(ct); + if (!ct_pptp_info) + return NF_DROP; =20 new_callid =3D ct_pptp_info->pns_call_id; =20 @@ -204,11 +208,13 @@ pptp_exp_gre(struct nf_conntrack_expect *expect_orig, struct nf_ct_pptp_master *ct_pptp_info; struct nf_nat_pptp *nat_pptp_info; =20 - if (WARN_ON_ONCE(!nat)) + if (!nat) return; =20 nat_pptp_info =3D &nat->help.nat_pptp_info; ct_pptp_info =3D nfct_help_data(ct); + if (!ct_pptp_info) + return; =20 /* save original PAC call ID in nat_info */ nat_pptp_info->pac_call_id =3D ct_pptp_info->pac_call_id; @@ -241,7 +247,7 @@ pptp_inbound_pkt(struct sk_buff *skb, __be16 new_pcid; unsigned int pcid_off; =20 - if (WARN_ON_ONCE(!nat)) + if (!nat) return NF_DROP; =20 nat_pptp_info =3D &nat->help.nat_pptp_info; diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conn= track_broadcast.c index ef8a7ca8c116..6b77d67b589f 100644 --- a/net/netfilter/nf_conntrack_broadcast.c +++ b/net/netfilter/nf_conntrack_broadcast.c @@ -29,6 +29,9 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb, struct nf_conn_help *help =3D nfct_help(ct); __be32 mask =3D 0; =20 + if (!help) + goto out; + /* we're only interested in locally generated packets */ if (skb->sk =3D=3D NULL || !net_eq(nf_ct_net(ct), sock_net(skb->sk))) goto out; diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntra= ck_expect.c index 34324dece89d..e0b99cffe1ee 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -52,8 +52,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expec= t *exp, struct nf_conntrack_net *cnet; =20 lockdep_nfct_expect_lock_held(); - WARN_ON(!master_help); - WARN_ON(timer_pending(&exp->timeout)); + WARN_ON_ONCE(timer_pending(&exp->timeout)); =20 hlist_del_rcu(&exp->hnode); =20 @@ -61,7 +60,8 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expec= t *exp, cnet->expect_count--; =20 hlist_del_rcu(&exp->lnode); - master_help->expecting[exp->class]--; + if (master_help) + master_help->expecting[exp->class]--; =20 nf_ct_expect_event_report(IPEXP_DESTROY, exp, portid, report); nf_ct_expect_put(exp); @@ -405,10 +405,10 @@ void nf_ct_expect_put(struct nf_conntrack_expect *exp) } EXPORT_SYMBOL_GPL(nf_ct_expect_put); =20 -static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) +static void nf_ct_expect_insert(struct nf_conntrack_expect *exp, + struct nf_conn_help *master_help) { struct nf_conntrack_net *cnet; - struct nf_conn_help *master_help =3D nfct_help(exp->master); struct nf_conntrack_helper *helper; struct net *net =3D nf_ct_exp_net(exp); unsigned int h =3D nf_ct_expect_dst_hash(net, &exp->tuple); @@ -436,10 +436,9 @@ static void nf_ct_expect_insert(struct nf_conntrack_ex= pect *exp) } =20 /* Race with expectations being used means we could have none to find; OK.= */ -static void evict_oldest_expect(struct nf_conn *master, +static void evict_oldest_expect(struct nf_conn_help *master_help, struct nf_conntrack_expect *new) { - struct nf_conn_help *master_help =3D nfct_help(master); struct nf_conntrack_expect *exp, *last =3D NULL; =20 hlist_for_each_entry(exp, &master_help->expectations, lnode) { @@ -452,13 +451,12 @@ static void evict_oldest_expect(struct nf_conn *maste= r, } =20 static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect, + struct nf_conn_help *master_help, unsigned int flags) { const struct nf_conntrack_expect_policy *p; struct nf_conntrack_expect *i; struct nf_conntrack_net *cnet; - struct nf_conn *master =3D expect->master; - struct nf_conn_help *master_help =3D nfct_help(master); struct nf_conntrack_helper *helper; struct net *net =3D nf_ct_exp_net(expect); struct hlist_node *next; @@ -467,10 +465,6 @@ static inline int __nf_ct_expect_check(struct nf_connt= rack_expect *expect, =20 lockdep_nfct_expect_lock_held(); =20 - if (!master_help) { - ret =3D -ESHUTDOWN; - goto out; - } h =3D nf_ct_expect_dst_hash(net, &expect->tuple); hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) { if (master_matches(i, expect, flags) && @@ -493,7 +487,7 @@ static inline int __nf_ct_expect_check(struct nf_conntr= ack_expect *expect, p =3D &helper->expect_policy[expect->class]; if (p->max_expected && master_help->expecting[expect->class] >=3D p->max_expected) { - evict_oldest_expect(master, expect); + evict_oldest_expect(master_help, expect); if (master_help->expecting[expect->class] >=3D p->max_expected) { ret =3D -EMFILE; @@ -514,14 +508,21 @@ static inline int __nf_ct_expect_check(struct nf_conn= track_expect *expect, int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, u32 portid, int report, unsigned int flags) { + struct nf_conn_help *master_help; int ret; =20 spin_lock_bh(&nf_conntrack_expect_lock); - ret =3D __nf_ct_expect_check(expect, flags); + master_help =3D nfct_help(expect->master); + if (!master_help) { + ret =3D -ESHUTDOWN; + goto out; + } + + ret =3D __nf_ct_expect_check(expect, master_help, flags); if (ret < 0) goto out; =20 - nf_ct_expect_insert(expect); + nf_ct_expect_insert(expect, master_help); =20 nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report); spin_unlock_bh(&nf_conntrack_expect_lock); diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_= ftp.c index 617f744a2e3a..02ede9be47ca 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -387,6 +387,9 @@ static int help(struct sk_buff *skb, int found =3D 0, ends_in_nl; typeof(nf_nat_ftp_hook) nf_nat_ftp; =20 + if (!ct_ftp_info) + return NF_DROP; + /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo !=3D IP_CT_ESTABLISHED && ctinfo !=3D IP_CT_ESTABLISHED_REPLY) { @@ -548,6 +551,9 @@ static int nf_ct_ftp_from_nlattr(struct nlattr *attr, s= truct nf_conn *ct) { struct nf_ct_ftp_master *ftp =3D nfct_help_data(ct); =20 + if (!ftp) + return -ENOENT; + /* This conntrack has been injected from user-space, always pick up * sequence tracking. Otherwise, the first FTP command after the * failover breaks. diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conn= track_h323_main.c index c42547284f35..2e8595f2adcd 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -75,6 +75,9 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned in= t protoff, int tpktlen; int tpktoff; =20 + if (!info) + return 0; + /* Get TCP header */ th =3D skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); if (th =3D=3D NULL) @@ -1214,6 +1217,9 @@ static int expect_q931(struct sk_buff *skb, struct nf= _conn *ct, union nf_inet_addr addr; struct nf_conntrack_expect *exp; =20 + if (!info) + return -1; + /* Look for the first related address */ for (i =3D 0; i < count; i++) { if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) && @@ -1327,6 +1333,9 @@ static int process_rrq(struct sk_buff *skb, struct nf= _conn *ct, const struct nfct_h323_nat_hooks *nathook; int ret; =20 + if (!info) + return -1; + pr_debug("nf_ct_ras: RRQ\n"); =20 ret =3D expect_q931(skb, ct, ctinfo, protoff, data, @@ -1365,6 +1374,9 @@ static int process_rcf(struct sk_buff *skb, struct nf= _conn *ct, int ret; struct nf_conntrack_expect *exp; =20 + if (!info) + return -1; + pr_debug("nf_ct_ras: RCF\n"); =20 nathook =3D rcu_dereference(nfct_h323_nat_hook); @@ -1415,6 +1427,9 @@ static int process_urq(struct sk_buff *skb, struct nf= _conn *ct, int dir =3D CTINFO2DIR(ctinfo); int ret; =20 + if (!info) + return -1; + pr_debug("nf_ct_ras: URQ\n"); =20 nathook =3D rcu_dereference(nfct_h323_nat_hook); @@ -1449,6 +1464,9 @@ static int process_arq(struct sk_buff *skb, struct nf= _conn *ct, __be16 port; union nf_inet_addr addr; =20 + if (!info) + return 0; + pr_debug("nf_ct_ras: ARQ\n"); =20 nathook =3D rcu_dereference(nfct_h323_nat_hook); diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack= _pptp.c index 759683d7de4f..6eb7f98c003e 100644 --- a/net/netfilter/nf_conntrack_pptp.c +++ b/net/netfilter/nf_conntrack_pptp.c @@ -202,6 +202,9 @@ pptp_inbound_pkt(struct sk_buff *skb, unsigned int prot= off, u_int16_t msg; __be16 cid =3D 0, pcid =3D 0; =20 + if (!info) + return NF_DROP; + msg =3D ntohs(ctlh->messageType); pr_debug("inbound control message %s\n", pptp_msg_name(msg)); =20 @@ -329,6 +332,9 @@ pptp_outbound_pkt(struct sk_buff *skb, unsigned int pro= toff, u_int16_t msg; __be16 cid =3D 0, pcid =3D 0; =20 + if (!info) + return NF_DROP; + msg =3D ntohs(ctlh->messageType); pr_debug("outbound control message %s\n", pptp_msg_name(msg)); =20 @@ -447,6 +453,9 @@ conntrack_pptp_help(struct sk_buff *skb, unsigned int p= rotoff, int ret; u_int16_t msg; =20 + if (!info) + return NF_DROP; + #if IS_ENABLED(CONFIG_NF_NAT) if (!nf_ct_is_confirmed(ct) && (ct->status & IPS_NAT_MASK)) { struct nf_conn_nat *nat =3D nf_ct_ext_find(ct, NF_CT_EXT_NAT); diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conn= track_proto_gre.c index dcff889b574e..29ac81658602 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -94,6 +94,10 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_con= ntrack_dir dir, struct nf_ct_pptp_master *ct_pptp_info =3D nfct_help_data(ct); struct nf_ct_gre_keymap **kmp, *km; =20 + if (!ct_pptp_info) + return false; + + kmp =3D &ct_pptp_info->keymap[dir]; if (*kmp) { /* check whether it's a retransmission */ @@ -129,6 +133,9 @@ void nf_ct_gre_keymap_destroy(struct nf_conn *ct) struct nf_ct_pptp_master *ct_pptp_info =3D nfct_help_data(ct); enum ip_conntrack_dir dir; =20 + if (!ct_pptp_info) + return; + pr_debug("entering for ct %p\n", ct); =20 spin_lock_bh(&keymap_lock); @@ -323,6 +330,9 @@ void gre_pptp_destroy_siblings(struct nf_conn *ct) const struct nf_ct_pptp_master *ct_pptp_info =3D nfct_help_data(ct); struct nf_conntrack_tuple t; =20 + if (!ct_pptp_info) + return; + nf_ct_gre_keymap_destroy(ct); =20 /* try original (pns->pac) tuple */ diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack= _sane.c index 13dc421fc4f5..9cf4a22eca4a 100644 --- a/net/netfilter/nf_conntrack_sane.c +++ b/net/netfilter/nf_conntrack_sane.c @@ -74,6 +74,9 @@ static int help(struct sk_buff *skb, struct sane_reply_net_start repl; } buf; =20 + if (!ct_sane_info) + return NF_DROP; + /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo !=3D IP_CT_ESTABLISHED && ctinfo !=3D IP_CT_ESTABLISHED_REPLY) diff --git a/net/netfilter/nf_conntrack_seqadj.c b/net/netfilter/nf_conntra= ck_seqadj.c index b7e99f34dfce..220216a4edc5 100644 --- a/net/netfilter/nf_conntrack_seqadj.c +++ b/net/netfilter/nf_conntrack_seqadj.c @@ -18,9 +18,12 @@ int nf_ct_seqadj_init(struct nf_conn *ct, enum ip_conntr= ack_info ctinfo, return 0; =20 spin_lock_bh(&ct->lock); - set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); - seqadj =3D nfct_seqadj(ct); + if (!seqadj) { + spin_unlock_bh(&ct->lock); + return 0; + } + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); this_way =3D &seqadj->seq[dir]; this_way->offset_before =3D off; this_way->offset_after =3D off; @@ -39,10 +42,8 @@ int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntra= ck_info ctinfo, if (off =3D=3D 0) return 0; =20 - if (unlikely(!seqadj)) { - WARN_ONCE(1, "Missing nfct_seqadj_ext_add() setup call\n"); + if (unlikely(!seqadj)) return 0; - } =20 set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); =20 @@ -125,6 +126,9 @@ static unsigned int nf_ct_sack_adjust(struct sk_buff *s= kb, struct nf_conn_seqadj *seqadj =3D nfct_seqadj(ct); unsigned int dir, optoff, optend; =20 + if (!seqadj) + return 0; + optoff =3D protoff + sizeof(struct tcphdr); optend =3D protoff + tcph->doff * 4; =20 @@ -175,6 +179,9 @@ int nf_ct_seq_adjust(struct sk_buff *skb, struct nf_ct_seqadj *this_way, *other_way; int res =3D 1; =20 + if (!seqadj) + return 0; + this_way =3D &seqadj->seq[dir]; other_way =3D &seqadj->seq[!dir]; =20 diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_= sip.c index 4f975b83c84f..366f6c062801 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -887,6 +887,9 @@ static int refresh_signalling_expectation(struct nf_con= n *ct, struct hlist_node *next; int found =3D 0; =20 + if (!help) + return 0; + spin_lock_bh(&nf_conntrack_expect_lock); hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) { if (exp->class !=3D SIP_EXPECT_SIGNALLING || @@ -910,6 +913,9 @@ static void flush_expectations(struct nf_conn *ct, bool= media) struct nf_conntrack_expect *exp; struct hlist_node *next; =20 + if (!help) + return; + spin_lock_bh(&nf_conntrack_expect_lock); hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) { if ((exp->class !=3D SIP_EXPECT_SIGNALLING) ^ media) @@ -940,6 +946,11 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, = unsigned int protoff, u_int16_t base_port; __be16 rtp_port, rtcp_port; const struct nf_nat_sip_hooks *hooks; + struct nf_conn_help *help; + + help =3D nfct_help(ct); + if (!help) + return NF_DROP; =20 saddr =3D NULL; if (sip_direct_media) { @@ -1005,7 +1016,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,= unsigned int protoff, exp =3D __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple); =20 if (!exp || exp->master =3D=3D ct || - exp->helper !=3D nfct_help(ct)->helper || + exp->helper !=3D help->helper || exp->class !=3D class) break; #if IS_ENABLED(CONFIG_NF_NAT) @@ -1230,6 +1241,9 @@ static int process_invite_response(struct sk_buff *sk= b, unsigned int protoff, struct nf_conn *ct =3D nf_ct_get(skb, &ctinfo); struct nf_ct_sip_master *ct_sip_info =3D nfct_help_data(ct); =20 + if (!ct_sip_info) + return NF_DROP; + if ((code >=3D 100 && code <=3D 199) || (code >=3D 200 && code <=3D 299)) return process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); @@ -1247,6 +1261,9 @@ static int process_update_response(struct sk_buff *sk= b, unsigned int protoff, struct nf_conn *ct =3D nf_ct_get(skb, &ctinfo); struct nf_ct_sip_master *ct_sip_info =3D nfct_help_data(ct); =20 + if (!ct_sip_info) + return NF_DROP; + if ((code >=3D 100 && code <=3D 199) || (code >=3D 200 && code <=3D 299)) return process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); @@ -1264,6 +1281,9 @@ static int process_prack_response(struct sk_buff *skb= , unsigned int protoff, struct nf_conn *ct =3D nf_ct_get(skb, &ctinfo); struct nf_ct_sip_master *ct_sip_info =3D nfct_help_data(ct); =20 + if (!ct_sip_info) + return NF_DROP; + if ((code >=3D 100 && code <=3D 199) || (code >=3D 200 && code <=3D 299)) return process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); @@ -1282,6 +1302,9 @@ static int process_invite_request(struct sk_buff *skb= , unsigned int protoff, struct nf_ct_sip_master *ct_sip_info =3D nfct_help_data(ct); unsigned int ret; =20 + if (!ct_sip_info) + return NF_DROP; + flush_expectations(ct, true); ret =3D process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); if (ret =3D=3D NF_ACCEPT) @@ -1319,11 +1342,15 @@ static int process_register_request(struct sk_buff = *skb, unsigned int protoff, union nf_inet_addr *saddr, daddr; const struct nf_nat_sip_hooks *hooks; struct nf_conntrack_helper *helper; + struct nf_conn_help *help; __be16 port; u8 proto; unsigned int expires =3D 0; int ret; =20 + if (!ct_sip_info) + return NF_DROP; + /* Expected connections can not register again. */ if (ct->status & IPS_EXPECTED) return NF_ACCEPT; @@ -1369,7 +1396,11 @@ static int process_register_request(struct sk_buff *= skb, unsigned int protoff, goto store_cseq; } =20 - helper =3D rcu_dereference(nfct_help(ct)->helper); + help =3D nfct_help(ct); + if (!help) + return NF_DROP; + + helper =3D rcu_dereference(help->helper); if (!helper) return NF_DROP; =20 @@ -1424,6 +1455,9 @@ static int process_register_response(struct sk_buff *= skb, unsigned int protoff, unsigned int expires =3D 0; int in_contact =3D 0, ret; =20 + if (!ct_sip_info) + return NF_DROP; + /* According to RFC 3261, "UAs MUST NOT send a new registration until * they have received a final response from the registrar for the * previous one or the previous REGISTER request has timed out". @@ -1553,6 +1587,9 @@ static int process_sip_request(struct sk_buff *skb, u= nsigned int protoff, union nf_inet_addr addr; __be16 port; =20 + if (!ct_sip_info) + return NF_DROP; + /* Many Cisco IP phones use a high source port for SIP requests, but * listen for the response on port 5060. If we are the local * router for one of these phones, save the port number from the diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c index 6b00c81084fe..9c4f6a339395 100644 --- a/net/netfilter/nf_nat_sip.c +++ b/net/netfilter/nf_nat_sip.c @@ -106,6 +106,9 @@ static int map_addr(struct sk_buff *skb, unsigned int p= rotoff, union nf_inet_addr newaddr; __be16 newport; =20 + if (!ct_sip_info) + return 0; + if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, addr) && ct->tuplehash[dir].tuple.src.u.udp.port =3D=3D port) { newaddr =3D ct->tuplehash[!dir].tuple.dst.u3; @@ -158,6 +161,9 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, uns= igned int protoff, __be16 port; int request, in_header; =20 + if (!ct_sip_info) + return NF_DROP; + /* Basic rules: requests and responses. */ if (strncasecmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) !=3D 0) { if (ct_sip_parse_request(ct, *dptr, *datalen, @@ -342,6 +348,9 @@ static void nf_nat_sip_expected(struct nf_conn *ct, int range_set_for_snat =3D 0; struct nf_nat_range2 range; =20 + if (!help) + return; + /* This must be a fresh one. */ BUG_ON(ct->status & IPS_NAT_DONE_MASK); =20 @@ -406,6 +415,9 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *s= kb, unsigned int protoff, char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; unsigned int buflen; =20 + if (!ct_sip_info) + return NF_DROP; + /* Connection will come from reply */ if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3)) diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_c= thelper.c index daf8ccbb6433..4954d473d27f 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c @@ -98,6 +98,9 @@ nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_= conn *ct) struct nf_conn_help *help =3D nfct_help(ct); const struct nf_conntrack_helper *helper; =20 + if (!help) + return -EINVAL; + if (attr =3D=3D NULL) return -EINVAL; =20 @@ -115,6 +118,9 @@ nfnl_cthelper_to_nlattr(struct sk_buff *skb, const stru= ct nf_conn *ct) const struct nf_conn_help *help =3D nfct_help(ct); const struct nf_conntrack_helper *helper; =20 + if (!help) + return 0; + helper =3D rcu_dereference(help->helper); if (helper && helper->data_len && nla_put(skb, CTA_HELP_INFO, helper->data_len, &help->data)) --=20 2.55.0 From nobody Thu Sep 24 22:57:52 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3D6D651FCA1; Fri, 18 Sep 2026 18:25:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789755937; cv=none; b=MraNb7TpYZM+KWko//cHU33cWT00pnJHZO1i1YWZTNK/9S2N0kI/5/U8QlZSdq3y4jGgFG/SCJt3JFmG6qM1/gJL9SFo/hjr35KJseXu2A7n9LVb2bfu9Bgcm69Qpzgg0er9hEyM5I9KR+BQTvquEL87+87Dw/ZoSYwEDrDGLFw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789755937; c=relaxed/simple; bh=4PP/ihN1xwSiEPSDW1srwU5VM/fHIbs/RQDXYWDHOmA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HSmoYaChb3nM2gOaRqB6lX5W6GQyGALdqZCOjjoWwakBieQa8wctei9KJJOxSnio9bLacySl5d1q+PA6VmBmEp6UawjCSxvTb7EJNFnqFv99siAjtOfezp2Tt1VAFiLlcBUh3muVcZJLmR3jOiyuJOyB6ZkqoyHFgIGdvJ2xeB0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=l7LLx40k; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="l7LLx40k" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 7898E4E407BD; Fri, 18 Sep 2026 18:25:31 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 469C060649; Fri, 18 Sep 2026 18:25:31 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 3C00510328E70; Fri, 18 Sep 2026 20:25:26 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1789755930; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=N60O7awveG74am11xhmaN5FDFaX+BPa2hQwt2gJN64o=; b=l7LLx40kltatLQaiKsS6VcfRz1VLWVIjUz2zi/Deo5Vnzrv6Ib/+trP60BTQJodyHLK1/5 KHFs+7eXKVwHvgagFDnRp/4oHTpSYlk2F7DcjDMn007UunMX+Hf8bNCbTWSIfkggqpWUT9 4pwi4tdxV7K+Lo+tk0DDgUe+kHXB18WnC5VsX4aFqW4oxGnSi5K2qhTyRxZvLqjNd5M45L Sm5Vayg6mCNYuqnLULcRu4gxAMaOByexLc8jVrxV98ISyW2ecG2ISjYR8Rk6sZsEAGJiNv txCpcoG70bis+9MWGAq9I02k8JrRJRzWmaK+3RWeaS8rcdSiL7yBddeLUHelwg== From: "Miguel Gazquez (Schneider Electric)" Date: Fri, 18 Sep 2026 20:24:55 +0200 Subject: [PATCH 6.1.y 3/3] netfilter: nf_conntrack_expect: use conntrack GC to reap expectations Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260918-cve-2026-80668-6-1-v1-3-7a8667286d67@bootlin.com> References: <20260918-cve-2026-80668-6-1-v1-0-7a8667286d67@bootlin.com> In-Reply-To: <20260918-cve-2026-80668-6-1-v1-0-7a8667286d67@bootlin.com> To: stable@vger.kernel.org, Pablo Neira Ayuso , Jozsef Kadlecsik , Florian Westphal , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Hideaki YOSHIFUJI , David Ahern Cc: Benjamin Robin , netfilter-devel@vger.kernel.org, coreteam@netfilter.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, "Miguel Gazquez (Schneider Electric)" X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1789755899; l=22826; i=miguel.gazquez@bootlin.com; s=20250708; h=from:subject:message-id; bh=oHb38BtlA5AHDbVHwAgkk5FvVJTbqSmjPbSkWYWyyW4=; b=6xFgx/egat01cGMJVPVZQrRIWUj1Hsz0mMl224fWysVrupX+415EFvfLLprhbN3Ur/9K94Rjn yd/t7fReQNBB8u5xcos9/H4P48L27xOmvEjyAwNz8Rs5oXg0yIS5GvK X-Developer-Key: i=miguel.gazquez@bootlin.com; a=ed25519; pk=k/2KI9jkmayaF0ghZ8QYUH9Wm/kFHDhl8QoZ0RHbr4w= X-Last-TLS-Session-Version: TLSv1.3 From: Pablo Neira Ayuso This patch replaces the timer API by GC worker approach for expectations, as it already happened in many other subsystems. Use the existing conntrack GC worker to iterate over the local list of expectations in the master conntrack to reap expired expectations. Check IPS_HELPER_BIT to run GC for expectations, set it on for nft_ct expectation which nevers sets it. Hold the expectation spinlock while iterating over the master conntrack expectation list to synchronize with nf_ct_remove_expectations(). This also performs runtime packet path garbage collection through the expectation insertion and lookup functions while walking over one of the chains of the global expectation hashtables. Unconfirmed conntrack entries are skipped since ct->ext can be reallocated and dying are skipped since those will be gone soon. Set on IPS_HELPER_BIT if the helper ct extension is added, then the new GC worker does not need to bump the ct refcount to check if the ct->ext helper is available. This removes the extra bump on the refcount for expectation timers, this allows to remove several nf_ct_expect_put() calls after the unlink, after this update only refcount remains at 1 while on the expectation hashes. This patch implicitly addresses a race with the existing timer API allowing an expectation to access a stale exp->master pointer which has been already released when expectation removal loses races with an expiring timer, ie. timer_del() reporting false. Add a new NF_CT_EXPECT_DEAD flag to reap this expectation via GC. This is needed by nf_conntrack_unexpect_related() which is called in error paths to invalidate newly created expectations that has been added into the hashes. These expectactions cannot be inmediately released as GC or nf_ct_remove_expectations() could race to make it. On expectation insert, the runtime GC reaps stale expectations before checking the expectation limit set by policy. Set current timestamp in nf_ct_expect_alloc(), then add the expectation policy timeout (or custom timeout specified added on top of this) to specify the expectation lifetime. Fixes: bffcaad9afdf ("netfilter: ctnetlink: ensure safe access to master co= nntrack") Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_expect.h | 16 ++- include/uapi/linux/netfilter/nf_conntrack_common.h | 1 + net/netfilter/nf_conntrack_core.c | 33 ++++- net/netfilter/nf_conntrack_expect.c | 145 ++++++++++-------= ---- net/netfilter/nf_conntrack_h323_main.c | 4 +- net/netfilter/nf_conntrack_helper.c | 10 +- net/netfilter/nf_conntrack_netlink.c | 22 ++-- net/netfilter/nf_conntrack_sip.c | 13 +- net/netfilter/nft_ct.c | 3 +- 9 files changed, 139 insertions(+), 108 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netf= ilter/nf_conntrack_expect.h index 80f50fd0f7ad..be4a120d549e 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -54,8 +54,8 @@ struct nf_conntrack_expect { /* The conntrack of the master connection */ struct nf_conn *master; =20 - /* Timer function; deletes the expectation. */ - struct timer_list timeout; + /* jiffies32 when this expectation expires */ + u32 timeout; =20 #if IS_ENABLED(CONFIG_NF_NAT) union nf_inet_addr saved_addr; @@ -69,6 +69,14 @@ struct nf_conntrack_expect { struct rcu_head rcu; }; =20 +static inline bool nf_ct_exp_is_expired(const struct nf_conntrack_expect *= exp) +{ + if (READ_ONCE(exp->flags) & NF_CT_EXPECT_DEAD) + return true; + + return (__s32)(READ_ONCE(exp->timeout) - nfct_time_stamp) <=3D 0; +} + static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp) { return read_pnet(&exp->net); @@ -130,7 +138,6 @@ static inline void nf_ct_unlink_expect(struct nf_conntr= ack_expect *exp) =20 void nf_ct_remove_expectations(struct nf_conn *ct); void nf_ct_unexpect_related(struct nf_conntrack_expect *exp); -bool nf_ct_remove_expect(struct nf_conntrack_expect *exp); =20 void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect = *e, void *data), void *data); void nf_ct_expect_iterate_net(struct net *net, @@ -153,5 +160,8 @@ static inline int nf_ct_expect_related(struct nf_conntr= ack_expect *expect, return nf_ct_expect_related_report(expect, 0, 0, flags); } =20 +struct nf_conn_help; +void nf_ct_expectation_gc(struct nf_conn_help *master_help); + #endif /*_NF_CONNTRACK_EXPECT_H*/ =20 diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/u= api/linux/netfilter/nf_conntrack_common.h index 56b6b60a814f..ee51045ae1d6 100644 --- a/include/uapi/linux/netfilter/nf_conntrack_common.h +++ b/include/uapi/linux/netfilter/nf_conntrack_common.h @@ -160,6 +160,7 @@ enum ip_conntrack_expect_events { #define NF_CT_EXPECT_USERSPACE 0x4 =20 #ifdef __KERNEL__ +#define NF_CT_EXPECT_DEAD 0x8 #define NF_CT_EXPECT_MASK (NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE = | \ NF_CT_EXPECT_USERSPACE) #endif diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack= _core.c index 342627b0d32b..a782836c79ba 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1493,6 +1493,31 @@ static bool gc_worker_can_early_drop(const struct nf= _conn *ct) return false; } =20 +static void nf_ct_help_gc(struct nf_conn *ct) +{ + struct nf_conn_help *help; + + if (!refcount_inc_not_zero(&ct->ct_general.use)) + return; + + /* load ->status after refcount increase */ + smp_acquire__after_ctrl_dep(); + + if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct)) { + nf_ct_put(ct); + return; + } + + /* re-check helper due to SLAB_TYPESAFE_BY_RCU */ + if (test_bit(IPS_HELPER_BIT, &ct->status)) { + help =3D nfct_help(ct); + if (help) + nf_ct_expectation_gc(help); + } + + nf_ct_put(ct); +} + static void gc_worker(struct work_struct *work) { unsigned int i, hashsz, nf_conntrack_max95 =3D 0; @@ -1570,7 +1595,13 @@ static void gc_worker(struct work_struct *work) expires =3D (expires - (long)next_run) / ++count; next_run +=3D expires; =20 - if (nf_conntrack_max95 =3D=3D 0 || gc_worker_skip_ct(tmp)) + if (gc_worker_skip_ct(tmp)) + continue; + + if (test_bit(IPS_HELPER_BIT, &tmp->status)) + nf_ct_help_gc(tmp); + + if (nf_conntrack_max95 =3D=3D 0) continue; =20 net =3D nf_ct_net(tmp); diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntra= ck_expect.c index e0b99cffe1ee..acf6e3490f8c 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -43,6 +43,24 @@ unsigned int nf_ct_expect_max __read_mostly; static struct kmem_cache *nf_ct_expect_cachep __read_mostly; static siphash_aligned_key_t nf_ct_expect_hashrnd; =20 +void nf_ct_expectation_gc(struct nf_conn_help *master_help) +{ + struct nf_conntrack_expect *exp; + struct hlist_node *next; + + if (hlist_empty(&master_help->expectations)) + return; + + spin_lock_bh(&nf_conntrack_expect_lock); + hlist_for_each_entry_safe(exp, next, &master_help->expectations, lnode) { + if (!nf_ct_exp_is_expired(exp)) + continue; + + nf_ct_unlink_expect(exp); + } + spin_unlock_bh(&nf_conntrack_expect_lock); +} + /* nf_conntrack_expect helper functions */ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp, u32 portid, int report) @@ -52,7 +70,6 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expec= t *exp, struct nf_conntrack_net *cnet; =20 lockdep_nfct_expect_lock_held(); - WARN_ON_ONCE(timer_pending(&exp->timeout)); =20 hlist_del_rcu(&exp->hnode); =20 @@ -70,16 +87,6 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expe= ct *exp, } EXPORT_SYMBOL_GPL(nf_ct_unlink_expect_report); =20 -static void nf_ct_expectation_timed_out(struct timer_list *t) -{ - struct nf_conntrack_expect *exp =3D from_timer(exp, t, timeout); - - spin_lock_bh(&nf_conntrack_expect_lock); - nf_ct_unlink_expect(exp); - spin_unlock_bh(&nf_conntrack_expect_lock); - nf_ct_expect_put(exp); -} - static unsigned int nf_ct_expect_dst_hash(const struct net *n, const struc= t nf_conntrack_tuple *tuple) { struct { @@ -117,19 +124,6 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple, nf_ct_exp_zone_equal_any(i, zone); } =20 -bool nf_ct_remove_expect(struct nf_conntrack_expect *exp) -{ - lockdep_nfct_expect_lock_held(); - - if (del_timer(&exp->timeout)) { - nf_ct_unlink_expect(exp); - nf_ct_expect_put(exp); - return true; - } - return false; -} -EXPORT_SYMBOL_GPL(nf_ct_remove_expect); - struct nf_conntrack_expect * __nf_ct_expect_find(struct net *net, const struct nf_conntrack_zone *zone, @@ -144,6 +138,8 @@ __nf_ct_expect_find(struct net *net, =20 h =3D nf_ct_expect_dst_hash(net, tuple); hlist_for_each_entry_rcu(i, &nf_ct_expect_hash[h], hnode) { + if (nf_ct_exp_is_expired(i)) + continue; if (nf_ct_exp_equal(tuple, i, zone, net)) return i; } @@ -178,6 +174,7 @@ nf_ct_find_expectation(struct net *net, { struct nf_conntrack_net *cnet =3D nf_ct_pernet(net); struct nf_conntrack_expect *i, *exp =3D NULL; + struct hlist_node *next; unsigned int h; =20 lockdep_nfct_expect_lock_held(); @@ -186,7 +183,11 @@ nf_ct_find_expectation(struct net *net, return NULL; =20 h =3D nf_ct_expect_dst_hash(net, tuple); - hlist_for_each_entry(i, &nf_ct_expect_hash[h], hnode) { + hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) { + if (nf_ct_exp_is_expired(i)) { + nf_ct_unlink_expect(i); + continue; + } if (!(i->flags & NF_CT_EXPECT_INACTIVE) && nf_ct_exp_equal(tuple, i, zone, net)) { exp =3D i; @@ -196,13 +197,16 @@ nf_ct_find_expectation(struct net *net, if (!exp) return NULL; =20 + if (!refcount_inc_not_zero(&exp->use)) + return NULL; + /* If master is not in hash table yet (ie. packet hasn't left this machine yet), how can other end know about expected? Hence these are not the droids you are looking for (if master ct never got confirmed, we'd hold a reference to it and weird things would happen to future packets). */ if (!nf_ct_is_confirmed(exp->master)) - return NULL; + goto err_release_exp; =20 /* Avoid race with other CPUs, that for exp->master ct, is * about to invoke ->destroy(), or nf_ct_delete() via timeout @@ -214,18 +218,17 @@ nf_ct_find_expectation(struct net *net, */ if (unlikely(nf_ct_is_dying(exp->master) || !refcount_inc_not_zero(&exp->master->ct_general.use))) - return NULL; + goto err_release_exp; =20 - if (exp->flags & NF_CT_EXPECT_PERMANENT || !unlink) { - refcount_inc(&exp->use); - return exp; - } else if (del_timer(&exp->timeout)) { - nf_ct_unlink_expect(exp); + if (exp->flags & NF_CT_EXPECT_PERMANENT || !unlink) return exp; - } - /* Undo exp->master refcnt increase, if del_timer() failed */ - nf_ct_put(exp->master); =20 + nf_ct_unlink_expect(exp); + + return exp; + +err_release_exp: + nf_ct_expect_put(exp); return NULL; } =20 @@ -241,9 +244,8 @@ void nf_ct_remove_expectations(struct nf_conn *ct) return; =20 spin_lock_bh(&nf_conntrack_expect_lock); - hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) { - nf_ct_remove_expect(exp); - } + hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) + nf_ct_unlink_expect(exp); spin_unlock_bh(&nf_conntrack_expect_lock); } EXPORT_SYMBOL_GPL(nf_ct_remove_expectations); @@ -292,7 +294,7 @@ static bool master_matches(const struct nf_conntrack_ex= pect *a, void nf_ct_unexpect_related(struct nf_conntrack_expect *exp) { spin_lock_bh(&nf_conntrack_expect_lock); - nf_ct_remove_expect(exp); + WRITE_ONCE(exp->flags, exp->flags | NF_CT_EXPECT_DEAD); spin_unlock_bh(&nf_conntrack_expect_lock); } EXPORT_SYMBOL_GPL(nf_ct_unexpect_related); @@ -308,6 +310,7 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct n= f_conn *me) if (!new) return NULL; =20 + new->timeout =3D nfct_time_stamp; new->master =3D me; refcount_set(&new->use, 1); return new; @@ -413,17 +416,12 @@ static void nf_ct_expect_insert(struct nf_conntrack_e= xpect *exp, struct net *net =3D nf_ct_exp_net(exp); unsigned int h =3D nf_ct_expect_dst_hash(net, &exp->tuple); =20 - /* two references : one for hash insert, one for the timer */ - refcount_add(2, &exp->use); + refcount_inc(&exp->use); =20 - timer_setup(&exp->timeout, nf_ct_expectation_timed_out, 0); helper =3D rcu_dereference_protected(master_help->helper, lockdep_is_held(&nf_conntrack_expect_lock)); - if (helper) { - exp->timeout.expires =3D jiffies + - helper->expect_policy[exp->class].timeout * HZ; - } - add_timer(&exp->timeout); + if (helper) + exp->timeout +=3D helper->expect_policy[exp->class].timeout * HZ; =20 hlist_add_head_rcu(&exp->lnode, &master_help->expectations); master_help->expecting[exp->class]++; @@ -435,19 +433,26 @@ static void nf_ct_expect_insert(struct nf_conntrack_e= xpect *exp, NF_CT_STAT_INC(net, expect_create); } =20 -/* Race with expectations being used means we could have none to find; OK.= */ static void evict_oldest_expect(struct nf_conn_help *master_help, - struct nf_conntrack_expect *new) + struct nf_conntrack_expect *new, + const struct nf_conntrack_expect_policy *p) { struct nf_conntrack_expect *exp, *last =3D NULL; + struct hlist_node *next; =20 - hlist_for_each_entry(exp, &master_help->expectations, lnode) { + hlist_for_each_entry_safe(exp, next, &master_help->expectations, lnode) { + if (nf_ct_exp_is_expired(exp)) { + nf_ct_unlink_expect(exp); + continue; + } if (exp->class =3D=3D new->class) last =3D exp; } =20 - if (last) - nf_ct_remove_expect(last); + /* Still worth to evict oldest expectation after garbage collection? */ + if (last && + master_help->expecting[last->class] >=3D p->max_expected) + nf_ct_unlink_expect(last); } =20 static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect, @@ -467,14 +472,18 @@ static inline int __nf_ct_expect_check(struct nf_conn= track_expect *expect, =20 h =3D nf_ct_expect_dst_hash(net, &expect->tuple); hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) { + if (nf_ct_exp_is_expired(i)) { + nf_ct_unlink_expect(i); + continue; + } if (master_matches(i, expect, flags) && expect_matches(i, expect)) { if (i->class !=3D expect->class || i->master !=3D expect->master) return -EALREADY; =20 - if (nf_ct_remove_expect(i)) - break; + nf_ct_unlink_expect(i); + break; } else if (expect_clash(i, expect)) { ret =3D -EBUSY; goto out; @@ -486,14 +495,8 @@ static inline int __nf_ct_expect_check(struct nf_connt= rack_expect *expect, if (helper) { p =3D &helper->expect_policy[expect->class]; if (p->max_expected && - master_help->expecting[expect->class] >=3D p->max_expected) { - evict_oldest_expect(master_help, expect); - if (master_help->expecting[expect->class] - >=3D p->max_expected) { - ret =3D -EMFILE; - goto out; - } - } + master_help->expecting[expect->class] >=3D p->max_expected) + evict_oldest_expect(master_help, expect, p); } =20 cnet =3D nf_ct_pernet(net); @@ -547,10 +550,8 @@ void nf_ct_expect_iterate_destroy(bool (*iter)(struct = nf_conntrack_expect *e, vo hlist_for_each_entry_safe(exp, next, &nf_ct_expect_hash[i], hnode) { - if (iter(exp, data) && del_timer(&exp->timeout)) { + if (iter(exp, data)) nf_ct_unlink_expect(exp); - nf_ct_expect_put(exp); - } } } =20 @@ -577,10 +578,8 @@ void nf_ct_expect_iterate_net(struct net *net, if (!net_eq(nf_ct_exp_net(exp), net)) continue; =20 - if (iter(exp, data) && del_timer(&exp->timeout)) { + if (iter(exp, data)) nf_ct_unlink_expect_report(exp, portid, report); - nf_ct_expect_put(exp); - } } } =20 @@ -657,17 +656,17 @@ static int exp_seq_show(struct seq_file *s, void *v) struct net *net =3D seq_file_net(s); struct hlist_node *n =3D v; char *delim =3D ""; + __s32 timeout; =20 expect =3D hlist_entry(n, struct nf_conntrack_expect, hnode); =20 if (!net_eq(nf_ct_exp_net(expect), net)) return 0; + if (nf_ct_exp_is_expired(expect)) + return 0; =20 - if (expect->timeout.function) - seq_printf(s, "%ld ", timer_pending(&expect->timeout) - ? (long)(expect->timeout.expires - jiffies)/HZ : 0); - else - seq_puts(s, "- "); + timeout =3D (__s32)(READ_ONCE(expect->timeout) - nfct_time_stamp) / HZ; + seq_printf(s, "%d ", timeout > 0 ? timeout : 0); seq_printf(s, "l3proto =3D %u proto=3D%u ", expect->tuple.src.l3num, expect->tuple.dst.protonum); diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conn= track_h323_main.c index 2e8595f2adcd..1f979268057f 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -1408,8 +1408,8 @@ static int process_rcf(struct sk_buff *skb, struct nf= _conn *ct, "timeout to %u seconds for", info->timeout); nf_ct_dump_tuple(&exp->tuple); - mod_timer_pending(&exp->timeout, - jiffies + info->timeout * HZ); + WRITE_ONCE(exp->timeout, + nfct_time_stamp + (info->timeout * HZ)); } spin_unlock_bh(&nf_conntrack_expect_lock); } diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntra= ck_helper.c index efa080cb1709..b16a45856bdc 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -178,10 +178,10 @@ nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp) struct nf_conn_help *help; =20 help =3D nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp); - if (help) + if (help) { + __set_bit(IPS_HELPER_BIT, &ct->status); INIT_HLIST_HEAD(&help->expectations); - else - pr_debug("failed to add helper extension area"); + } return help; } EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); @@ -205,10 +205,8 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, stru= ct nf_conn *tmpl, return 0; =20 help =3D nfct_help(tmpl); - if (help !=3D NULL) { + if (help) helper =3D rcu_dereference(help->helper); - set_bit(IPS_HELPER_BIT, &ct->status); - } =20 help =3D nfct_help(ct); =20 diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntr= ack_netlink.c index 55bc5626b967..e66e8a32a619 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -2997,8 +2997,8 @@ static int ctnetlink_exp_dump_expect(struct sk_buff *skb, const struct nf_conntrack_expect *exp) { + __s32 timeout =3D (__s32)(READ_ONCE(exp->timeout) - nfct_time_stamp) / HZ; struct nf_conn *master =3D exp->master; - long timeout =3D ((long)exp->timeout.expires - (long)jiffies) / HZ; struct nf_conntrack_helper *helper; #if IS_ENABLED(CONFIG_NF_NAT) struct nlattr *nest_parms; @@ -3161,6 +3161,9 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct = netlink_callback *cb) restart: hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]], hnode) { + if (nf_ct_exp_is_expired(exp)) + continue; + if (l3proto && exp->tuple.src.l3num !=3D l3proto) continue; =20 @@ -3439,11 +3442,8 @@ static int ctnetlink_del_expect(struct sk_buff *skb, } =20 /* after list removal, usage count =3D=3D 1 */ - if (del_timer(&exp->timeout)) { - nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid, - nlmsg_report(info->nlh)); - nf_ct_expect_put(exp); - } + nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid, + nlmsg_report(info->nlh)); spin_unlock_bh(&nf_conntrack_expect_lock); /* have to put what we 'get' above. * after this line usage count =3D=3D 0 */ @@ -3467,14 +3467,10 @@ static int ctnetlink_change_expect(struct nf_conntrack_expect *x, const struct nlattr * const cda[]) { - if (cda[CTA_EXPECT_TIMEOUT]) { - if (!del_timer(&x->timeout)) - return -ETIME; + if (cda[CTA_EXPECT_TIMEOUT]) + WRITE_ONCE(x->timeout, nfct_time_stamp + + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ); =20 - x->timeout.expires =3D jiffies + - ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ; - add_timer(&x->timeout); - } return 0; } =20 diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_= sip.c index 366f6c062801..51ea8a32139a 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -897,11 +897,10 @@ static int refresh_signalling_expectation(struct nf_c= onn *ct, exp->tuple.dst.protonum !=3D proto || exp->tuple.dst.u.udp.port !=3D port) continue; - if (mod_timer_pending(&exp->timeout, jiffies + expires * HZ)) { - exp->flags &=3D ~NF_CT_EXPECT_INACTIVE; - found =3D 1; - break; - } + WRITE_ONCE(exp->timeout, nfct_time_stamp + (expires * HZ)); + WRITE_ONCE(exp->flags, exp->flags & ~NF_CT_EXPECT_INACTIVE); + found =3D 1; + break; } spin_unlock_bh(&nf_conntrack_expect_lock); return found; @@ -920,8 +919,7 @@ static void flush_expectations(struct nf_conn *ct, bool= media) hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) { if ((exp->class !=3D SIP_EXPECT_SIGNALLING) ^ media) continue; - if (!nf_ct_remove_expect(exp)) - continue; + nf_ct_unlink_expect(exp); if (!media) break; } @@ -1416,7 +1414,6 @@ static int process_register_request(struct sk_buff *s= kb, unsigned int protoff, =20 nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), saddr, &daddr, proto, NULL, &port); - exp->timeout.expires =3D sip_timeout * HZ; rcu_assign_pointer(exp->assign_helper, helper); exp->flags =3D NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; =20 diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index e2ef510ab048..3cce87d8d442 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -1160,7 +1160,6 @@ static void nft_ct_helper_obj_eval(struct nft_object = *obj, help =3D nf_ct_helper_ext_add(ct, GFP_ATOMIC); if (help) { rcu_assign_pointer(help->helper, to_assign); - set_bit(IPS_HELPER_BIT, &ct->status); =20 if ((ct->status & IPS_NAT_MASK) && !nfct_seqadj(ct)) if (!nfct_seqadj_ext_add(ct)) @@ -1342,7 +1341,7 @@ static void nft_ct_expect_obj_eval(struct nft_object = *obj, &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, priv->l4proto, NULL, &priv->dport); - exp->timeout.expires =3D jiffies + priv->timeout * HZ; + exp->timeout +=3D priv->timeout * HZ; =20 if (nf_ct_expect_related(exp, 0) !=3D 0) regs->verdict.code =3D NF_DROP; --=20 2.55.0