From eb0c18404c8943356f4aa164e5db9067b79ea93c Mon Sep 17 00:00:00 2001 From: Omar Ramadan Date: Mon, 28 Sep 2026 21:15:57 +0300 Subject: [PATCH] amt: pull the AMT header behind the transport header in amt_parse_type() A gateway's encap socket passes ICMP errors to amt_err_lookup(), which calls amt_parse_type() on the quoted datagram to see which AMT message failed. On that path skb->data points at the quoted IP header and the transport header at the quoted UDP header, and icmp_socket_deliver() only guarantees the quoted IP header plus 8 bytes, that is, up to the end of the UDP header. amt_parse_type() pulls sizeof(struct udphdr) + sizeof(struct amt_header) bytes from skb->data, which on this path stays inside the quoted IP header, and then reads the AMT header behind udp_hdr(skb). An ICMP error that quotes only the IP and UDP headers of a Request, the minimum RFC 792 asks for, therefore makes it read past the pulled data, and past the end of the packet when nothing follows. Pull up to the transport header plus the UDP and AMT headers, as vxlan_err_lookup() does. amt_rcv() is called with the transport header at skb->data, so the pull on the receive path does not change. Fixes: cbc21dc1cfe9 ("amt: add data plane of amt interface") Signed-off-by: Omar Ramadan Reviewed-by: Eric Dumazet Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20260928181557.85796-1-omar@blockcast.net Signed-off-by: Paolo Abeni --- drivers/net/amt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/amt.c b/drivers/net/amt.c index bddc24e1856d..0277e4cac39b 100644 --- a/drivers/net/amt.c +++ b/drivers/net/amt.c @@ -1310,8 +1310,12 @@ static int amt_parse_type(struct sk_buff *skb) { struct amt_header *amth; - if (!pskb_may_pull(skb, sizeof(struct udphdr) + - sizeof(struct amt_header))) + /* skb->data is the UDP header on receive, but the quoted IP header + * when amt_err_lookup() parses an ICMP error, so pull up to the + * transport header rather than from skb->data. + */ + if (!pskb_may_pull(skb, skb_transport_offset(skb) + + sizeof(struct udphdr) + sizeof(struct amt_header))) return -1; amth = (struct amt_header *)(udp_hdr(skb) + 1);