]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
sctp: Use sctp_clone_sock() in sctp_do_peeloff().
authorKuniyuki Iwashima <kuniyu@google.com>
Thu, 23 Oct 2025 23:16:56 +0000 (23:16 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 28 Oct 2025 01:04:58 +0000 (18:04 -0700)
sctp_do_peeloff() calls sock_create() to allocate and initialise
struct sock, inet_sock, and sctp_sock, but later sctp_copy_sock()
and sctp_sock_migrate() overwrite most fields.

What sctp_do_peeloff() does is more like accept().

Let's use sock_create_lite() and sctp_clone_sock().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Acked-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/20251023231751.4168390-8-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/af_inet.c
net/sctp/socket.c

index 77f6ae0fc231d8e0f45e78b95cb5bd83189965a4..0784e2a873a15fea6535b234e053cb66cca5a721 100644 (file)
@@ -788,6 +788,7 @@ void __inet_accept(struct socket *sock, struct socket *newsock, struct sock *new
 
        newsock->state = SS_CONNECTED;
 }
+EXPORT_SYMBOL_GPL(__inet_accept);
 
 /*
  *     Accept a pending connection. The TCP layer now gives BSD semantics.
index 826f17747f176e7b7ddd95a935aa8d10a5f19f77..60d3e340dfedac2bd6c290a6044b9c0daa8ee246 100644 (file)
@@ -5671,11 +5671,11 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv
 
 /* Helper routine to branch off an association to a new socket.  */
 static int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id,
-               struct socket **sockp)
+                          struct socket **sockp)
 {
        struct sctp_association *asoc = sctp_id2assoc(sk, id);
-       struct sctp_sock *sp = sctp_sk(sk);
        struct socket *sock;
+       struct sock *newsk;
        int err = 0;
 
        /* Do not peel off from one netns to another one. */
@@ -5691,30 +5691,24 @@ static int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id,
        if (!sctp_style(sk, UDP))
                return -EINVAL;
 
-       /* Create a new socket.  */
-       err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock);
-       if (err < 0)
+       err = sock_create_lite(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock);
+       if (err)
                return err;
 
-       sctp_copy_sock(sock->sk, sk, asoc);
-
-       /* Make peeled-off sockets more like 1-1 accepted sockets.
-        * Set the daddr and initialize id to something more random and also
-        * copy over any ip options.
-        */
-       sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sock->sk);
-       sp->pf->copy_ip_options(sk, sock->sk);
-
-       /* Populate the fields of the newsk from the oldsk and migrate the
-        * asoc to the newsk.
-        */
-       err = sctp_sock_migrate(sk, sock->sk, asoc,
-                               SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
-       if (err) {
+       newsk = sctp_clone_sock(sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
+       if (IS_ERR(newsk)) {
                sock_release(sock);
-               sock = NULL;
+               *sockp = NULL;
+               return PTR_ERR(newsk);
        }
 
+       lock_sock_nested(newsk, SINGLE_DEPTH_NESTING);
+       __inet_accept(sk->sk_socket, sock, newsk);
+       release_sock(newsk);
+
+       sock->ops = sk->sk_socket->ops;
+       __module_get(sock->ops->owner);
+
        *sockp = sock;
 
        return err;