diff --git a/Documentation/networking/psp.rst b/Documentation/networking/psp.rst index 4ac09e64e95a..0f9b6b73f244 100644 --- a/Documentation/networking/psp.rst +++ b/Documentation/networking/psp.rst @@ -132,6 +132,14 @@ numbers in a way that deletes a prefix of the PSP protected part of the TCP stream. If userspace cares to mitigate this type of attack, a special "start of PSP" message should be exchanged after ``tx-assoc``. +Upgrade to PSP must be done on established TCP connections. +``rx-assoc`` and ``tx-assoc`` will return ``-ENOTCONN`` if +``sk_state`` is not ``TCP_ESTABLISHED``. + +The PSP assoc state of a socket is not reset when the connection is +torn down. ``connect()`` on a socket that has PSP assoc state will +return ``-EINVAL``. + Rotation notifications ---------------------- diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index c107b7e44e5b..410d63d9e5c1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -238,6 +238,9 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len if (usin->sin_family != AF_INET) return -EAFNOSUPPORT; + if (psp_sk_assoc(sk)) + return -EINVAL; + nexthop = daddr = usin->sin_addr.s_addr; inet_opt = rcu_dereference_protected(inet->inet_opt, lockdep_sock_is_held(sk)); @@ -291,9 +294,9 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len inet->inet_dport = usin->sin_port; sk_daddr_set(sk, daddr); - inet_csk(sk)->icsk_ext_hdr_len = psp_sk_overhead(sk); + inet_csk(sk)->icsk_ext_hdr_len = 0; if (inet_opt) - inet_csk(sk)->icsk_ext_hdr_len += inet_opt->opt.optlen; + inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen; tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index afb4d8e9fa67..e006a30360ea 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -153,6 +153,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr_unsized *uaddr, if (usin->sin6_family != AF_INET6) return -EAFNOSUPPORT; + if (psp_sk_assoc(sk)) + return -EINVAL; + fl6 = &inet_sk(sk)->cork.fl.u.ip6; memset(fl6, 0, sizeof(*fl6)); @@ -311,10 +314,10 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr_unsized *uaddr, sk->sk_gso_type = SKB_GSO_TCPV6; ip6_dst_store(sk, dst, false, false); - icsk->icsk_ext_hdr_len = psp_sk_overhead(sk); + icsk->icsk_ext_hdr_len = 0; if (opt) - icsk->icsk_ext_hdr_len += opt->opt_flen + - opt->opt_nflen; + icsk->icsk_ext_hdr_len = opt->opt_flen + + opt->opt_nflen; tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); diff --git a/net/psp/psp_sock.c b/net/psp/psp_sock.c index a9cfeebe4ba1..a6b1c42dd626 100644 --- a/net/psp/psp_sock.c +++ b/net/psp/psp_sock.c @@ -159,6 +159,12 @@ int psp_sock_assoc_set_rx(struct sock *sk, struct psp_assoc *pas, lock_sock(sk); + if (sk->sk_state != TCP_ESTABLISHED) { + NL_SET_ERR_MSG(extack, "Socket must be in established state"); + err = -ENOTCONN; + goto exit_unlock; + } + if (psp_sk_assoc(sk)) { NL_SET_ERR_MSG(extack, "Socket already has PSP state"); err = -EBUSY; @@ -252,6 +258,12 @@ int psp_sock_assoc_set_tx(struct sock *sk, struct psp_dev *psd, lock_sock(sk); + if (sk->sk_state != TCP_ESTABLISHED) { + NL_SET_ERR_MSG(extack, "Socket must be in established state"); + err = -ENOTCONN; + goto exit_unlock; + } + pas = psp_sk_assoc(sk); if (!pas) { NL_SET_ERR_MSG(extack, "Socket has no Rx key");