mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
ila: reload IPv6 header after pskb_may_pull in checksum adjust
ila_csum_adjust_transport() caches ip6h = ipv6_hdr(skb) before calling
pskb_may_pull(). On a non-linear skb whose transport header sits in a page
fragment, pskb_may_pull() can call __pskb_pull_tail() / pskb_expand_head()
and free the old skb head, leaving ip6h dangling; the following
get_csum_diff(ip6h, p) then reads freed memory. ila_update_ipv6_locator()
uses ip6h (and the iaddr derived from it) again after the csum-adjust
call and additionally writes the new locator through that pointer.
Impact: a remote IPv6 packet routed through a configured ILA
csum-adjust-transport route or receive-side mapping triggers a
slab-use-after-free in ila_update_ipv6_locator() (KASAN). The route or
mapping requires CAP_NET_ADMIN to configure, but trigger packets are
unauthenticated once it exists.
Reload ip6h after each pskb_may_pull() in ila_csum_adjust_transport()
before the csum-diff read. In ila_update_ipv6_locator() only the
ILA_CSUM_ADJUST_TRANSPORT case pulls the skb, so reload ip6h and iaddr in
that case alone before the destination-address write; the neutral-map
modes never pull and keep their cached pointers.
Fixes: 33f11d1614 ("ila: Create net/ipv6/ila directory")
Cc: stable@vger.kernel.org
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Antoine Tenart <atenart@kernel.org>
Link: https://patch.msgid.link/20260714114903.3763420-1-michael.bommarito@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
34a71f5361
commit
92d3817649
|
|
@ -85,6 +85,7 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
|
|||
struct tcphdr *th = (struct tcphdr *)
|
||||
(skb_network_header(skb) + nhoff);
|
||||
|
||||
ip6h = ipv6_hdr(skb);
|
||||
diff = get_csum_diff(ip6h, p);
|
||||
inet_proto_csum_replace_by_diff(&th->check, skb,
|
||||
diff, true, true);
|
||||
|
|
@ -96,6 +97,7 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
|
|||
(skb_network_header(skb) + nhoff);
|
||||
|
||||
if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
ip6h = ipv6_hdr(skb);
|
||||
diff = get_csum_diff(ip6h, p);
|
||||
inet_proto_csum_replace_by_diff(&uh->check, skb,
|
||||
diff, true, true);
|
||||
|
|
@ -110,6 +112,7 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
|
|||
struct icmp6hdr *ih = (struct icmp6hdr *)
|
||||
(skb_network_header(skb) + nhoff);
|
||||
|
||||
ip6h = ipv6_hdr(skb);
|
||||
diff = get_csum_diff(ip6h, p);
|
||||
inet_proto_csum_replace_by_diff(&ih->icmp6_cksum, skb,
|
||||
diff, true, true);
|
||||
|
|
@ -127,6 +130,15 @@ void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p,
|
|||
switch (p->csum_mode) {
|
||||
case ILA_CSUM_ADJUST_TRANSPORT:
|
||||
ila_csum_adjust_transport(skb, p);
|
||||
/*
|
||||
* ila_csum_adjust_transport() calls pskb_may_pull(), which can
|
||||
* reallocate the skb head and leave ip6h (and the iaddr derived
|
||||
* from it) dangling; reload both before the write below. The
|
||||
* other csum modes do not pull, so their cached pointers stay
|
||||
* valid.
|
||||
*/
|
||||
ip6h = ipv6_hdr(skb);
|
||||
iaddr = ila_a2i(&ip6h->daddr);
|
||||
break;
|
||||
case ILA_CSUM_NEUTRAL_MAP:
|
||||
if (sir2ila) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user