From e1311a79032b023a88ed487fb88e04e12618a0fc Mon Sep 17 00:00:00 2001 From: Maher Homsi Date: Fri, 18 Sep 2026 10:35:04 -0700 Subject: [PATCH 1/8] kernel-6.1: include patch to validate AH6 routing header segments_left Signed-off-by: Maher Homsi --- ...alidate-routing-header-segments_left.patch | 106 ++++++++++++++++++ packages/kernel-6.1/kernel-6.1.spec | 2 + 2 files changed, 108 insertions(+) create mode 100644 packages/kernel-6.1/1009-xfrm-ah6-validate-routing-header-segments_left.patch diff --git a/packages/kernel-6.1/1009-xfrm-ah6-validate-routing-header-segments_left.patch b/packages/kernel-6.1/1009-xfrm-ah6-validate-routing-header-segments_left.patch new file mode 100644 index 00000000..9013d1ae --- /dev/null +++ b/packages/kernel-6.1/1009-xfrm-ah6-validate-routing-header-segments_left.patch @@ -0,0 +1,106 @@ +From 1b7e066eabcc7d6d8f476c34739b45932f2f4c31 Mon Sep 17 00:00:00 2001 +From: Asim Viladi Oglu Manizada +Date: Thu, 23 Jul 2026 09:35:48 +0000 +Subject: xfrm: ah6: validate routing header segments_left + +commit 7bad4bda74dc4713f398d3b7624ff05478e3a568 upstream. + +AH6 rearranges routing-header addresses before computing or verifying the +ICV. ipv6_rearrange_rthdr() assumes that segments_left is not larger than +the number of addresses described by the routing header's hdrlen field. + +That assumption does not hold for raw IPv6 HDRINCL packets. A packet with +hdrlen equal to 2 describes one address, but can carry an arbitrary +segments_left value. With segments_left equal to 255, the function moves +its address pointer 4,064 bytes backwards and passes a 4,064-byte length to +memmove(), resulting in an out-of-bounds access. + +Validate the invariant locally before modifying the routing header or +performing any address-pointer arithmetic, and propagate malformed-header +errors to the existing AH6 input and output error paths. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Assisted-by: avom-custom-harness:gpt-5.5-qwen3.6-mod-mix +Signed-off-by: Asim Viladi Oglu Manizada +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Maher Homsi +--- + net/ipv6/ah6.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c +index 434071b5a37f0..d9543dbf4c937 100644 +--- a/net/ipv6/ah6.c ++++ b/net/ipv6/ah6.c +@@ -232,26 +232,28 @@ static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *des + * Rearrange the destination address in @iph and the addresses in @rthdr + * so that they appear in the order they will at the final destination. + * See Appendix A2 of RFC 2402 for details. ++ * ++ * Return: 0 on success, -EINVAL if segments_left exceeds the number of ++ * addresses described by hdrlen. + */ +-static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) ++static int ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) + { +- int segments, segments_left; ++ unsigned int segments, segments_left; + struct in6_addr *addrs; + struct in6_addr final_addr; + + segments_left = rthdr->segments_left; + if (segments_left == 0) +- return; +- rthdr->segments_left = 0; ++ return 0; + +- /* The value of rthdr->hdrlen has been verified either by the system +- * call if it is locally generated, or by ipv6_rthdr_rcv() for incoming +- * packets. So we can assume that it is even and that segments is +- * greater than or equal to segments_left. +- * +- * For the same reason we can assume that this option is of type 0. ++ /* Raw locally generated packets can reach AH6 without the invariant ++ * required by the rt0-style address rearrangement below. + */ + segments = rthdr->hdrlen >> 1; ++ if (segments_left > segments) ++ return -EINVAL; ++ ++ rthdr->segments_left = 0; + + addrs = ((struct rt0_hdr *)rthdr)->addr; + final_addr = addrs[segments - 1]; +@@ -261,6 +263,8 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) + + addrs[0] = iph->daddr; + iph->daddr = final_addr; ++ ++ return 0; + } + + static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) +@@ -273,6 +277,7 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) + } exthdr = { .iph = iph }; + char *end = exthdr.raw + len; + int nexthdr = iph->nexthdr; ++ int err; + + exthdr.iph++; + +@@ -292,7 +297,9 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) + break; + + case NEXTHDR_ROUTING: +- ipv6_rearrange_rthdr(iph, exthdr.rth); ++ err = ipv6_rearrange_rthdr(iph, exthdr.rth); ++ if (err) ++ return err; + break; + + default: +-- +cgit 1.3.1-korg + diff --git a/packages/kernel-6.1/kernel-6.1.spec b/packages/kernel-6.1/kernel-6.1.spec index 10a9192f..3173fc0b 100644 --- a/packages/kernel-6.1/kernel-6.1.spec +++ b/packages/kernel-6.1/kernel-6.1.spec @@ -64,6 +64,8 @@ Patch1006: 1006-strscpy-write-destination-buffer-only-once.patch Patch1007: 1007-nitro_enclaves-fix-use-after-free-on-SLOT_ALLOC-fail.patch # Initialize modname and offset in ftrace print_rec() to avoid GP fault Patch1008: 1008-ftrace-initialize-modname-and-offset-in-print_rec.patch +# Validate IPv6 routing header segments_left in AH6 to avoid OOB access +Patch1009: 1009-xfrm-ah6-validate-routing-header-segments_left.patch BuildRequires: bc BuildRequires: elfutils-devel From 6b2e72570d666d16ba382d416d37115dd06b68d2 Mon Sep 17 00:00:00 2001 From: Maher Homsi Date: Fri, 18 Sep 2026 10:35:05 -0700 Subject: [PATCH 2/8] kernel-6.1: include patch to bound tun receive headroom Signed-off-by: Maher Homsi --- .../1010-net-tun-bound-receive-headroom.patch | 88 +++++++++++++++++++ packages/kernel-6.1/kernel-6.1.spec | 2 + 2 files changed, 90 insertions(+) create mode 100644 packages/kernel-6.1/1010-net-tun-bound-receive-headroom.patch diff --git a/packages/kernel-6.1/1010-net-tun-bound-receive-headroom.patch b/packages/kernel-6.1/1010-net-tun-bound-receive-headroom.patch new file mode 100644 index 00000000..970ae90a --- /dev/null +++ b/packages/kernel-6.1/1010-net-tun-bound-receive-headroom.patch @@ -0,0 +1,88 @@ +From 18ef24cdb2eba32e38f1d27f2d02b7b4212e8f76 Mon Sep 17 00:00:00 2001 +From: Asim Viladi Oglu Manizada +Date: Wed, 12 Aug 2026 01:21:53 +0000 +Subject: net: tun: bound receive headroom + +commit 447c9303942c439a117d9b76ce6d6e2116b38ee7 upstream. + +tun_get_user() uses tun->align both as skb headroom and when choosing how +much packet data to keep linear. OVS can propagate an oversized headroom +request from another port to TUN or TAP. + +When align is larger than the usable space in a one-page skb head, +SKB_MAX_HEAD(align) underflows and the result becomes negative when stored +in good_linear. That value later wraps when assigned to the size_t linear +variable, and tun_alloc_skb() can place skb->data outside the allocated +head. + +Bound the headroom stored by TUN to the one-page skb-head budget and the +largest non-sentinel 16-bit skb header offset. Leave one linear byte for +raw TUN and a complete Ethernet header for TAP, including NET_IP_ALIGN. + +Also pull the raw-TUN protocol byte and the TAP Ethernet header before +accessing them, so these checks remain safe for nonlinear skbs supplied by +other allocation paths. + +Fixes: eaea34b23c46 ("net/tun: implement ndo_set_rx_headroom") +Cc: stable@vger.kernel.org +Signed-off-by: Asim Viladi Oglu Manizada +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260812012139.2134643-1-manizada@pm.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Maher Homsi +--- + drivers/net/tun.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index e8f8c7d5df29e..6e021a7caa07a 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -1175,11 +1175,16 @@ static netdev_features_t tun_net_fix_features(struct net_device *dev, + static void tun_set_headroom(struct net_device *dev, int new_hr) + { + struct tun_struct *tun = netdev_priv(dev); ++ size_t max_headroom; + +- if (new_hr < NET_SKB_PAD) +- new_hr = NET_SKB_PAD; ++ max_headroom = min_t(size_t, SKB_MAX_HEAD(0), U16_MAX - 1); + +- tun->align = new_hr; ++ if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) ++ max_headroom -= ETH_HLEN + NET_IP_ALIGN; ++ else ++ max_headroom -= 1; ++ ++ tun->align = clamp_t(int, new_hr, NET_SKB_PAD, max_headroom); + } + + static void +@@ -1868,7 +1873,13 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, + switch (tun->flags & TUN_TYPE_MASK) { + case IFF_TUN: + if (tun->flags & IFF_NO_PI) { +- u8 ip_version = skb->len ? (skb->data[0] >> 4) : 0; ++ u8 ip_version; ++ ++ if (!pskb_may_pull(skb, 1)) { ++ err = -EINVAL; ++ goto drop; ++ } ++ ip_version = skb->data[0] >> 4; + + switch (ip_version) { + case 4: +@@ -1888,7 +1899,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, + skb->dev = tun->dev; + break; + case IFF_TAP: +- if (frags && !pskb_may_pull(skb, ETH_HLEN)) { ++ if (!pskb_may_pull(skb, ETH_HLEN)) { + err = -ENOMEM; + drop_reason = SKB_DROP_REASON_HDR_TRUNC; + goto drop; +-- +cgit 1.3.1-korg + diff --git a/packages/kernel-6.1/kernel-6.1.spec b/packages/kernel-6.1/kernel-6.1.spec index 3173fc0b..2a670fc4 100644 --- a/packages/kernel-6.1/kernel-6.1.spec +++ b/packages/kernel-6.1/kernel-6.1.spec @@ -66,6 +66,8 @@ Patch1007: 1007-nitro_enclaves-fix-use-after-free-on-SLOT_ALLOC-fail.patch Patch1008: 1008-ftrace-initialize-modname-and-offset-in-print_rec.patch # Validate IPv6 routing header segments_left in AH6 to avoid OOB access Patch1009: 1009-xfrm-ah6-validate-routing-header-segments_left.patch +# Bound tun receive headroom to prevent skb overflow +Patch1010: 1010-net-tun-bound-receive-headroom.patch BuildRequires: bc BuildRequires: elfutils-devel From ea52032257666857583ffba9a19b12b29de0ea46 Mon Sep 17 00:00:00 2001 From: Maher Homsi Date: Fri, 18 Sep 2026 10:35:05 -0700 Subject: [PATCH 3/8] kernel-6.12: include patch to validate AH6 routing header segments_left Signed-off-by: Maher Homsi --- ...alidate-routing-header-segments_left.patch | 106 ++++++++++++++++++ packages/kernel-6.12/kernel-6.12.spec | 2 + 2 files changed, 108 insertions(+) create mode 100644 packages/kernel-6.12/1011-xfrm-ah6-validate-routing-header-segments_left.patch diff --git a/packages/kernel-6.12/1011-xfrm-ah6-validate-routing-header-segments_left.patch b/packages/kernel-6.12/1011-xfrm-ah6-validate-routing-header-segments_left.patch new file mode 100644 index 00000000..bc85a2f1 --- /dev/null +++ b/packages/kernel-6.12/1011-xfrm-ah6-validate-routing-header-segments_left.patch @@ -0,0 +1,106 @@ +From 1516e31ac458a738be485620579d8f7fb2700fcb Mon Sep 17 00:00:00 2001 +From: Asim Viladi Oglu Manizada +Date: Thu, 23 Jul 2026 09:35:48 +0000 +Subject: xfrm: ah6: validate routing header segments_left + +commit 7bad4bda74dc4713f398d3b7624ff05478e3a568 upstream. + +AH6 rearranges routing-header addresses before computing or verifying the +ICV. ipv6_rearrange_rthdr() assumes that segments_left is not larger than +the number of addresses described by the routing header's hdrlen field. + +That assumption does not hold for raw IPv6 HDRINCL packets. A packet with +hdrlen equal to 2 describes one address, but can carry an arbitrary +segments_left value. With segments_left equal to 255, the function moves +its address pointer 4,064 bytes backwards and passes a 4,064-byte length to +memmove(), resulting in an out-of-bounds access. + +Validate the invariant locally before modifying the routing header or +performing any address-pointer arithmetic, and propagate malformed-header +errors to the existing AH6 input and output error paths. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Assisted-by: avom-custom-harness:gpt-5.5-qwen3.6-mod-mix +Signed-off-by: Asim Viladi Oglu Manizada +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Maher Homsi +--- + net/ipv6/ah6.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c +index bf4e11614af25..188397b9a9db0 100644 +--- a/net/ipv6/ah6.c ++++ b/net/ipv6/ah6.c +@@ -232,26 +232,28 @@ static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *des + * Rearrange the destination address in @iph and the addresses in @rthdr + * so that they appear in the order they will at the final destination. + * See Appendix A2 of RFC 2402 for details. ++ * ++ * Return: 0 on success, -EINVAL if segments_left exceeds the number of ++ * addresses described by hdrlen. + */ +-static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) ++static int ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) + { +- int segments, segments_left; ++ unsigned int segments, segments_left; + struct in6_addr *addrs; + struct in6_addr final_addr; + + segments_left = rthdr->segments_left; + if (segments_left == 0) +- return; +- rthdr->segments_left = 0; ++ return 0; + +- /* The value of rthdr->hdrlen has been verified either by the system +- * call if it is locally generated, or by ipv6_rthdr_rcv() for incoming +- * packets. So we can assume that it is even and that segments is +- * greater than or equal to segments_left. +- * +- * For the same reason we can assume that this option is of type 0. ++ /* Raw locally generated packets can reach AH6 without the invariant ++ * required by the rt0-style address rearrangement below. + */ + segments = rthdr->hdrlen >> 1; ++ if (segments_left > segments) ++ return -EINVAL; ++ ++ rthdr->segments_left = 0; + + addrs = ((struct rt0_hdr *)rthdr)->addr; + final_addr = addrs[segments - 1]; +@@ -261,6 +263,8 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) + + addrs[0] = iph->daddr; + iph->daddr = final_addr; ++ ++ return 0; + } + + static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) +@@ -273,6 +277,7 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) + } exthdr = { .iph = iph }; + char *end = exthdr.raw + len; + int nexthdr = iph->nexthdr; ++ int err; + + exthdr.iph++; + +@@ -292,7 +297,9 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) + break; + + case NEXTHDR_ROUTING: +- ipv6_rearrange_rthdr(iph, exthdr.rth); ++ err = ipv6_rearrange_rthdr(iph, exthdr.rth); ++ if (err) ++ return err; + break; + + default: +-- +cgit 1.3.1-korg + diff --git a/packages/kernel-6.12/kernel-6.12.spec b/packages/kernel-6.12/kernel-6.12.spec index 63a44a3c..aa18a652 100644 --- a/packages/kernel-6.12/kernel-6.12.spec +++ b/packages/kernel-6.12/kernel-6.12.spec @@ -75,6 +75,8 @@ Patch1008: 1008-Revert-selinux-fix-overlayfs-mmap-and-mprotect-acces.patch Patch1009: 1009-nitro_enclaves-fix-use-after-free-on-SLOT_ALLOC-fail.patch # Initialize modname and offset in ftrace print_rec() to avoid GP fault Patch1010: 1010-ftrace-initialize-modname-and-offset-in-print_rec.patch +# Validate IPv6 routing header segments_left in AH6 to avoid OOB access +Patch1011: 1011-xfrm-ah6-validate-routing-header-segments_left.patch BuildRequires: bc BuildRequires: elfutils-devel From ac8cbe36e2e7aeb70a9d9d4ad1bb48934f9d3f8a Mon Sep 17 00:00:00 2001 From: Maher Homsi Date: Fri, 18 Sep 2026 10:35:06 -0700 Subject: [PATCH 4/8] kernel-6.12: include patch to bound tun receive headroom Signed-off-by: Maher Homsi --- .../1012-net-tun-bound-receive-headroom.patch | 88 +++++++++++++++++++ packages/kernel-6.12/kernel-6.12.spec | 2 + 2 files changed, 90 insertions(+) create mode 100644 packages/kernel-6.12/1012-net-tun-bound-receive-headroom.patch diff --git a/packages/kernel-6.12/1012-net-tun-bound-receive-headroom.patch b/packages/kernel-6.12/1012-net-tun-bound-receive-headroom.patch new file mode 100644 index 00000000..dcac3673 --- /dev/null +++ b/packages/kernel-6.12/1012-net-tun-bound-receive-headroom.patch @@ -0,0 +1,88 @@ +From 379d85c7f25f3e05a428225e6b8a65613c6e9b9d Mon Sep 17 00:00:00 2001 +From: Asim Viladi Oglu Manizada +Date: Wed, 12 Aug 2026 01:21:53 +0000 +Subject: net: tun: bound receive headroom + +commit 447c9303942c439a117d9b76ce6d6e2116b38ee7 upstream. + +tun_get_user() uses tun->align both as skb headroom and when choosing how +much packet data to keep linear. OVS can propagate an oversized headroom +request from another port to TUN or TAP. + +When align is larger than the usable space in a one-page skb head, +SKB_MAX_HEAD(align) underflows and the result becomes negative when stored +in good_linear. That value later wraps when assigned to the size_t linear +variable, and tun_alloc_skb() can place skb->data outside the allocated +head. + +Bound the headroom stored by TUN to the one-page skb-head budget and the +largest non-sentinel 16-bit skb header offset. Leave one linear byte for +raw TUN and a complete Ethernet header for TAP, including NET_IP_ALIGN. + +Also pull the raw-TUN protocol byte and the TAP Ethernet header before +accessing them, so these checks remain safe for nonlinear skbs supplied by +other allocation paths. + +Fixes: eaea34b23c46 ("net/tun: implement ndo_set_rx_headroom") +Cc: stable@vger.kernel.org +Signed-off-by: Asim Viladi Oglu Manizada +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260812012139.2134643-1-manizada@pm.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Maher Homsi +--- + drivers/net/tun.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index d53e60823bf1b..4d62f089d38bf 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -1170,11 +1170,16 @@ static netdev_features_t tun_net_fix_features(struct net_device *dev, + static void tun_set_headroom(struct net_device *dev, int new_hr) + { + struct tun_struct *tun = netdev_priv(dev); ++ size_t max_headroom; + +- if (new_hr < NET_SKB_PAD) +- new_hr = NET_SKB_PAD; ++ max_headroom = min_t(size_t, SKB_MAX_HEAD(0), U16_MAX - 1); + +- tun->align = new_hr; ++ if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) ++ max_headroom -= ETH_HLEN + NET_IP_ALIGN; ++ else ++ max_headroom -= 1; ++ ++ tun->align = clamp_t(int, new_hr, NET_SKB_PAD, max_headroom); + } + + static void +@@ -1877,7 +1882,13 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, + switch (tun->flags & TUN_TYPE_MASK) { + case IFF_TUN: + if (tun->flags & IFF_NO_PI) { +- u8 ip_version = skb->len ? (skb->data[0] >> 4) : 0; ++ u8 ip_version; ++ ++ if (!pskb_may_pull(skb, 1)) { ++ err = -EINVAL; ++ goto drop; ++ } ++ ip_version = skb->data[0] >> 4; + + switch (ip_version) { + case 4: +@@ -1897,7 +1908,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, + skb->dev = tun->dev; + break; + case IFF_TAP: +- if (frags && !pskb_may_pull(skb, ETH_HLEN)) { ++ if (!pskb_may_pull(skb, ETH_HLEN)) { + err = -ENOMEM; + drop_reason = SKB_DROP_REASON_HDR_TRUNC; + goto drop; +-- +cgit 1.3.1-korg + diff --git a/packages/kernel-6.12/kernel-6.12.spec b/packages/kernel-6.12/kernel-6.12.spec index aa18a652..d07eda4c 100644 --- a/packages/kernel-6.12/kernel-6.12.spec +++ b/packages/kernel-6.12/kernel-6.12.spec @@ -77,6 +77,8 @@ Patch1009: 1009-nitro_enclaves-fix-use-after-free-on-SLOT_ALLOC-fail.patch Patch1010: 1010-ftrace-initialize-modname-and-offset-in-print_rec.patch # Validate IPv6 routing header segments_left in AH6 to avoid OOB access Patch1011: 1011-xfrm-ah6-validate-routing-header-segments_left.patch +# Bound tun receive headroom to prevent skb overflow +Patch1012: 1012-net-tun-bound-receive-headroom.patch BuildRequires: bc BuildRequires: elfutils-devel From f6fe2166a6ab37b2c3007e5735d00400af17380d Mon Sep 17 00:00:00 2001 From: Maher Homsi Date: Fri, 18 Sep 2026 10:35:07 -0700 Subject: [PATCH 5/8] kernel-6.18: include patch to validate AH6 routing header segments_left Signed-off-by: Maher Homsi --- ...alidate-routing-header-segments_left.patch | 106 ++++++++++++++++++ packages/kernel-6.18/kernel-6.18.spec | 2 + 2 files changed, 108 insertions(+) create mode 100644 packages/kernel-6.18/1009-xfrm-ah6-validate-routing-header-segments_left.patch diff --git a/packages/kernel-6.18/1009-xfrm-ah6-validate-routing-header-segments_left.patch b/packages/kernel-6.18/1009-xfrm-ah6-validate-routing-header-segments_left.patch new file mode 100644 index 00000000..2be89cee --- /dev/null +++ b/packages/kernel-6.18/1009-xfrm-ah6-validate-routing-header-segments_left.patch @@ -0,0 +1,106 @@ +From 6733ae71268a27d598cfb3f3339a3c950b9b656d Mon Sep 17 00:00:00 2001 +From: Asim Viladi Oglu Manizada +Date: Thu, 23 Jul 2026 09:35:48 +0000 +Subject: xfrm: ah6: validate routing header segments_left + +commit 7bad4bda74dc4713f398d3b7624ff05478e3a568 upstream. + +AH6 rearranges routing-header addresses before computing or verifying the +ICV. ipv6_rearrange_rthdr() assumes that segments_left is not larger than +the number of addresses described by the routing header's hdrlen field. + +That assumption does not hold for raw IPv6 HDRINCL packets. A packet with +hdrlen equal to 2 describes one address, but can carry an arbitrary +segments_left value. With segments_left equal to 255, the function moves +its address pointer 4,064 bytes backwards and passes a 4,064-byte length to +memmove(), resulting in an out-of-bounds access. + +Validate the invariant locally before modifying the routing header or +performing any address-pointer arithmetic, and propagate malformed-header +errors to the existing AH6 input and output error paths. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Assisted-by: avom-custom-harness:gpt-5.5-qwen3.6-mod-mix +Signed-off-by: Asim Viladi Oglu Manizada +Signed-off-by: Steffen Klassert +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Maher Homsi +--- + net/ipv6/ah6.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c +index bf4e11614af25..188397b9a9db0 100644 +--- a/net/ipv6/ah6.c ++++ b/net/ipv6/ah6.c +@@ -232,26 +232,28 @@ static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *des + * Rearrange the destination address in @iph and the addresses in @rthdr + * so that they appear in the order they will at the final destination. + * See Appendix A2 of RFC 2402 for details. ++ * ++ * Return: 0 on success, -EINVAL if segments_left exceeds the number of ++ * addresses described by hdrlen. + */ +-static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) ++static int ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) + { +- int segments, segments_left; ++ unsigned int segments, segments_left; + struct in6_addr *addrs; + struct in6_addr final_addr; + + segments_left = rthdr->segments_left; + if (segments_left == 0) +- return; +- rthdr->segments_left = 0; ++ return 0; + +- /* The value of rthdr->hdrlen has been verified either by the system +- * call if it is locally generated, or by ipv6_rthdr_rcv() for incoming +- * packets. So we can assume that it is even and that segments is +- * greater than or equal to segments_left. +- * +- * For the same reason we can assume that this option is of type 0. ++ /* Raw locally generated packets can reach AH6 without the invariant ++ * required by the rt0-style address rearrangement below. + */ + segments = rthdr->hdrlen >> 1; ++ if (segments_left > segments) ++ return -EINVAL; ++ ++ rthdr->segments_left = 0; + + addrs = ((struct rt0_hdr *)rthdr)->addr; + final_addr = addrs[segments - 1]; +@@ -261,6 +263,8 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) + + addrs[0] = iph->daddr; + iph->daddr = final_addr; ++ ++ return 0; + } + + static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) +@@ -273,6 +277,7 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) + } exthdr = { .iph = iph }; + char *end = exthdr.raw + len; + int nexthdr = iph->nexthdr; ++ int err; + + exthdr.iph++; + +@@ -292,7 +297,9 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) + break; + + case NEXTHDR_ROUTING: +- ipv6_rearrange_rthdr(iph, exthdr.rth); ++ err = ipv6_rearrange_rthdr(iph, exthdr.rth); ++ if (err) ++ return err; + break; + + default: +-- +cgit 1.3.1-korg + diff --git a/packages/kernel-6.18/kernel-6.18.spec b/packages/kernel-6.18/kernel-6.18.spec index d9f2a503..9c046b42 100644 --- a/packages/kernel-6.18/kernel-6.18.spec +++ b/packages/kernel-6.18/kernel-6.18.spec @@ -84,6 +84,8 @@ Patch1006: 1006-Revert-selinux-fix-overlayfs-mmap-and-mprotect-acces.patch Patch1007: 1007-nitro_enclaves-fix-use-after-free-on-SLOT_ALLOC-fail.patch # Initialize modname and offset in ftrace print_rec() to avoid GP fault Patch1008: 1008-ftrace-initialize-modname-and-offset-in-print_rec.patch +# Validate IPv6 routing header segments_left in AH6 to avoid OOB access +Patch1009: 1009-xfrm-ah6-validate-routing-header-segments_left.patch BuildRequires: bc BuildRequires: elfutils-devel From d0a71c9374330beeacc7098bc9c23889aaccdc76 Mon Sep 17 00:00:00 2001 From: Maher Homsi Date: Fri, 18 Sep 2026 10:35:08 -0700 Subject: [PATCH 6/8] kernel-6.18: include patch to bound tun receive headroom Signed-off-by: Maher Homsi --- .../1010-net-tun-bound-receive-headroom.patch | 88 +++++++++++++++++++ packages/kernel-6.18/kernel-6.18.spec | 2 + 2 files changed, 90 insertions(+) create mode 100644 packages/kernel-6.18/1010-net-tun-bound-receive-headroom.patch diff --git a/packages/kernel-6.18/1010-net-tun-bound-receive-headroom.patch b/packages/kernel-6.18/1010-net-tun-bound-receive-headroom.patch new file mode 100644 index 00000000..0f9276b1 --- /dev/null +++ b/packages/kernel-6.18/1010-net-tun-bound-receive-headroom.patch @@ -0,0 +1,88 @@ +From e098d9cc8859614a7f7baebc96e32a5a16b18ed2 Mon Sep 17 00:00:00 2001 +From: Asim Viladi Oglu Manizada +Date: Wed, 12 Aug 2026 01:21:53 +0000 +Subject: net: tun: bound receive headroom + +commit 447c9303942c439a117d9b76ce6d6e2116b38ee7 upstream. + +tun_get_user() uses tun->align both as skb headroom and when choosing how +much packet data to keep linear. OVS can propagate an oversized headroom +request from another port to TUN or TAP. + +When align is larger than the usable space in a one-page skb head, +SKB_MAX_HEAD(align) underflows and the result becomes negative when stored +in good_linear. That value later wraps when assigned to the size_t linear +variable, and tun_alloc_skb() can place skb->data outside the allocated +head. + +Bound the headroom stored by TUN to the one-page skb-head budget and the +largest non-sentinel 16-bit skb header offset. Leave one linear byte for +raw TUN and a complete Ethernet header for TAP, including NET_IP_ALIGN. + +Also pull the raw-TUN protocol byte and the TAP Ethernet header before +accessing them, so these checks remain safe for nonlinear skbs supplied by +other allocation paths. + +Fixes: eaea34b23c46 ("net/tun: implement ndo_set_rx_headroom") +Cc: stable@vger.kernel.org +Signed-off-by: Asim Viladi Oglu Manizada +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260812012139.2134643-1-manizada@pm.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Maher Homsi +--- + drivers/net/tun.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index d27c3229465ad..172273ae65754 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -1105,11 +1105,16 @@ static netdev_features_t tun_net_fix_features(struct net_device *dev, + static void tun_set_headroom(struct net_device *dev, int new_hr) + { + struct tun_struct *tun = netdev_priv(dev); ++ size_t max_headroom; + +- if (new_hr < NET_SKB_PAD) +- new_hr = NET_SKB_PAD; ++ max_headroom = min_t(size_t, SKB_MAX_HEAD(0), U16_MAX - 1); + +- tun->align = new_hr; ++ if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) ++ max_headroom -= ETH_HLEN + NET_IP_ALIGN; ++ else ++ max_headroom -= 1; ++ ++ tun->align = clamp_t(int, new_hr, NET_SKB_PAD, max_headroom); + } + + static void +@@ -1820,7 +1825,13 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, + switch (tun->flags & TUN_TYPE_MASK) { + case IFF_TUN: + if (tun->flags & IFF_NO_PI) { +- u8 ip_version = skb->len ? (skb->data[0] >> 4) : 0; ++ u8 ip_version; ++ ++ if (!pskb_may_pull(skb, 1)) { ++ err = -EINVAL; ++ goto drop; ++ } ++ ip_version = skb->data[0] >> 4; + + switch (ip_version) { + case 4: +@@ -1840,7 +1851,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, + skb->dev = tun->dev; + break; + case IFF_TAP: +- if (frags && !pskb_may_pull(skb, ETH_HLEN)) { ++ if (!pskb_may_pull(skb, ETH_HLEN)) { + err = -ENOMEM; + drop_reason = SKB_DROP_REASON_HDR_TRUNC; + goto drop; +-- +cgit 1.3.1-korg + diff --git a/packages/kernel-6.18/kernel-6.18.spec b/packages/kernel-6.18/kernel-6.18.spec index 9c046b42..908d9525 100644 --- a/packages/kernel-6.18/kernel-6.18.spec +++ b/packages/kernel-6.18/kernel-6.18.spec @@ -86,6 +86,8 @@ Patch1007: 1007-nitro_enclaves-fix-use-after-free-on-SLOT_ALLOC-fail.patch Patch1008: 1008-ftrace-initialize-modname-and-offset-in-print_rec.patch # Validate IPv6 routing header segments_left in AH6 to avoid OOB access Patch1009: 1009-xfrm-ah6-validate-routing-header-segments_left.patch +# Bound tun receive headroom to prevent skb overflow +Patch1010: 1010-net-tun-bound-receive-headroom.patch BuildRequires: bc BuildRequires: elfutils-devel From 147f46a6ac067874970e34dd3094606916de6b92 Mon Sep 17 00:00:00 2001 From: Maher Homsi Date: Fri, 18 Sep 2026 10:35:09 -0700 Subject: [PATCH 7/8] twoliter: bump kit version to v9.1.3 Signed-off-by: Maher Homsi --- Twoliter.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Twoliter.toml b/Twoliter.toml index a7fa524a..19236d04 100644 --- a/Twoliter.toml +++ b/Twoliter.toml @@ -1,5 +1,5 @@ schema-version = 2 -release-version = "9.1.2" +release-version = "9.1.3" project-vendor = "Bottlerocket" [vendor.bottlerocket] From d5ff99758f8dfe711046669b3cc85edcb0281bb7 Mon Sep 17 00:00:00 2001 From: Maher Homsi Date: Fri, 18 Sep 2026 10:35:09 -0700 Subject: [PATCH 8/8] changelog: update for v9.1.3 Signed-off-by: Maher Homsi --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 210a5111..95343737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# v9.1.3 (2026-09-18) + +## OS Changes + +* Backport patches to fix TUN and AH6 bugs in the networking stack ([#559]) + +[#559]: https://github.com/bottlerocket-os/bottlerocket-kernel-kit/pull/559 + # v9.1.2 (2026-09-14) ## OS Changes