PSP conflicts with TLS ULP in its usage of both skb->decrypted and
sk->sk_validate_xmit_skb(). Offloaded TLS conflicts on both sides in
both Tx and Rx. SW TLS could mistake skb->decrypted in the Rx path set
by a PSP device as being a decrypted TLS record.

Prevent PSP from being used with other socket features that use
skb->decrypted or sk->sk_validate_xmit_skb().

For now, we include all TCP ULPs in the sk_has_decrypt_user() check,
even though TLS is the only one that conflicts with PSP via the
decrypted bit. This is intentional because PSP was not designed to be
used with ULPs. It is best to close off surface area that may make bugs
reachable, until someone wishes to design and test an actual user of PSP
with ULPs.

Fixes: 6b46ca260e22 ("net: psp: add socket security association code")
Signed-off-by: Daniel Zahka <[email protected]>
---
 include/net/sock.h | 11 +++++++++++
 net/core/sock.c    |  7 +++++++
 net/ipv4/tcp_ulp.c |  4 ++++
 net/psp/psp_sock.c |  4 ++++
 4 files changed, 26 insertions(+)

diff --git a/include/net/sock.h b/include/net/sock.h
index 51185222aac2..ba5e5092f192 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2312,6 +2312,17 @@ static inline void sk_gso_disable(struct sock *sk)
        sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
 }
 
+static inline bool sk_has_validate_xmit_skb(const struct sock *sk)
+{
+#ifdef CONFIG_SOCK_VALIDATE_XMIT
+       return !!sk->sk_validate_xmit_skb;
+#else
+       return false;
+#endif
+}
+
+bool sk_has_decrypt_user(const struct sock *sk);
+
 static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff 
*skb,
                                           struct iov_iter *from, char *to,
                                           int copy, int offset)
diff --git a/net/core/sock.c b/net/core/sock.c
index fa60b7494c58..9489d9c47949 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -142,6 +142,7 @@
 
 #include <trace/events/sock.h>
 
+#include <net/psp.h>
 #include <net/tcp.h>
 #include <net/busy_poll.h>
 #include <net/phonet/phonet.h>
@@ -2670,6 +2671,12 @@ void sk_setup_caps(struct sock *sk, struct dst_entry 
*dst)
 }
 EXPORT_SYMBOL_GPL(sk_setup_caps);
 
+bool sk_has_decrypt_user(const struct sock *sk)
+{
+       return psp_sk_assoc(sk) ||
+              (sk_is_inet(sk) && inet_csk_has_ulp(sk)); /* for tls */
+}
+
 /*
  *     Simple resource managers for sockets.
  */
diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c
index 2aa442128630..f3e0c9d379bb 100644
--- a/net/ipv4/tcp_ulp.c
+++ b/net/ipv4/tcp_ulp.c
@@ -136,6 +136,10 @@ static int __tcp_set_ulp(struct sock *sk, const struct 
tcp_ulp_ops *ulp_ops)
        if (icsk->icsk_ulp_ops)
                goto out_err;
 
+       err = -EINVAL;
+       if (sk_has_decrypt_user(sk) || sk_has_validate_xmit_skb(sk))
+               goto out_err;
+
        if (sk->sk_socket)
                clear_bit(SOCK_SUPPORT_ZC, &sk->sk_socket->flags);
 
diff --git a/net/psp/psp_sock.c b/net/psp/psp_sock.c
index 1a2a6b7516b0..509035617894 100644
--- a/net/psp/psp_sock.c
+++ b/net/psp/psp_sock.c
@@ -143,6 +143,10 @@ int psp_sock_assoc_set_rx(struct sock *sk, struct 
psp_assoc *pas,
                NL_SET_ERR_MSG(extack, "Socket already has PSP state");
                err = -EBUSY;
                goto exit_unlock;
+       } else if (sk_has_decrypt_user(sk) || sk_has_validate_xmit_skb(sk)) {
+               NL_SET_ERR_MSG(extack, "Socket has incompatible state");
+               err = -EINVAL;
+               goto exit_unlock;
        }
 
        refcount_inc(&pas->refcnt);

-- 
2.52.0


Reply via email to