From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.netfilter.org (mail.netfilter.org [217.70.190.124]) (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 01F513D16E7; Mon, 20 Apr 2026 22:02:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.190.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776722551; cv=none; b=Z3IL9sYR5Y0Q+DQP5fXce7ALmlUSGCBp9Iuu/EkcuLL/dqi/trCOQSVQvh6DMyhj6gXjZNAB2giWqtpobzFIoJjB117SW4Rtpd3VFmb2dr6P0nNZRnt15QgBNICHUL5JFzYBqIeOR0BK4LYVOT7/jEX+HA6FszGl/0QuDpnVSNU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776722551; c=relaxed/simple; bh=AgaNzu1I6apmtJBryk603dr+KoFw6oDh9jzwgMwbWF8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=p9+FCrqqfHoXTpvNaIrl/gEzr2+ZlwjO7tTlBPrkOaumN7VJt8+e4PtlbRq25V+jxYkhS+fuOsjoh/XA/GexpdwEOfiJdoYgfl+DD8RWjz0CSe6DPBctYTCATfJbP7z9bquwtMwziYwp443sjItcixsiuS/ziZWu5SH1XPtR7CU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=netfilter.org; spf=pass smtp.mailfrom=netfilter.org; dkim=pass (2048-bit key) header.d=netfilter.org header.i=@netfilter.org header.b=kz1geMoX; arc=none smtp.client-ip=217.70.190.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=netfilter.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=netfilter.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=netfilter.org header.i=@netfilter.org header.b="kz1geMoX" Received: from localhost.localdomain (mail-agni [217.70.190.124]) by mail.netfilter.org (Postfix) with ESMTPSA id 2508B60269; Tue, 21 Apr 2026 00:02:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netfilter.org; s=2025; t=1776722548; bh=PVB7UXPbS7DPHrW/VNCAqGnK0ENCpHD4L9AlwzELepY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kz1geMoX6i/wSSkOU2X07IvPq/PKB2y2cJuC8SampOUjF2JHxufN92c+KkCtesBr0 /EwDoov1XpyEVp6WhFtbRDN2iaTin1p8R565iHLuTp9R2JDaEr7TW+3/V38jr3z9U2 PQJapKY+yAP6JOgXP9SMcR59WOYBtj+WKGFx+qkXPdLc4rrULmBt1V0X8VhjTk3IF5 OMUwvmGvSM+ZmCxp/Daflj8ITJZY3LD8ZI2xaMGz5f2ZLqsLBfhKdb2X8tBrQuNSke 6LoVqC46nMbcQbrIFKNGoQDL0wzpUnjfe3ypWhS/KHDQeFKf2teOk1r+BvFDtggO/l pLHw5Ga03gutA== From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Cc: davem@davemloft.net, netdev@vger.kernel.org, kuba@kernel.org, pabeni@redhat.com, edumazet@google.com, fw@strlen.de, horms@kernel.org Subject: [PATCH net 7/8] netfilter: nfnetlink_osf: fix out-of-bounds read on option matching Date: Tue, 21 Apr 2026 00:02:14 +0200 Message-ID: <20260420220215.111510-8-pablo@netfilter.org> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260420220215.111510-1-pablo@netfilter.org> References: <20260420220215.111510-1-pablo@netfilter.org> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Fernando Fernandez Mancera In nf_osf_match(), the nf_osf_hdr_ctx structure is initialized once and passed by reference to nf_osf_match_one() for each fingerprint checked. During TCP option parsing, nf_osf_match_one() advances the shared ctx->optp pointer. If a fingerprint perfectly matches, the function returns early without restoring ctx->optp to its initial state. If the user has configured NF_OSF_LOGLEVEL_ALL, the loop continues to the next fingerprint. However, because ctx->optp was not restored, the next call to nf_osf_match_one() starts parsing from the end of the options buffer. This causes subsequent matches to read garbage data and fail immediately, making it impossible to log more than one match or logging incorrect matches. Instead of using a shared ctx->optp pointer, pass the context as a constant pointer and use a local pointer (optp) for TCP option traversal. This makes nf_osf_match_one() strictly stateless from the caller's perspective, ensuring every fingerprint check starts at the correct option offset. Fixes: 1a6a0951fc00 ("netfilter: nfnetlink_osf: add missing fmatch check") Suggested-by: Florian Westphal Signed-off-by: Fernando Fernandez Mancera Reviewed-by: Pablo Neira Ayuso Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_osf.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index 9de91fdd107c..9b209241029b 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -64,9 +64,9 @@ struct nf_osf_hdr_ctx { static bool nf_osf_match_one(const struct sk_buff *skb, const struct nf_osf_user_finger *f, int ttl_check, - struct nf_osf_hdr_ctx *ctx) + const struct nf_osf_hdr_ctx *ctx) { - const __u8 *optpinit = ctx->optp; + const __u8 *optp = ctx->optp; unsigned int check_WSS = 0; int fmatch = FMATCH_WRONG; int foptsize, optnum; @@ -95,17 +95,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, check_WSS = f->wss.wc; for (optnum = 0; optnum < f->opt_num; ++optnum) { - if (f->opt[optnum].kind == *ctx->optp) { + if (f->opt[optnum].kind == *optp) { __u32 len = f->opt[optnum].length; - const __u8 *optend = ctx->optp + len; + const __u8 *optend = optp + len; fmatch = FMATCH_OK; - switch (*ctx->optp) { + switch (*optp) { case OSFOPT_MSS: - mss = ctx->optp[3]; + mss = optp[3]; mss <<= 8; - mss |= ctx->optp[2]; + mss |= optp[2]; mss = ntohs((__force __be16)mss); break; @@ -113,7 +113,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb, break; } - ctx->optp = optend; + optp = optend; } else fmatch = FMATCH_OPT_WRONG; @@ -156,9 +156,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, } } - if (fmatch != FMATCH_OK) - ctx->optp = optpinit; - return fmatch == FMATCH_OK; } -- 2.47.3