mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
ipv6: ioam: fix heap buffer overflow in __ioam6_fill_trace_data()
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: 9ee11f0fff ("ipv6: ioam: Data plane support for Pre-allocated Trace")
Cc: stable@vger.kernel.org
Signed-off-by: Junxi Qian <qjx1298677004@gmail.com>
Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
Link: https://patch.msgid.link/20260211040412.86195-1-qjx1298677004@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
a68a9bd086
commit
6db8b56eed
4 changed files with 22 additions and 9 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -931,6 +931,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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue