on transmit, skb->decrypted means the device must encrypt the skb. if it can't do that, then the packet should be dropped, not transmitted in the clear. ip_do_fragment() and ip6_fragment() on a decrypted skb produce fragments which have skb->decrypted unset, and can be sent out unencrypted. tx of individually encrypted fragments would not work anyway, because encrypting needs the L4 header, which non-initial fragments do not have. ktls could encrypt in sw before fragmenting. that would not work for psp offload which does not have a software fallback path. tcp sizes segments to the mtu, so psp and ktls socket packets normally won't reach this path. an ipv4 tcp socket can be made to send fragments by setting a route mtu above the device mtu and disabling pmtud on the socket (IP_PMTUDISC_OMIT). the selftest later in the series does this. emitting fragments from an ipv6 tcp socket requires more steps, but is also possible. the test setup here uses ipvs, which sets ignore_df on forwarded packets. in ip6_fragment(), check skb->decrypted after the too-big checks, so that a local socket still gets PKT_TOOBIG for path mtu discovery. tested with tls tx offload on mlx5 (connectx-7), over ipv4. without this patch some fragments after the first go out in cleartext, with it they're dropped (IpFragFails) and the connection stalls. tested over ipv6, with tls tx offload and psp on mlx5 (connectx-7), through an ipvs dr service with a local client. without this patch, fragments after the first go out in cleartext, and the peer reassembles them; with it they're dropped (Ip6FragFails). Fixes: e8f69799810c ("net/tls: Add generic NIC offload infrastructure") Fixes: 659a2899a57d ("tcp: add datapath logic for PSP with inline key exchange") Signed-off-by: Todd Freed --- net/ipv4/ip_output.c | 8 ++++++++ net/ipv6/ip6_output.c | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index d42d776af273..94a40e7ed534 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -770,6 +770,14 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, struct ip_frag_state state; int err = 0; + /* PSP and TLS offload need the packet's L4 header, which non-initial + * fragments do not have. + */ + if (unlikely(skb_is_decrypted(skb))) { + err = -EMSGSIZE; + goto fail; + } + /* for offloaded checksums cleanup checksum before fragmentation */ if (skb->ip_summed == CHECKSUM_PARTIAL) { err = ip_check_csum_start(skb); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 25fe0ba98b1a..5f19d170ed29 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -929,6 +929,15 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, mtu = IPV6_MIN_MTU; } + /* PSP and TLS offload need the packet's L4 header, which non-initial + * fragments do not have. Checked after the too-big checks above, + * so that PMTUD for a local socket works. + */ + if (unlikely(skb_is_decrypted(skb))) { + err = -EMSGSIZE; + goto fail; + } + if (np) { u32 frag_size = READ_ONCE(np->frag_size); -- 2.53.0-Meta