From nobody Fri Sep 25 10:03:43 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 CCDF33515ED; Mon, 14 Sep 2026 12:20:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388424; cv=none; b=AUGahyK1Yd+Iq9GieIMUHZyrhYIvcKBotM7QkhEQm4Ji8jxEC8MWk79+uVDXkx2/6IXbnyAkKxStJu9Dw893aj7a0SAXRTag27MAON5LtcQsaUVW2DToltFd+wkZJ0n7svFCdAzLZvfwWggv2JwlHKG8DhkZ9FutOPqN9unHSOY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388424; c=relaxed/simple; bh=rdl+BcaghWHtfV7+1VqfVd7sJRug6nmHf+pErejLkqQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=U8oTuOHiAIMwA27OWmbkyL8+eum6bx460DTKY+l0MxL73jMWX3YJL5N1K2pfVhDOhTFkrXiSSscTii6657+WR9DH2X8QfkTj8DjqJpYcDVq0erBtbyKvsNtDkNM1mbYBOtyHIJqwZy0Kul3qi6Jnupi8/GYPanTH8WJt5fNKO2E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=Kv1UOyPP; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="Kv1UOyPP" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=36vjxovsp5VC9PYmAmRvtGCqLI9aZONSq/ohKmKaSzw=; b=Kv1UOyPPkyMnmqzOApH9BAm5Vh 56NalrNu0EnGNaVG5ymeqgqxomEe/1/hqN6qbMDJ6TKe73imwKKOEY281NUMm5zUGCknFDtnZzQlf Wf1unuXffFC451u0fEFEia5BraruT1F7gBhQ5yOz/bORK6XG3y00pc3NZoIrA91wRht4brSdimuxP KlWgyzOQNBroBEtmC7hbHNG3+VBfvEj7QCxgGb1lNNhK/iR8p4HSU00maAYtSczA297k5xSIfv5hc 30BJYXzR4FhlyxkjAXTDqKzKVaeW5fX0VtahJPTQjUbru9xVXpoKMtImcKS0tA49j7XW5JpkpwGQ5 Y17unS1g==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x65fW-003btm-1s; Mon, 14 Sep 2026 12:20:18 +0000 From: Breno Leitao Date: Mon, 14 Sep 2026 05:20:07 -0700 Subject: [PATCH net-next v2 1/2] net: add sockopt_expand_out() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-getsockopt_phase6-v2-1-e48befc9602e@debian.org> References: <20260914-getsockopt_phase6-v2-0-e48befc9602e@debian.org> In-Reply-To: <20260914-getsockopt_phase6-v2-0-e48befc9602e@debian.org> To: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Kuniyuki Iwashima , Willem de Bruijn , David Ahern , Ido Schimmel Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, david.laight.linux@gmail.com, Breno Leitao , kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=3629; i=leitao@debian.org; h=from:subject:message-id; bh=rdl+BcaghWHtfV7+1VqfVd7sJRug6nmHf+pErejLkqQ=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqp+Z4MymIGXJEddyX3QBwOi6IBtF6ldg+YZjK9 4hbYQm5Yr+JAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqfmeAAKCRA1o5Of/Hh3 bc/uEACRLzTwuKw6bEUxy++GsHNq0amWJJ6Ez3ajbNj4x/haRBarVNhy1Cf5Zd1kHm7oD89Rh94 oUQJ1ZEXv4DcVp9EkSHveXwHnh6FKhU0th1MuQqkZM8lvaFipFQKSPWjdZcwGkk+/TqTyocxK1E 95KnRBjdwG1UqyjXEh0Q1s0bUFolgDdpXu+5WhOlMPGSsRADRGChosTqlAEai1dDJTE7iH08HPZ rI0xPrig74iZhH1P7jLcCS3zubkBSItVA8+AGOT7fpG03vU+v9rcdL+9FpjxFpg2qK4MCwdy/TT zF8UhqBtz2g56GunNaxd6aqPkAGxSvA0HvidvtTOeksdqWL2fbugmnl/vDjIIgoH/8fUyduuz6Q MogOyUuCSd5ICOr3TCC99TufUiuelfpvEi4Dn8aWakzlVs3EXAxfN1Zo4FojIlQlGxSfa399kww PzNQ6Nony9mHuYYYwkyedLE7u7ja77zac6Zp3yUEUUh/1E2IC3NZjnZ9nJjeBtdjz+iegOAOxZW CgDCnoljRwyj//JcfZCHKp87OQre0WU5p2RdrksNoCNr2aD71bw17Vw+0g4FLb3/zDagQfu5pNO q7GOUHy0LTHeA7wNd1Zhu3xvDLK2MbLj+4T/SXttwk0Qah6d2JpC4Ofb9DI+t8OK2OYIXtEWpWz /sdEsTaAzrup6eg== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao Some getsockopt options size their reply from a count the caller left in optval rather than from optlen, and so write past the optlen the caller declared. Userspace relies on that, so the sockopt_t conversion has to keep doing it. IP_MSFILTER is the first one to convert: its reply covers the imsf_numsrc sources the caller asked for, while optlen only has to cover the fixed header. Add sockopt_expand_out() to grow opt->iter_out mid-air, so the quirk sits in one place instead of each protocol assuming it implicitly. It is a no-op unless the reply outruns optlen. Growing re-anchors the iterator at the head of optval, so it has to be called before anything is written through iter_out. Only a user buffer can be longer than optlen says. A kernel-backed optval keeps the bounded iterator, and a callback that asks to grow one gets a WARN_ON_ONCE() and -EINVAL. Nothing in tree can trip that WARN: the only kernel-backed path into do_ip_getsockopt() is sol_ip_sockopt(), which takes IP_TOS and IP_TRANSPARENT only. It is an assert for the in-kernel callers BPF and io_uring gain once the conversion is done, so they declare an optlen covering the whole buffer instead of repeating the userspace mistake. The conversion in the next patch calls sockptr_to_sockopt() from net/ipv4/, so drop its static and declare it in net.h. Signed-off-by: Breno Leitao Acked-by: Stanislav Fomichev --- include/linux/net.h | 32 ++++++++++++++++++++++++++++++++ net/socket.c | 4 ++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/include/linux/net.h b/include/linux/net.h index 470100ae710773..7db3aff33f2ba5 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -70,6 +70,38 @@ static inline int sockopt_init_user(sockopt_t *opt, char= __user *optval, return 0; } =20 +/* + * Grow optval to @size, for the options whose reply is sized by a count t= he + * caller left in optval rather than by optlen. Those write past optlen to= day + * and userspace relies on it. + * + * Call it before writing through opt->iter_out: it re-anchors the iterato= r at + * the head of optval. Only a user buffer can be longer than the optlen the + * caller declared, so a kernel-backed optval is refused with -EINVAL. + */ +static inline int sockopt_expand_out(sockopt_t *opt, size_t size) +{ + if (size <=3D (size_t)opt->optlen) + return 0; + + if (size > INT_MAX) + return -EINVAL; + + /* Re-anchoring reads iter_out.ubuf, so the iterator has to be a user + * buffer that nothing has written through yet. + */ + if (WARN_ON_ONCE(!iter_is_ubuf(&opt->iter_out) || + iov_iter_count(&opt->iter_out) !=3D (size_t)opt->optlen)) + return -EINVAL; + + iov_iter_ubuf(&opt->iter_out, ITER_DEST, opt->iter_out.ubuf, size); + + return 0; +} + +int sockptr_to_sockopt(sockopt_t *opt, sockptr_t optval, sockptr_t optlen, + struct kvec *kvec); + struct poll_table_struct; struct pipe_inode_info; struct inode; diff --git a/net/socket.c b/net/socket.c index c05d86e63abf7d..29a0f7f8e2cabe 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2437,8 +2437,8 @@ INDIRECT_CALLABLE_DECLARE(bool tcp_bpf_bypass_getsock= opt(int level, * It is important to remember that both iov points to the same data, but, * .iter_in is read-only and .iter_out is write-only by the protocol callb= acks */ -static int sockptr_to_sockopt(sockopt_t *opt, sockptr_t optval, - sockptr_t optlen, struct kvec *kvec) +int sockptr_to_sockopt(sockopt_t *opt, sockptr_t optval, + sockptr_t optlen, struct kvec *kvec) { int koptlen; =20 --=20 2.53.0-Meta From nobody Fri Sep 25 10:03:43 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (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 E0EEA3F5BFC; Mon, 14 Sep 2026 12:20:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388426; cv=none; b=MBVvsbQdzvUMWGRx5aqen+Zo0+1zWEqgC8v4xeVEXL+1FLujpTHHbPf9wm3cVvAOuzH8zWlXgNvAVO19ze5AzAp7mQI6sBmyZR/v1JbRJbHtY5Wd0xD4xWKhITMbnJ/MwVTBhGHKM8uaPbeqtp6R/GEX/2Q8EgNJAUciYVJN3vE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388426; c=relaxed/simple; bh=3ufswQVQR+63tDafLALw2FZWz+l+9LWhRH3gAEgpyuA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=T2ij5QxCT5HII0YKdxOvxcv9ynIlkBZ7p/5XlMPmP+r5pC+zLnwTZegY4xl6nFJYwMvf5L9IeXF3gWJlW8hdUALbh8w55e7ml5TRwhSFbwP9W1p0vJ7Cexp56Bm/EW1S4SRkkIdJESQzufbtda9uRcrMlhGBYTMl0eypPCb8Yl8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=ERQBdk85; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="ERQBdk85" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=oJhhgKFVY6AJH/Glck9e3yrRte0HMPO9hUkqs1342oo=; b=ERQBdk85LcpVncNxbv6PC2DH5b g7JOLioYOBl3zjB+/EytOuEH8yCKHhfT2S0Ly4BvotRtwveXP0Q4qO6YRUb6Zjr1aftZttiGJh+oV HvNo7ZyO+IySyQPxjnVjWEFJLlqGc8/zv7sOv488EU/qtihDtoR/jFind7kLxH/TCMssrBFI7jRid KxYdA/UXHfq1LVQd8ytkgN3euVKpOolY2MfHA1YW+MhY6Z0AhLZT887eOCo18+FxIHPlU9KAHWSPy GdAD9ttvneqqfuCl4OADjFZZCwv5WjvXnFNrgy8L1uXmkA5f2TN+3jDtyV095u+bO4i6g9cf1Vf8g Qm9MLVXg==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1x65fa-003bts-2u; Mon, 14 Sep 2026 12:20:23 +0000 From: Breno Leitao Date: Mon, 14 Sep 2026 05:20:08 -0700 Subject: [PATCH net-next v2 2/2] ipv4: igmp: convert ip_mc_msfget() to sockopt_t Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-getsockopt_phase6-v2-2-e48befc9602e@debian.org> References: <20260914-getsockopt_phase6-v2-0-e48befc9602e@debian.org> In-Reply-To: <20260914-getsockopt_phase6-v2-0-e48befc9602e@debian.org> To: "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Kuniyuki Iwashima , Willem de Bruijn , David Ahern , Ido Schimmel Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, david.laight.linux@gmail.com, Breno Leitao , kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=4442; i=leitao@debian.org; h=from:subject:message-id; bh=3ufswQVQR+63tDafLALw2FZWz+l+9LWhRH3gAEgpyuA=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqp+Z4fN1hIVs3P1mWxp5y3Rp/5cCNul/rS+pw3 TqxdAOVr6qJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaqfmeAAKCRA1o5Of/Hh3 bQFvD/9QB0f44UDN4AOTC3soXNd/DyIS/8ZeK8k27GrnVW9OCbnwPFYYE6Mlz75jQ9KTyJMEAXf 9cg6d9RuRFERUSTtpzsG9PWEZpCw6SvBXlYR1+MGubAcH236T4ZS5uDNX8xBANLhU0hwfrkdQfZ /0TZE5C3qWHNebs0paoA/+KTTSVVaG5Cg3D7wpWNHyzdjCs9+FznNZwuZY65QciyzXPicJ1aKqN zH78lV5QgWBf+AwzeUClew/PDQy958gpnvi5+ml4jEsjrpuaR8dFdRjuA6aArh6B1zmBQFuMuUB RiYOUaIGbrD4msjDh8ZTUQ8UXzmiT9ia8DpAPwwlAXwmH1+OzNqhYb+REvAwsHmR0tqp2Cauiz8 f+NHlk6Rqm/VFilgpkhkP5BMPtETLBqhhLCJxt2v+T1ArDjJkCNNA0wnlSn4Go0H2TMzCF0ZE40 7hKf3loq/OXLlM/h4NvkcmRaVjmORqL22+MlJTGGRg3v+ra18AUHK4UYUYMjSZh5P7EUo/1P4xT NvnFj+JZaIXq1pznyts4TVMgG7ei2lO0G5qldaTkk0jzlad0RIgkiYaL8rLdI/Zu8B6MfCt9vOK C5d3kdMxKoJpOgYEROsJitDb4hnadXlqm3y+W7Y+7IDu+iHRYxqcgDvwKstj7+RTbO4K/r9es01 BlhKMhhR7CKGk9Q== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao IP_MSFILTER reads its reply through ip_mc_msfget(), reached from do_ip_getsockopt() and from nowhere else. Convert it, and build the sockopt_t at the call site for as long as the caller still carries a sockptr_t pair. optlen here only has to cover the header, and the real reply size comes from the imsf_numsrc field inside it. This is nasty, but userspace relies on it, so sockopt_expand_out() preserves the same mechanism: it grows optval only for a user address, and assumes the caller left room for the size its own header asked for. The *optlen store moves out of ip_mc_msfget() and into the call site, guarded by !err so the -EINVAL, -ENODEV and -EADDRNOTAVAIL returns still leave the caller's optlen word untouched. The source list also moves from copy_to_sockptr_offset() to a sequential copy_to_iter(). IP_MSFILTER_SIZE(0) and offsetof(struct ip_msfilter, imsf_slist_flex) are both 16, so the bytes land where they did. Signed-off-by: Breno Leitao Acked-by: Stanislav Fomichev --- include/linux/igmp.h | 3 ++- net/ipv4/igmp.c | 23 ++++++++++++++--------- net/ipv4/ip_sockglue.c | 10 +++++++++- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/include/linux/igmp.h b/include/linux/igmp.h index a0cf0398519fd7..e075611344ef3b 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -273,7 +274,7 @@ extern int ip_mc_source(int add, int omode, struct sock= *sk, struct ip_mreq_source *mreqs, int ifindex); extern int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf,int ifi= ndex); extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, - sockptr_t optval, sockptr_t optlen); + sockopt_t *opt); extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, sockptr_t optval, size_t offset); extern int ip_mc_sf_allow(const struct sock *sk, __be32 local, __be32 rmt, diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d56355aca79776..144fca158adcb0 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2709,8 +2709,8 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilte= r *msf, int ifindex) err =3D ip_mc_leave_group(sk, &imr); return err; } -int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, - sockptr_t optval, sockptr_t optlen) + +int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, sockopt_t *opt) { int err, len, count, copycount, msf_size; struct ip_mreqn imr; @@ -2755,14 +2755,19 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilte= r *msf, len =3D flex_array_size(psl, sl_addr, copycount); msf->imsf_numsrc =3D count; msf_size =3D IP_MSFILTER_SIZE(copycount); - if (copy_to_sockptr(optlen, &msf_size, sizeof(int)) || - copy_to_sockptr(optval, msf, IP_MSFILTER_SIZE(0))) { + + /* The source list is sized by the imsf_numsrc the caller left in + * optval, not by optlen, which only has to cover the fixed part. + */ + err =3D sockopt_expand_out(opt, msf_size); + if (err) + return err; + + opt->optlen =3D msf_size; + if (copy_to_iter(msf, IP_MSFILTER_SIZE(0), &opt->iter_out) !=3D + IP_MSFILTER_SIZE(0)) return -EFAULT; - } - if (len && - copy_to_sockptr_offset(optval, - offsetof(struct ip_msfilter, imsf_slist_flex), - psl->sl_addr, len)) + if (len && copy_to_iter(psl->sl_addr, len, &opt->iter_out) !=3D len) return -EFAULT; return 0; done: diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index a55ef327ec932c..e06c1f48ecad6e 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1706,6 +1706,8 @@ int do_ip_getsockopt(struct sock *sk, int level, int = optname, case IP_MSFILTER: { struct ip_msfilter msf; + struct kvec kvec; + sockopt_t opt; =20 if (len < IP_MSFILTER_SIZE(0)) { err =3D -EINVAL; @@ -1715,7 +1717,13 @@ int do_ip_getsockopt(struct sock *sk, int level, int= optname, err =3D -EFAULT; goto out; } - err =3D ip_mc_msfget(sk, &msf, optval, optlen); + err =3D sockptr_to_sockopt(&opt, optval, optlen, &kvec); + if (err) + goto out; + + err =3D ip_mc_msfget(sk, &msf, &opt); + if (!err && copy_to_sockptr(optlen, &opt.optlen, sizeof(int))) + err =3D -EFAULT; goto out; } case MCAST_MSFILTER: --=20 2.53.0-Meta