Skip to content

Commit 900f57e

Browse files
committed
net/ulp: prevent ULP without clone op from entering the LISTEN status
jira VULN-8789 cve CVE-2023-0461 commit-author Paolo Abeni <pabeni@redhat.com> commit 2c02d41 upstream-diff In inet_csk_listen_start ret is reinitialized to -EADDRINUSE after the new inet_ulp_can_listen check. The upstream change did not do this because err would inevitably be set later in the function in that version. In this kernel there is no future inevitable set of err so we need to set it back to -EADDRINUSE to ensure this function will return -EADDERINUSE if ->get_port() fails. See LT 5.10 commit fdaf885 for the inspiration for this upstream-diff When an ULP-enabled socket enters the LISTEN status, the listener ULP data pointer is copied inside the child/accepted sockets by sk_clone_lock(). The relevant ULP can take care of de-duplicating the context pointer via the clone() operation, but only MPTCP and SMC implement such op. Other ULPs may end-up with a double-free at socket disposal time. We can't simply clear the ULP data at clone time, as TLS replaces the socket ops with custom ones assuming a valid TLS ULP context is available. Instead completely prevent clone-less ULP sockets from entering the LISTEN status. Fixes: 734942c ("tcp: ULP infrastructure") Reported-by: slipper <slipper.alive@gmail.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Link: https://lore.kernel.org/r/4b80c3d1dbe3d0ab072f80450c202d9bc88b4b03.1672740602.git.pabeni@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> (cherry picked from commit 2c02d41) Signed-off-by: Brett Mastbergen <bmastbergen@ciq.com>
1 parent fb31b6a commit 900f57e

File tree

2 files changed

+19
-0
lines changed

2 files changed

+19
-0
lines changed

net/ipv4/inet_connection_sock.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,12 +900,27 @@ void inet_csk_prepare_forced_close(struct sock *sk)
900900
}
901901
EXPORT_SYMBOL(inet_csk_prepare_forced_close);
902902

903+
static int inet_ulp_can_listen(const struct sock *sk)
904+
{
905+
const struct inet_connection_sock *icsk = inet_csk(sk);
906+
907+
if (icsk->icsk_ulp_ops && !icsk->icsk_ulp_ops->clone)
908+
return -EINVAL;
909+
910+
return 0;
911+
}
912+
903913
int inet_csk_listen_start(struct sock *sk, int backlog)
904914
{
905915
struct inet_connection_sock *icsk = inet_csk(sk);
906916
struct inet_sock *inet = inet_sk(sk);
907917
int err = -EADDRINUSE;
908918

919+
err = inet_ulp_can_listen(sk);
920+
if (unlikely(err))
921+
return err;
922+
923+
err = -EADDRINUSE;
909924
reqsk_queue_alloc(&icsk->icsk_accept_queue);
910925

911926
sk->sk_ack_backlog = 0;

net/ipv4/tcp_ulp.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops)
131131
if (icsk->icsk_ulp_ops)
132132
goto out_err;
133133

134+
err = -EINVAL;
135+
if (!ulp_ops->clone && sk->sk_state == TCP_LISTEN)
136+
goto out_err;
137+
134138
err = ulp_ops->init(sk);
135139
if (err)
136140
goto out_err;

0 commit comments

Comments
 (0)