From: Breno Leitao <leitao@debian.org>
To: "David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
Kuniyuki Iwashima <kuniyu@google.com>,
Willem de Bruijn <willemb@google.com>,
David Ahern <dsahern@kernel.org>,
Ido Schimmel <idosch@nvidia.com>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
david.laight.linux@gmail.com, Breno Leitao <leitao@debian.org>,
kernel-team@meta.com
Subject: [PATCH net-next v2 1/2] net: add sockopt_expand_out()
Date: Mon, 14 Sep 2026 05:20:07 -0700 [thread overview]
Message-ID: <20260914-getsockopt_phase6-v2-1-e48befc9602e@debian.org> (raw)
In-Reply-To: <20260914-getsockopt_phase6-v2-0-e48befc9602e@debian.org>
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 <leitao@debian.org>
---
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;
}
+/*
+ * Grow optval to @size, for the options whose reply is sized by a count the
+ * caller left in optval rather than by optlen. Those write past optlen today
+ * and userspace relies on it.
+ *
+ * Call it before writing through opt->iter_out: it re-anchors the iterator 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 <= (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) != (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_getsockopt(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 callbacks
*/
-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;
--
2.53.0-Meta
next prev parent reply other threads:[~2026-09-14 12:20 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-14 12:20 [PATCH net-next v2 0/2] net: a sockopt_t quirk for the options that write past optlen Breno Leitao
2026-09-14 12:20 ` Breno Leitao [this message]
2026-09-14 12:20 ` [PATCH net-next v2 2/2] ipv4: igmp: convert ip_mc_msfget() to sockopt_t Breno Leitao
2026-09-14 13:46 ` [PATCH net-next v2 0/2] net: a sockopt_t quirk for the options that write past optlen David Laight
2026-09-14 16:19 ` Stanislav Fomichev
2026-09-19 0:10 ` patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260914-getsockopt_phase6-v2-1-e48befc9602e@debian.org \
--to=leitao@debian.org \
--cc=davem@davemloft.net \
--cc=david.laight.linux@gmail.com \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=kernel-team@meta.com \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=willemb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.