[PATCH net v4 3/7] ipv4: icmp: don't quote decrypted payload in icmp errors
flat view
HOTtoday
From: Todd Freed <hidden>
Date: 2026-11-03 00:12:12
Also in:
linux-kselftest
Subsystem:
networking [general], networking [ipv4/ipv6], psp security protocol, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Daniel Zahka, Willem de Bruijn, Linus Torvalds
an icmp error quotes as much of the invoking packet as fits in 576 bytes. if the device had decrypted the packet (as indicated by skb->decrypted) then the icmp error is sending part of it back out onto the network in cleartext. the two offloads encrypt different parts of the packet: - ktls rx device offload decrypts the tls records in the tcp payload. the tcp header was in the clear on the wire, so quote the ip header and the tcp header, options included, and leave out the rfc 4884 extension, which would carry the payload too. - psp encryption also covers the tcp header. the quote could include just the ip header, but that's not really useful. linux receivers want to look at the l4 layer on the quoted packet, so such a truncated icmp error packet is just dropped (icmp_socket_deliver()). don't send the error at all for psp. a decrypted psp skb has SKB_EXT_PSP, which is used to distinguish the two cases. note though that if an inner tunnel is decapsulated, skb_scrub_packet() drops the extension but keeps skb->decrypted, so an error about the inner packet takes the ktls path in this case (quote includes the l4 header), which is less than before. on tx, skb->decrypted is also set. an error about a locally originated skb (skb_iif is 0) is sent in full as before, if it goes to a local address, as determined by the packet's source address. Reported-by: Sashiko <sashiko-bot@kernel.org> Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261023234640.1459291-1-toddfreed%40meta.com Suggested-by: Jakub Kicinski <kuba@kernel.org> Suggested-by: Björn Töpel <bjorn@kernel.org> Fixes: 784abe24c903 ("net: Add decrypted field to skb") Signed-off-by: Todd Freed <redacted> --- include/net/psp/functions.h | 11 ++++++++ net/ipv4/icmp.c | 54 +++++++++++++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 5 deletions(-)
diff --git a/include/net/psp/functions.h b/include/net/psp/functions.h
index c5c23a54774e..b263b573ae4c 100644
--- a/include/net/psp/functions.h
+++ b/include/net/psp/functions.h@@ -51,6 +51,12 @@ psp_enqueue_set_decrypted(struct sock *sk, struct sk_buff *skb) skb->decrypted = 1; } +/* The device decrypted @skb with psp, on receive */ +static inline bool psp_skb_is_decrypted(const struct sk_buff *skb) +{ + return skb_ext_find(skb, SKB_EXT_PSP); +} + static inline unsigned long __psp_skb_coalesce_diff(const struct sk_buff *one, const struct sk_buff *two, unsigned long diffs)
@@ -170,6 +176,11 @@ static inline struct psp_assoc *psp_sk_assoc(const struct sock *sk) static inline void psp_enqueue_set_decrypted(struct sock *sk, struct sk_buff *skb) { } +static inline bool psp_skb_is_decrypted(const struct sk_buff *skb) +{ + return false; +} + static inline unsigned long __psp_skb_coalesce_diff(const struct sk_buff *one, const struct sk_buff *two, unsigned long diffs)
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 90c0e22c29be..d522488475b6 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c@@ -78,6 +78,7 @@ #include <net/ip.h> #include <net/route.h> #include <net/protocol.h> +#include <net/psp/functions.h> #include <net/icmp.h> #include <net/tcp.h> #include <net/udp.h>
@@ -823,7 +824,8 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info, int room; struct rtable *rt = skb_rtable(skb_in); bool apply_ratelimit = false; - struct sk_buff *ext_skb; + struct sk_buff *ext_skb = NULL; + bool decrypted = false; struct ipcm_cookie ipc; struct flowi4 fl4; __be32 saddr;
@@ -979,6 +981,32 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info, if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) goto ende; + /* Don't send the decrypted part of an skb onto the network */ + if (unlikely(skb_is_decrypted(skb_in))) { + if (!skb_in->skb_iif) { + /* A locally originated skb to be encrypted. Permit + * the packet to be quoted, if its source address is + * local. otherwise skip. + */ + if (!(rt->rt_flags & RTCF_LOCAL)) + goto ende; + } else if (psp_skb_is_decrypted(skb_in)) { + /* PSP encrypts the transport header too, so it should + * not be quoted. But an error whose quote is truncated + * to fewer than 8 bytes of the transport header won't + * be processed, so just skip it. + */ + goto ende; + } else { + /* TLS offload leaves the tcp header in the clear and + * so can be quoted up to its end. A psp skb whose inner + * tunnel was decapsulated also ends up here, since + * skb_scrub_packet() drops SKB_EXT_PSP. + */ + decrypted = true; + } + } + /* peer icmp_ratelimit */ if (!icmpv4_xrlim_allow(net, rt, &fl4, type, code, apply_ratelimit)) goto ende;
@@ -996,10 +1024,26 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info, if (room <= (int)sizeof(struct iphdr)) goto ende; - ext_skb = icmp_ext_append(net, skb_in, &icmp_param->data.icmph, room, - parm->iif); - if (ext_skb) - icmp_param->skb = ext_skb; + if (unlikely(decrypted)) { + /* Quote up to the end of the tcp header. The RFC 4884 + * extension would carry the payload too. + */ + int len = iph->ihl * 4 + 8; + const struct tcphdr *th; + struct tcphdr _th; + + th = skb_header_pointer(skb_in, skb_network_offset(skb_in) + + iph->ihl * 4, sizeof(_th), &_th); + if (th && iph->protocol == IPPROTO_TCP) + len = iph->ihl * 4 + max_t(int, th->doff * 4, 8); + room = min_t(int, room, len); + } else { + ext_skb = icmp_ext_append(net, skb_in, + &icmp_param->data.icmph, room, + parm->iif); + if (ext_skb) + icmp_param->skb = ext_skb; + } icmp_param->data_len = icmp_param->skb->len - icmp_param->offset; if (icmp_param->data_len > room)
--
2.53.0-Meta