* [PATCH net v2] ipv6: ioam: fix heap buffer overflow in __ioam6_fill_trace_data()
@ 2026-02-11 4:04 Qanux
2026-02-11 20:20 ` Justin Iurman
2026-02-13 20:30 ` patchwork-bot+netdevbpf
0 siblings, 2 replies; 3+ messages in thread
From: Qanux @ 2026-02-11 4:04 UTC (permalink / raw)
To: netdev; +Cc: justin.iurman, davem, edumazet, kuba, pabeni, horms, dsahern
On the receive path, __ioam6_fill_trace_data() uses trace->nodelen
to decide how much data to write for each node. It trusts this field
as-is from the incoming packet, with no consistency check against
trace->type (the 24-bit field that tells which data items are
present). A crafted packet can set nodelen=0 while setting type bits
0-21, causing the function to write ~100 bytes past the allocated
region (into skb_shared_info), which corrupts adjacent heap memory
and leads to a kernel panic.
Add a shared helper ioam6_trace_compute_nodelen() in ioam6.c to
derive the expected nodelen from the type field, and use it:
- in ioam6_iptunnel.c (send path, existing validation) to replace
the open-coded computation;
- in exthdrs.c (receive path, ipv6_hop_ioam) to drop packets whose
nodelen is inconsistent with the type field, before any data is
written.
Per RFC 9197, bits 12-21 are each short (4-octet) fields, so they
are included in IOAM6_MASK_SHORT_FIELDS (changed from 0xff100000 to
0xff1ffc00).
Fixes: 9ee11f0fff20 ("ipv6: ioam: Data plane support for Pre-allocated Trace")
Cc: stable@vger.kernel.org
Signed-off-by: Junxi Qian <qjx1298677004@gmail.com>
---
v1 -> v2:
- Don't recompute nodelen in the data plane; instead, validate
nodelen consistency in ipv6_hop_ioam() on the receive path and
drop inconsistent packets.
- Add shared helper ioam6_trace_compute_nodelen() in ioam6.c,
reuse it in both ioam6_iptunnel.c (send) and exthdrs.c (receive).
- Per RFC 9197, include bits 12-21 in IOAM6_MASK_SHORT_FIELDS
(0xff100000 -> 0xff1ffc00) instead of a separate UNDEF mask.
Thanks to Justin Iurman for the detailed review and suggestions.
The patch has been tested with the PoC that previously triggered the
heap overflow. After applying this fix, the crafted packet is now
correctly dropped at the receive path, and the kernel no longer panics.
The patched kernel compiles and boots successfully.
---
include/net/ioam6.h | 2 ++
net/ipv6/exthdrs.c | 5 +++++
net/ipv6/ioam6.c | 14 ++++++++++++++
net/ipv6/ioam6_iptunnel.c | 10 +---------
4 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/include/net/ioam6.h b/include/net/ioam6.h
index 2cbbee6e8..a75912fe2 100644
--- a/include/net/ioam6.h
+++ b/include/net/ioam6.h
@@ -60,6 +60,8 @@ void ioam6_fill_trace_data(struct sk_buff *skb,
struct ioam6_trace_hdr *trace,
bool is_input);
+u8 ioam6_trace_compute_nodelen(u32 trace_type);
+
int ioam6_init(void);
void ioam6_exit(void);
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index a23eb8734..50062f98d 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -930,6 +930,11 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff)
if (hdr->opt_len < 2 + sizeof(*trace) + trace->remlen * 4)
goto drop;
+ /* Inconsistent Pre-allocated Trace header */
+ if (trace->nodelen !=
+ ioam6_trace_compute_nodelen(be32_to_cpu(trace->type_be32)))
+ goto drop;
+
/* Ignore if the IOAM namespace is unknown */
ns = ioam6_namespace(dev_net(skb->dev), trace->namespace_id);
if (!ns)
diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
index 9553a3200..08b7ac8c9 100644
--- a/net/ipv6/ioam6.c
+++ b/net/ipv6/ioam6.c
@@ -690,6 +690,20 @@ struct ioam6_namespace *ioam6_namespace(struct net *net, __be16 id)
return rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
}
+#define IOAM6_MASK_SHORT_FIELDS 0xff1ffc00
+#define IOAM6_MASK_WIDE_FIELDS 0x00e00000
+
+u8 ioam6_trace_compute_nodelen(u32 trace_type)
+{
+ u8 nodelen = hweight32(trace_type & IOAM6_MASK_SHORT_FIELDS)
+ * (sizeof(__be32) / 4);
+
+ nodelen += hweight32(trace_type & IOAM6_MASK_WIDE_FIELDS)
+ * (sizeof(__be64) / 4);
+
+ return nodelen;
+}
+
static void __ioam6_fill_trace_data(struct sk_buff *skb,
struct ioam6_namespace *ns,
struct ioam6_trace_hdr *trace,
diff --git a/net/ipv6/ioam6_iptunnel.c b/net/ipv6/ioam6_iptunnel.c
index 1fe7894f1..b9f6d892a 100644
--- a/net/ipv6/ioam6_iptunnel.c
+++ b/net/ipv6/ioam6_iptunnel.c
@@ -22,9 +22,6 @@
#include <net/ip6_route.h>
#include <net/addrconf.h>
-#define IOAM6_MASK_SHORT_FIELDS 0xff100000
-#define IOAM6_MASK_WIDE_FIELDS 0xe00000
-
struct ioam6_lwt_encap {
struct ipv6_hopopt_hdr eh;
u8 pad[2]; /* 2-octet padding for 4n-alignment */
@@ -93,13 +90,8 @@ static bool ioam6_validate_trace_hdr(struct ioam6_trace_hdr *trace)
trace->type.bit21 | trace->type.bit23)
return false;
- trace->nodelen = 0;
fields = be32_to_cpu(trace->type_be32);
-
- trace->nodelen += hweight32(fields & IOAM6_MASK_SHORT_FIELDS)
- * (sizeof(__be32) / 4);
- trace->nodelen += hweight32(fields & IOAM6_MASK_WIDE_FIELDS)
- * (sizeof(__be64) / 4);
+ trace->nodelen = ioam6_trace_compute_nodelen(fields);
return true;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH net v2] ipv6: ioam: fix heap buffer overflow in __ioam6_fill_trace_data()
2026-02-11 4:04 [PATCH net v2] ipv6: ioam: fix heap buffer overflow in __ioam6_fill_trace_data() Qanux
@ 2026-02-11 20:20 ` Justin Iurman
2026-02-13 20:30 ` patchwork-bot+netdevbpf
1 sibling, 0 replies; 3+ messages in thread
From: Justin Iurman @ 2026-02-11 20:20 UTC (permalink / raw)
To: Qanux, netdev; +Cc: davem, edumazet, kuba, pabeni, horms, dsahern
On 2/11/26 05:04, Qanux wrote:
> On the receive path, __ioam6_fill_trace_data() uses trace->nodelen
> to decide how much data to write for each node. It trusts this field
> as-is from the incoming packet, with no consistency check against
> trace->type (the 24-bit field that tells which data items are
> present). A crafted packet can set nodelen=0 while setting type bits
> 0-21, causing the function to write ~100 bytes past the allocated
> region (into skb_shared_info), which corrupts adjacent heap memory
> and leads to a kernel panic.
>
> Add a shared helper ioam6_trace_compute_nodelen() in ioam6.c to
> derive the expected nodelen from the type field, and use it:
>
> - in ioam6_iptunnel.c (send path, existing validation) to replace
> the open-coded computation;
> - in exthdrs.c (receive path, ipv6_hop_ioam) to drop packets whose
> nodelen is inconsistent with the type field, before any data is
> written.
>
> Per RFC 9197, bits 12-21 are each short (4-octet) fields, so they
> are included in IOAM6_MASK_SHORT_FIELDS (changed from 0xff100000 to
> 0xff1ffc00).
>
> Fixes: 9ee11f0fff20 ("ipv6: ioam: Data plane support for Pre-allocated Trace")
> Cc: stable@vger.kernel.org
> Signed-off-by: Junxi Qian <qjx1298677004@gmail.com>
> ---
> v1 -> v2:
> - Don't recompute nodelen in the data plane; instead, validate
> nodelen consistency in ipv6_hop_ioam() on the receive path and
> drop inconsistent packets.
> - Add shared helper ioam6_trace_compute_nodelen() in ioam6.c,
> reuse it in both ioam6_iptunnel.c (send) and exthdrs.c (receive).
> - Per RFC 9197, include bits 12-21 in IOAM6_MASK_SHORT_FIELDS
> (0xff100000 -> 0xff1ffc00) instead of a separate UNDEF mask.
>
> Thanks to Justin Iurman for the detailed review and suggestions.
>
> The patch has been tested with the PoC that previously triggered the
> heap overflow. After applying this fix, the crafted packet is now
> correctly dropped at the receive path, and the kernel no longer panics.
> The patched kernel compiles and boots successfully.
> ---
> include/net/ioam6.h | 2 ++
> net/ipv6/exthdrs.c | 5 +++++
> net/ipv6/ioam6.c | 14 ++++++++++++++
> net/ipv6/ioam6_iptunnel.c | 10 +---------
> 4 files changed, 22 insertions(+), 9 deletions(-)
>
> diff --git a/include/net/ioam6.h b/include/net/ioam6.h
> index 2cbbee6e8..a75912fe2 100644
> --- a/include/net/ioam6.h
> +++ b/include/net/ioam6.h
> @@ -60,6 +60,8 @@ void ioam6_fill_trace_data(struct sk_buff *skb,
> struct ioam6_trace_hdr *trace,
> bool is_input);
>
> +u8 ioam6_trace_compute_nodelen(u32 trace_type);
> +
> int ioam6_init(void);
> void ioam6_exit(void);
>
> diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
> index a23eb8734..50062f98d 100644
> --- a/net/ipv6/exthdrs.c
> +++ b/net/ipv6/exthdrs.c
> @@ -930,6 +930,11 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff)
> if (hdr->opt_len < 2 + sizeof(*trace) + trace->remlen * 4)
> goto drop;
>
> + /* Inconsistent Pre-allocated Trace header */
> + if (trace->nodelen !=
> + ioam6_trace_compute_nodelen(be32_to_cpu(trace->type_be32)))
> + goto drop;
> +
> /* Ignore if the IOAM namespace is unknown */
> ns = ioam6_namespace(dev_net(skb->dev), trace->namespace_id);
> if (!ns)
> diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
> index 9553a3200..08b7ac8c9 100644
> --- a/net/ipv6/ioam6.c
> +++ b/net/ipv6/ioam6.c
> @@ -690,6 +690,20 @@ struct ioam6_namespace *ioam6_namespace(struct net *net, __be16 id)
> return rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
> }
>
> +#define IOAM6_MASK_SHORT_FIELDS 0xff1ffc00
> +#define IOAM6_MASK_WIDE_FIELDS 0x00e00000
> +
> +u8 ioam6_trace_compute_nodelen(u32 trace_type)
> +{
> + u8 nodelen = hweight32(trace_type & IOAM6_MASK_SHORT_FIELDS)
> + * (sizeof(__be32) / 4);
> +
> + nodelen += hweight32(trace_type & IOAM6_MASK_WIDE_FIELDS)
> + * (sizeof(__be64) / 4);
> +
> + return nodelen;
> +}
> +
> static void __ioam6_fill_trace_data(struct sk_buff *skb,
> struct ioam6_namespace *ns,
> struct ioam6_trace_hdr *trace,
> diff --git a/net/ipv6/ioam6_iptunnel.c b/net/ipv6/ioam6_iptunnel.c
> index 1fe7894f1..b9f6d892a 100644
> --- a/net/ipv6/ioam6_iptunnel.c
> +++ b/net/ipv6/ioam6_iptunnel.c
> @@ -22,9 +22,6 @@
> #include <net/ip6_route.h>
> #include <net/addrconf.h>
>
> -#define IOAM6_MASK_SHORT_FIELDS 0xff100000
> -#define IOAM6_MASK_WIDE_FIELDS 0xe00000
> -
> struct ioam6_lwt_encap {
> struct ipv6_hopopt_hdr eh;
> u8 pad[2]; /* 2-octet padding for 4n-alignment */
> @@ -93,13 +90,8 @@ static bool ioam6_validate_trace_hdr(struct ioam6_trace_hdr *trace)
> trace->type.bit21 | trace->type.bit23)
> return false;
>
> - trace->nodelen = 0;
> fields = be32_to_cpu(trace->type_be32);
> -
> - trace->nodelen += hweight32(fields & IOAM6_MASK_SHORT_FIELDS)
> - * (sizeof(__be32) / 4);
> - trace->nodelen += hweight32(fields & IOAM6_MASK_WIDE_FIELDS)
> - * (sizeof(__be64) / 4);
> + trace->nodelen = ioam6_trace_compute_nodelen(fields);
>
> return true;
> }
LGTM, thanks.
Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH net v2] ipv6: ioam: fix heap buffer overflow in __ioam6_fill_trace_data()
2026-02-11 4:04 [PATCH net v2] ipv6: ioam: fix heap buffer overflow in __ioam6_fill_trace_data() Qanux
2026-02-11 20:20 ` Justin Iurman
@ 2026-02-13 20:30 ` patchwork-bot+netdevbpf
1 sibling, 0 replies; 3+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-02-13 20:30 UTC (permalink / raw)
To: Qanux; +Cc: netdev, justin.iurman, davem, edumazet, kuba, pabeni, horms,
dsahern
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 11 Feb 2026 12:04:12 +0800 you wrote:
> On the receive path, __ioam6_fill_trace_data() uses trace->nodelen
> to decide how much data to write for each node. It trusts this field
> as-is from the incoming packet, with no consistency check against
> trace->type (the 24-bit field that tells which data items are
> present). A crafted packet can set nodelen=0 while setting type bits
> 0-21, causing the function to write ~100 bytes past the allocated
> region (into skb_shared_info), which corrupts adjacent heap memory
> and leads to a kernel panic.
>
> [...]
Here is the summary with links:
- [net,v2] ipv6: ioam: fix heap buffer overflow in __ioam6_fill_trace_data()
https://git.kernel.org/netdev/net/c/6db8b56eed62
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-02-13 20:30 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-11 4:04 [PATCH net v2] ipv6: ioam: fix heap buffer overflow in __ioam6_fill_trace_data() Qanux
2026-02-11 20:20 ` Justin Iurman
2026-02-13 20:30 ` patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox