From patchwork Mon Mar 31 20:10:55 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Metzmacher X-Patchwork-Id: 14033911 Received: from hr2.samba.org (hr2.samba.org [144.76.82.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4E38621B9C1; Mon, 31 Mar 2025 20:12:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=144.76.82.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743451957; cv=none; b=bgPsN6Ed7IMjf1ym7TnVwWDCMN1WijyIGr9tSbr726uhg433dhVpqs4EKPuFnHnSR1pxCWJrpxOy/tTaZ+DxC8eflPJjXDIFUp4AIi0c4TG2k0sMYMDw+OLTW3E0/RBwCBT0QGRSBQOgjSU/QrEutHlfgwayRSftotPeD6leVbg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743451957; c=relaxed/simple; bh=M2Fp7exY4cxRbGe1lOl1dPG0xLZZ+A8jahAEIaGY12s=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=k827yxB8GsXdz/7zyqXqNPioYyyftKJeJfgGGFCBFzuvKm15w0L2mqwW7Cz4wmDK7k8eUVV7fnfPFwKZ/++uTQSa+HuntmCjmNPx/5WpBTeNn5TQBLvlE7NW+G1ZygBigArYjbx/n8gHia7+XwgBS3oVTDSxKMv0nmSgQyC9kjY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=samba.org; spf=pass smtp.mailfrom=samba.org; dkim=pass (3072-bit key) header.d=samba.org header.i=@samba.org header.b=utyKiDRo; arc=none smtp.client-ip=144.76.82.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=samba.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=samba.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (3072-bit key) header.d=samba.org header.i=@samba.org header.b="utyKiDRo" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=samba.org; s=42; h=Message-Id:Date:Cc:To:From; bh=F2PVnOBJYHIqIOs+UI7Bgnf84OIiQjHeCtccLCUmP1A=; b=utyKiDRouLC30Mip7B0Rdp/0UF lX4zlJy9xyEqAZfMk5bmwlArknGpBTZCx9x+KtkujSyR4YIfAQBtD2oDZbzN9fpOwy3+eEgciLSTl hQv+KJriEUECzmzS/Ypj+2bXC7ykTD0oJHESqgonh2sUlmznRNURVlDrHv8CW9JomQ3gBU+3Tb3dO U+55Fxx3rWiqs2FRTHh+TZn5II+ahLpdwnLNH48FsaOGBq8VUDPbqQr83p3nsYTtvUpPUM62AQUpK 6IKiNKDUG2h9yJjz6ZEDFfOlfZjLnrD0eFEB7DLTytNriY+ER0J4TZ8EfQJFkZ5ZQLEIJCLReN0hK tCaSqIl2WUM5pFmE2EUGm+M/48P9v6fxAeTSHmq4ws8RvrQ4ZELgOv2GOWpGJflYZFsK6NH/8xm/H iy2r+DC+YRP84swgbSb91M6IpBl9WO3gBdGmN3DdCDFx5lH6EbfXY4UThQ64yw1gzAxKMRX3azfYd Gob0TDZg6JCGblq1aQTLbCW+; Received: from [127.0.0.2] (localhost [127.0.0.1]) by hr2.samba.org with esmtpsa (TLS1.3:ECDHE_SECP256R1__ECDSA_SECP256R1_SHA256__CHACHA20_POLY1305:256) (Exim) id 1tzLUm-007Y8E-3A; Mon, 31 Mar 2025 20:12:33 +0000 From: Stefan Metzmacher To: Linus Torvalds , Jens Axboe Cc: Stefan Metzmacher , Pavel Begunkov , Breno Leitao , Jakub Kicinski , Christoph Hellwig , Karsten Keil , Ayush Sawal , Andrew Lunn , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Kuniyuki Iwashima , Willem de Bruijn , David Ahern , Marcelo Ricardo Leitner , Xin Long , Neal Cardwell , Joerg Reuter , Marcel Holtmann , Johan Hedberg , Luiz Augusto von Dentz , Oliver Hartkopp , Marc Kleine-Budde , Robin van der Gracht , Oleksij Rempel , kernel@pengutronix.de, Alexander Aring , Stefan Schmidt , Miquel Raynal , Alexandra Winter , Thorsten Winkler , James Chapman , Jeremy Kerr , Matt Johnston , Matthieu Baerts , Mat Martineau , Geliang Tang , Krzysztof Kozlowski , Remi Denis-Courmont , Allison Henderson , David Howells , Marc Dionne , Wenjia Zhang , Jan Karcher , "D. Wythe" , Tony Lu , Wen Gu , Jon Maloy , Boris Pismenny , John Fastabend , Stefano Garzarella , Martin Schiller , =?utf-8?b?QmrDtnJuIFTDtnBlbA==?= , Magnus Karlsson , Maciej Fijalkowski , Jonathan Lemon , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-sctp@vger.kernel.org, linux-hams@vger.kernel.org, linux-bluetooth@vger.kernel.org, linux-can@vger.kernel.org, dccp@vger.kernel.org, linux-wpan@vger.kernel.org, linux-s390@vger.kernel.org, mptcp@lists.linux.dev, linux-rdma@vger.kernel.org, rds-devel@oss.oracle.com, linux-afs@lists.infradead.org, tipc-discussion@lists.sourceforge.net, virtualization@lists.linux.dev, linux-x25@vger.kernel.org, bpf@vger.kernel.org, isdn4linux@listserv.isdn4linux.de, io-uring@vger.kernel.org Subject: [RFC PATCH 3/4] net: pass a kernel pointer via 'optlen_t' to proto[ops].getsockopt() hooks Date: Mon, 31 Mar 2025 22:10:55 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The motivation for this is to remove the SOL_SOCKET limitation from io_uring_cmd_getsockopt(). The reason for this limitation is that io_uring_cmd_getsockopt() passes a kernel pointer. The first idea would be to change the optval and optlen arguments to the protocol specific hooks also to sockptr_t, as that is already used for setsockopt() and also by do_sock_getsockopt() sk_getsockopt() and BPF_CGROUP_RUN_PROG_GETSOCKOPT(). But as Linus don't like 'sockptr_t' I used a different approach. Instead of passing the optlen as user or kernel pointer, we only ever pass a kernel pointer and do the translation from/to userspace in do_sock_getsockopt(). The simple solution would be to just remove the '__user' from the int *optlen argument, but it seems the compiler doesn't complain about '__user' vs. without it, so instead I used a helper struct in order to make sure everything compiles with a typesafe change. That together with get_optlen() and put_optlen() helper macros make it relatively easy to review and check the behaviour is most likely unchanged. In order to avoid uapi changes regarding different error code orders regarding -EFAULT, the real -EFAULT handling is deferred to get_optlen() and put_optlen(). This allows io_uring_cmd_getsockopt() to remove the SOL_SOCKET limitation. Removing 'sockptr_t optlen' from existing code is for patch for another day. Link: https://lore.kernel.org/io-uring/86b1dce5-4bb4-4a0b-9cff-e72f488bf57d@samba.org/T/#t Cc: Jens Axboe Cc: Pavel Begunkov Cc: Breno Leitao Cc: Linus Torvalds Cc: Jakub Kicinski Cc: Christoph Hellwig Cc: Karsten Keil Cc: Ayush Sawal Cc: Andrew Lunn Cc: "David S. Miller" Cc: Eric Dumazet Cc: Paolo Abeni Cc: Simon Horman Cc: Kuniyuki Iwashima Cc: Willem de Bruijn Cc: David Ahern Cc: Marcelo Ricardo Leitner Cc: Xin Long Cc: Neal Cardwell Cc: Joerg Reuter Cc: Marcel Holtmann Cc: Johan Hedberg Cc: Luiz Augusto von Dentz Cc: Oliver Hartkopp Cc: Marc Kleine-Budde Cc: Robin van der Gracht Cc: Oleksij Rempel Cc: kernel@pengutronix.de Cc: Alexander Aring Cc: Stefan Schmidt Cc: Miquel Raynal Cc: Alexandra Winter Cc: Thorsten Winkler Cc: James Chapman Cc: Jeremy Kerr Cc: Matt Johnston Cc: Matthieu Baerts Cc: Mat Martineau Cc: Geliang Tang Cc: Krzysztof Kozlowski Cc: Remi Denis-Courmont Cc: Allison Henderson Cc: David Howells Cc: Marc Dionne Cc: Wenjia Zhang Cc: Jan Karcher Cc: "D. Wythe" Cc: Tony Lu Cc: Wen Gu Cc: Jon Maloy Cc: Boris Pismenny Cc: John Fastabend Cc: Stefano Garzarella Cc: Martin Schiller Cc: "Björn Töpel" Cc: Magnus Karlsson Cc: Maciej Fijalkowski Cc: Jonathan Lemon Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Jesper Dangaard Brouer CC: Stefan Metzmacher Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-sctp@vger.kernel.org Cc: linux-hams@vger.kernel.org Cc: linux-bluetooth@vger.kernel.org Cc: linux-can@vger.kernel.org Cc: dccp@vger.kernel.org Cc: linux-wpan@vger.kernel.org Cc: linux-s390@vger.kernel.org Cc: mptcp@lists.linux.dev Cc: linux-rdma@vger.kernel.org Cc: rds-devel@oss.oracle.com Cc: linux-afs@lists.infradead.org Cc: tipc-discussion@lists.sourceforge.net Cc: virtualization@lists.linux.dev Cc: linux-x25@vger.kernel.org Cc: bpf@vger.kernel.org Cc: isdn4linux@listserv.isdn4linux.de Cc: io-uring@vger.kernel.org Signed-off-by: Stefan Metzmacher --- include/linux/sockptr.h | 20 +++++++++++++++----- net/socket.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/include/linux/sockptr.h b/include/linux/sockptr.h index 1baf66f26f4f..06ec7fd73028 100644 --- a/include/linux/sockptr.h +++ b/include/linux/sockptr.h @@ -170,20 +170,25 @@ static inline int check_zeroed_sockptr(sockptr_t src, size_t offset, } typedef struct { - int __user *up; + int *kp; } optlen_t; #define __check_optlen_t(__optlen) \ ({ \ optlen_t *__ptr __maybe_unused = &__optlen; \ - BUILD_BUG_ON(sizeof(*((__ptr)->up)) != sizeof(int)); \ + BUILD_BUG_ON(sizeof(*((__ptr)->kp)) != sizeof(int)); \ }) #define get_optlen(__val, __optlen) \ ({ \ long __err; \ __check_optlen_t(__optlen); \ - __err = get_user(__val, __optlen.up); \ + if ((__optlen).kp != NULL) { \ + (__val) = *((__optlen).kp); \ + __err = 0; \ + } else { \ + __err = -EFAULT; \ + } \ __err; \ }) @@ -191,13 +196,18 @@ typedef struct { ({ \ long __err; \ __check_optlen_t(__optlen); \ - __err = put_user(__val, __optlen.up); \ + if ((__optlen).kp != NULL) { \ + *((__optlen).kp) = (__val); \ + __err = 0; \ + } else { \ + __err = -EFAULT; \ + } \ __err; \ }) static inline sockptr_t OPTLEN_SOCKPTR(optlen_t optlen) { - return (sockptr_t) { .user = optlen.up, }; + return (sockptr_t) { .kernel = optlen.kp, .is_kernel = true }; } #endif /* _LINUX_SOCKPTR_H */ diff --git a/net/socket.c b/net/socket.c index fa2de12c10e6..81e5c9767bbc 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2350,15 +2350,42 @@ int do_sock_getsockopt(struct socket *sock, bool compat, int level, } else if (unlikely(!ops->getsockopt)) { err = -EOPNOTSUPP; } else { - optlen_t _optlen = { .up = NULL, }; + optlen_t _optlen = { .kp = NULL, }; + int koptlen; if (WARN_ONCE(optval.is_kernel, "Invalid argument type")) return -EOPNOTSUPP; - _optlen.up = optlen.user; + if (optlen.is_kernel) { + _optlen.kp = optlen.kernel; + } else if (optlen.user != NULL) { + /* + * If optlen.user is NULL, + * we pass _optlen.kp = NULL + * in order to avoid breaking + * any uapi for getsockopt() + * implementations that ignore + * the optlen pointer completely + * or do any level and optname + * checking before hitting a + * potential -EFAULT condition. + * + * Also when optlen.user is not NULL, + * but copy_from_sockptr() causes -EFAULT, + * we'll pass optlen.kp = NULL in order + * to defer a possible -EFAULT return + * to the caller to get_optlen() and put_optlen(). + */ + if (copy_from_sockptr(&koptlen, optlen, sizeof(koptlen)) == 0) + _optlen.kp = &koptlen; + } err = ops->getsockopt(sock, level, optname, optval.user, _optlen); + if (err != -EFAULT && _optlen.kp == &koptlen) { + if (copy_to_sockptr(optlen, &koptlen, sizeof(koptlen))) + return -EFAULT; + } } if (!compat)