Linux kernel -stable discussions
 help / color / mirror / Atom feed
* FAILED: patch "[PATCH] cipso: fix optlen corruption in cipso_v4_delopt()" failed to apply to 6.6-stable tree
@ 2026-11-10  1:11 Sasha Levin
  2026-11-12  2:39 ` [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options Sasha Levin
  0 siblings, 1 reply; 5+ messages in thread
From: Sasha Levin @ 2026-11-10  1:11 UTC (permalink / raw)
  To: q.h.hack.winter, paul, davem; +Cc: stable

The patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 1f1f8e8c5176234fa31858cd25f2e9b88aac0a45
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '20261109201138-failed-6.6-1f1f8e8c5176@kernel.org' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'

Thanks,
Sasha

------------------ original commit in Linus's tree ------------------

From 1f1f8e8c5176234fa31858cd25f2e9b88aac0a45 Mon Sep 17 00:00:00 2001
From: Qihang <q.h.hack.winter@gmail.com>
Date: Thu, 29 Oct 2026 11:39:42 +0800
Subject: [PATCH] cipso: fix optlen corruption in cipso_v4_delopt()

cipso_v4_delopt() recomputes the option length by walking the option
buffer after the CIPSO option has been moved out.  The walk then reads
the stale bytes at the tail of the buffer as option data, and a crafted
setsockopt(IP_OPTIONS) buffer can make it treat one of them as an option
length, increasing opt->opt.optlen beyond the valid option data.

The corrupted length stays on the socket and is later used as the copy
length by getsockopt(IP_OPTIONS) and by the udp/raw/ping sendmsg paths,
where it exceeds the size of the buffers they copy into.

Compute the new length from the intact options before the move and
subtract the CIPSO length, and fill the padding with IPOPT_END.

Assisted-by: LLM
Fixes: 014ab19a69c32 ("selinux: Set socket NetLabel based on connection endpoint")
Cc: stable@vger.kernel.org
Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
Acked-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
---
 net/ipv4/cipso_ipv4.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 1aacbbeffbc64..e65a3f29d2caf 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -2013,6 +2013,10 @@ static int cipso_v4_delopt(struct ip_options_rcu __rcu **opt_ptr)
 		cipso_ptr = &opt->opt.__data[cipso_off];
 		cipso_len = cipso_ptr[1];
 
+		optlen_new = cipso_v4_get_actual_opt_len(opt->opt.__data,
+							 opt->opt.optlen);
+		optlen_new -= cipso_len;
+
 		if (opt->opt.srr > opt->opt.cipso)
 			opt->opt.srr -= cipso_len;
 		if (opt->opt.rr > opt->opt.cipso)
@@ -2026,11 +2030,12 @@ static int cipso_v4_delopt(struct ip_options_rcu __rcu **opt_ptr)
 		memmove(cipso_ptr, cipso_ptr + cipso_len,
 			opt->opt.optlen - cipso_off - cipso_len);
 
-		optlen_new = cipso_v4_get_actual_opt_len(opt->opt.__data,
-							 opt->opt.optlen);
 		hdr_delta = opt->opt.optlen;
 		opt->opt.optlen = (optlen_new + 3) & ~3;
 		hdr_delta -= opt->opt.optlen;
+
+		memset(&opt->opt.__data[optlen_new], IPOPT_END,
+		       opt->opt.optlen - optlen_new);
 	} else {
 		/* only the cipso option was present on the socket so we can
 		 * remove the entire option struct */
-- 
2.53.0





^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options
  2026-11-10  1:11 FAILED: patch "[PATCH] cipso: fix optlen corruption in cipso_v4_delopt()" failed to apply to 6.6-stable tree Sasha Levin
@ 2026-11-12  2:39 ` Sasha Levin
  2026-11-12  2:39   ` [PATCH 6.6.y 2/2] cipso: fix optlen corruption in cipso_v4_delopt() Sasha Levin
  2026-11-12  9:33   ` [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options Ondrej Mosnacek
  0 siblings, 2 replies; 5+ messages in thread
From: Sasha Levin @ 2026-11-12  2:39 UTC (permalink / raw)
  To: stable; +Cc: Ondrej Mosnacek, David S. Miller, Sasha Levin

From: Ondrej Mosnacek <omosnace@redhat.com>

[ Upstream commit 89aa3619d141d6cfb6040a561aebb6d99d3e2285 ]

As the comment in this function says, the code currently just clears the
CIPSO part with IPOPT_NOP, rather than removing it completely and
trimming the packet. The other cipso_v4_*_delattr() functions, however,
do the proper removal and also calipso_skbuff_delattr() makes an effort
to remove the CALIPSO options instead of replacing them with padding.

Some routers treat IPv4 packets with anything (even NOPs) in the option
header as a special case and take them through a slower processing path.
Consequently, hardening guides such as STIG recommend to configure such
routers to drop packets with non-empty IP option headers [1][2]. Thus,
users might expect NetLabel to produce packets with minimal padding (or
at least with no padding when no actual options are present).

Implement the proper option removal to address this and to be closer to
what the peer functions do.

[1] https://www.stigviewer.com/stig/juniper_router_rtr/2019-09-27/finding/V-90937
[2] https://www.stigviewer.com/stig/cisco_ios_xe_router_rtr/2021-03-26/finding/V-217001

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Stable-dep-of: 1f1f8e8c5176 ("cipso: fix optlen corruption in cipso_v4_delopt()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 net/ipv4/cipso_ipv4.c | 79 +++++++++++++++++++++++++++++--------------
 1 file changed, 54 insertions(+), 25 deletions(-)

diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 8daa6418e25a0..83f58bb82c867 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -1813,6 +1813,29 @@ static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
 	return CIPSO_V4_HDR_LEN + ret_val;
 }
 
+static int cipso_v4_get_actual_opt_len(const unsigned char *data, int len)
+{
+	int iter = 0, optlen = 0;
+
+	/* determining the new total option length is tricky because of
+	 * the padding necessary, the only thing i can think to do at
+	 * this point is walk the options one-by-one, skipping the
+	 * padding at the end to determine the actual option size and
+	 * from there we can determine the new total option length
+	 */
+	while (iter < len) {
+		if (data[iter] == IPOPT_END) {
+			break;
+		} else if (data[iter] == IPOPT_NOP) {
+			iter++;
+		} else {
+			iter += data[iter + 1];
+			optlen = iter;
+		}
+	}
+	return optlen;
+}
+
 /**
  * cipso_v4_sock_setattr - Add a CIPSO option to a socket
  * @sk: the socket
@@ -1988,7 +2011,6 @@ static int cipso_v4_delopt(struct ip_options_rcu __rcu **opt_ptr)
 		u8 cipso_len;
 		u8 cipso_off;
 		unsigned char *cipso_ptr;
-		int iter;
 		int optlen_new;
 
 		cipso_off = opt->opt.cipso - sizeof(struct iphdr);
@@ -2008,23 +2030,8 @@ static int cipso_v4_delopt(struct ip_options_rcu __rcu **opt_ptr)
 		memmove(cipso_ptr, cipso_ptr + cipso_len,
 			opt->opt.optlen - cipso_off - cipso_len);
 
-		/* determining the new total option length is tricky because of
-		 * the padding necessary, the only thing i can think to do at
-		 * this point is walk the options one-by-one, skipping the
-		 * padding at the end to determine the actual option size and
-		 * from there we can determine the new total option length */
-		iter = 0;
-		optlen_new = 0;
-		while (iter < opt->opt.optlen) {
-			if (opt->opt.__data[iter] == IPOPT_END) {
-				break;
-			} else if (opt->opt.__data[iter] == IPOPT_NOP) {
-				iter++;
-			} else {
-				iter += opt->opt.__data[iter + 1];
-				optlen_new = iter;
-			}
-		}
+		optlen_new = cipso_v4_get_actual_opt_len(opt->opt.__data,
+							 opt->opt.optlen);
 		hdr_delta = opt->opt.optlen;
 		opt->opt.optlen = (optlen_new + 3) & ~3;
 		hdr_delta -= opt->opt.optlen;
@@ -2244,7 +2251,8 @@ int cipso_v4_skbuff_setattr(struct sk_buff *skb,
  */
 int cipso_v4_skbuff_delattr(struct sk_buff *skb)
 {
-	int ret_val;
+	int ret_val, cipso_len, hdr_len_actual, new_hdr_len_actual, new_hdr_len,
+	    hdr_len_delta;
 	struct iphdr *iph;
 	struct ip_options *opt = &IPCB(skb)->opt;
 	unsigned char *cipso_ptr;
@@ -2257,16 +2265,37 @@ int cipso_v4_skbuff_delattr(struct sk_buff *skb)
 	if (ret_val < 0)
 		return ret_val;
 
-	/* the easiest thing to do is just replace the cipso option with noop
-	 * options since we don't change the size of the packet, although we
-	 * still need to recalculate the checksum */
-
 	iph = ip_hdr(skb);
 	cipso_ptr = (unsigned char *)iph + opt->cipso;
-	memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]);
+	cipso_len = cipso_ptr[1];
+
+	hdr_len_actual = sizeof(struct iphdr) +
+			 cipso_v4_get_actual_opt_len((unsigned char *)(iph + 1),
+						     opt->optlen);
+	new_hdr_len_actual = hdr_len_actual - cipso_len;
+	new_hdr_len = (new_hdr_len_actual + 3) & ~3;
+	hdr_len_delta = (iph->ihl << 2) - new_hdr_len;
+
+	/* 1. shift any options after CIPSO to the left */
+	memmove(cipso_ptr, cipso_ptr + cipso_len,
+		new_hdr_len_actual - opt->cipso);
+	/* 2. move the whole IP header to its new place */
+	memmove((unsigned char *)iph + hdr_len_delta, iph, new_hdr_len_actual);
+	/* 3. adjust the skb layout */
+	skb_pull(skb, hdr_len_delta);
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
+	/* 4. re-fill new padding with IPOPT_END (may now be longer) */
+	memset((unsigned char *)iph + new_hdr_len_actual, IPOPT_END,
+	       new_hdr_len - new_hdr_len_actual);
+
+	opt->optlen -= hdr_len_delta;
 	opt->cipso = 0;
 	opt->is_changed = 1;
-
+	if (hdr_len_delta != 0) {
+		iph->ihl = new_hdr_len >> 2;
+		iph_set_totlen(iph, skb->len);
+	}
 	ip_send_check(iph);
 
 	return 0;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 6.6.y 2/2] cipso: fix optlen corruption in cipso_v4_delopt()
  2026-11-12  2:39 ` [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options Sasha Levin
@ 2026-11-12  2:39   ` Sasha Levin
  2026-11-12  9:33   ` [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options Ondrej Mosnacek
  1 sibling, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-11-12  2:39 UTC (permalink / raw)
  To: stable; +Cc: Qihang, Paul Moore, Dave Miller, Sasha Levin

From: Qihang <q.h.hack.winter@gmail.com>

[ Upstream commit 1f1f8e8c5176234fa31858cd25f2e9b88aac0a45 ]

cipso_v4_delopt() recomputes the option length by walking the option
buffer after the CIPSO option has been moved out.  The walk then reads
the stale bytes at the tail of the buffer as option data, and a crafted
setsockopt(IP_OPTIONS) buffer can make it treat one of them as an option
length, increasing opt->opt.optlen beyond the valid option data.

The corrupted length stays on the socket and is later used as the copy
length by getsockopt(IP_OPTIONS) and by the udp/raw/ping sendmsg paths,
where it exceeds the size of the buffers they copy into.

Compute the new length from the intact options before the move and
subtract the CIPSO length, and fill the padding with IPOPT_END.

Assisted-by: LLM
Fixes: 014ab19a69c32 ("selinux: Set socket NetLabel based on connection endpoint")
Cc: stable@vger.kernel.org
Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
Acked-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Dave Miller <davem@davem-thinkpadp1gen8.ibmlond.csb>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 net/ipv4/cipso_ipv4.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 83f58bb82c867..5ccc6f2524dd8 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -2017,6 +2017,10 @@ static int cipso_v4_delopt(struct ip_options_rcu __rcu **opt_ptr)
 		cipso_ptr = &opt->opt.__data[cipso_off];
 		cipso_len = cipso_ptr[1];
 
+		optlen_new = cipso_v4_get_actual_opt_len(opt->opt.__data,
+							 opt->opt.optlen);
+		optlen_new -= cipso_len;
+
 		if (opt->opt.srr > opt->opt.cipso)
 			opt->opt.srr -= cipso_len;
 		if (opt->opt.rr > opt->opt.cipso)
@@ -2030,11 +2034,12 @@ static int cipso_v4_delopt(struct ip_options_rcu __rcu **opt_ptr)
 		memmove(cipso_ptr, cipso_ptr + cipso_len,
 			opt->opt.optlen - cipso_off - cipso_len);
 
-		optlen_new = cipso_v4_get_actual_opt_len(opt->opt.__data,
-							 opt->opt.optlen);
 		hdr_delta = opt->opt.optlen;
 		opt->opt.optlen = (optlen_new + 3) & ~3;
 		hdr_delta -= opt->opt.optlen;
+
+		memset(&opt->opt.__data[optlen_new], IPOPT_END,
+		       opt->opt.optlen - optlen_new);
 	} else {
 		/* only the cipso option was present on the socket so we can
 		 * remove the entire option struct */
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options
  2026-11-12  2:39 ` [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options Sasha Levin
  2026-11-12  2:39   ` [PATCH 6.6.y 2/2] cipso: fix optlen corruption in cipso_v4_delopt() Sasha Levin
@ 2026-11-12  9:33   ` Ondrej Mosnacek
  2026-11-13 19:10     ` Sasha Levin
  1 sibling, 1 reply; 5+ messages in thread
From: Ondrej Mosnacek @ 2026-11-12  9:33 UTC (permalink / raw)
  To: Sasha Levin; +Cc: stable, David S. Miller

On Thu, Nov 12, 2026 at 3:45 AM Sasha Levin <sashal@kernel.org> wrote:
>
> From: Ondrej Mosnacek <omosnace@redhat.com>
>
> [ Upstream commit 89aa3619d141d6cfb6040a561aebb6d99d3e2285 ]
>
> As the comment in this function says, the code currently just clears the
> CIPSO part with IPOPT_NOP, rather than removing it completely and
> trimming the packet. The other cipso_v4_*_delattr() functions, however,
> do the proper removal and also calipso_skbuff_delattr() makes an effort
> to remove the CALIPSO options instead of replacing them with padding.
>
> Some routers treat IPv4 packets with anything (even NOPs) in the option
> header as a special case and take them through a slower processing path.
> Consequently, hardening guides such as STIG recommend to configure such
> routers to drop packets with non-empty IP option headers [1][2]. Thus,
> users might expect NetLabel to produce packets with minimal padding (or
> at least with no padding when no actual options are present).
>
> Implement the proper option removal to address this and to be closer to
> what the peer functions do.
>
> [1] https://www.stigviewer.com/stig/juniper_router_rtr/2019-09-27/finding/V-90937
> [2] https://www.stigviewer.com/stig/cisco_ios_xe_router_rtr/2021-03-26/finding/V-217001
>
> Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
> Stable-dep-of: 1f1f8e8c5176 ("cipso: fix optlen corruption in cipso_v4_delopt()")
> Signed-off-by: Sasha Levin <sashal@kernel.org>
> ---
>  net/ipv4/cipso_ipv4.c | 79 +++++++++++++++++++++++++++++--------------
>  1 file changed, 54 insertions(+), 25 deletions(-)
>

Friendly NACK (for the other stable branches as well), for the
following reasons:
1. There is another commit fixing this one (6d25ffca055a ("cipso:
adjust cached option offsets when removing CIPSO")) that isn't
included in these series.
2. This is not your fault, but it seems that the Fixes: metadata in
1f1f8e8c5176 ("cipso: fix optlen corruption in cipso_v4_delopt()") is
incorrect - the bug it fixes was actually introduced by this commit
(89aa3619d141 ("cipso: make cipso_v4_skbuff_delattr() fully remove the
CIPSO options")). It can't affect the code before that commit, because
back then the length of the options didn't change.

So I think it's best to just keep 89aa3619d141 (and all the follow-up
fixes) out of stable branches unless someone requests it specifically.

--
Ondrej Mosnacek
Senior Software Engineer, Linux Security - SELinux kernel
Red Hat, Inc.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options
  2026-11-12  9:33   ` [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options Ondrej Mosnacek
@ 2026-11-13 19:10     ` Sasha Levin
  0 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-11-13 19:10 UTC (permalink / raw)
  To: Ondrej Mosnacek; +Cc: Sasha Levin, stable, David S. Miller

On Thu, Nov 12, 2026 at 3:45 AM Sasha Levin <sashal@kernel.org> wrote:
> Friendly NACK (for the other stable branches as well), for the
> following reasons:
> 1. There is another commit fixing this one (6d25ffca055a ("cipso:
> adjust cached option offsets when removing CIPSO")) that isn't
> included in these series.

Ack

-- 
Thanks,
Sasha

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-11-13 19:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-10  1:11 FAILED: patch "[PATCH] cipso: fix optlen corruption in cipso_v4_delopt()" failed to apply to 6.6-stable tree Sasha Levin
2026-11-12  2:39 ` [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options Sasha Levin
2026-11-12  2:39   ` [PATCH 6.6.y 2/2] cipso: fix optlen corruption in cipso_v4_delopt() Sasha Levin
2026-11-12  9:33   ` [PATCH 6.6.y 1/2] cipso: make cipso_v4_skbuff_delattr() fully remove the CIPSO options Ondrej Mosnacek
2026-11-13 19:10     ` Sasha Levin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox