From 65734bbe4a9fb78fca55b27c969656bfad1c7dc3 Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Thu, 10 Sep 2026 13:53:15 -0400 Subject: [PATCH] net: preserve socketpair output on setup failure socketpair() writes the reserved descriptor numbers to userspace before creating the sockets and their file objects. A later failure therefore leaves a modified caller's array despite returning an error, contrary to POSIX. For example, socketpair(AF_UNIX, SOCK_STREAM, -1, fd) returns EPROTONOSUPPORT but replaces the array's sentinel values with unused fd numbers. Defer the output stores until both file objects have been created, before installing either descriptor. If a store faults, drop both file references before releasing the reserved descriptor slots. Keep the early descriptor reservation and the existing setup-failure cleanup paths. In practice, I doubt anyone notices. But this aligns with the expected behavior Signed-off-by: Steve Grubb Link: https://patch.msgid.link/JyK226D0S5CWGUpAC4MO4A@redhat.com Signed-off-by: Jakub Kicinski --- net/socket.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/net/socket.c b/net/socket.c index c05d86e63abf..4cb8662869f0 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1851,10 +1851,7 @@ int __sys_socketpair(int family, int type, int protocol, int __user *usockvec) if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; - /* - * reserve descriptors and make sure we won't fail - * to return them to userland. - */ + /* Reserve both descriptors before creating the sockets. */ fd1 = get_unused_fd_flags(flags); if (unlikely(fd1 < 0)) return fd1; @@ -1865,14 +1862,6 @@ int __sys_socketpair(int family, int type, int protocol, int __user *usockvec) return fd2; } - err = put_user(fd1, &usockvec[0]); - if (err) - goto out; - - err = put_user(fd2, &usockvec[1]); - if (err) - goto out; - /* * Obtain the first socket and check if the underlying protocol * supports the socketpair call. @@ -1916,6 +1905,16 @@ int __sys_socketpair(int family, int type, int protocol, int __user *usockvec) goto out; } + /* Publish the descriptors now that it shouldn't fail. */ + err = put_user(fd1, &usockvec[0]); + if (!err) + err = put_user(fd2, &usockvec[1]); + if (err) { + fput(newfile2); + fput(newfile1); + goto out; + } + audit_fd_pair(fd1, fd2); fd_install(fd1, newfile1);