Re: [PATCH net-next v2 2/4] net: call getsockopt_iter if available

From: Stanislav Fomichev

Date: Wed Apr 01 2026 - 13:01:36 EST


On 04/01, Breno Leitao wrote:
> Update do_sock_getsockopt() to use the new getsockopt_iter callback
> when available. Add do_sock_getsockopt_iter() helper that:
>
> 1. Reads optlen from user/kernel space
> 2. Initializes a sockopt_t with the appropriate iov_iter (kvec for
> kernel, ubuf for user buffers) and sets opt.optlen
> 3. Calls the protocol's getsockopt_iter callback
> 4. Writes opt.optlen back to user/kernel space
>
> The optlen is always written back, even on failure. Some protocols
> (e.g. CAN raw) return -ERANGE and set optlen to the required buffer
> size so userspace knows how much to allocate.
>
> The callback is responsible for setting opt.optlen to indicate the
> returned data size.
>
> Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>
> ---
> net/socket.c | 48 +++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 45 insertions(+), 3 deletions(-)
>
> diff --git a/net/socket.c b/net/socket.c
> index ade2ff5845a0..4a74a4aa1bb4 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -77,6 +77,7 @@
> #include <linux/mount.h>
> #include <linux/pseudo_fs.h>
> #include <linux/security.h>
> +#include <linux/uio.h>
> #include <linux/syscalls.h>
> #include <linux/compat.h>
> #include <linux/kmod.h>
> @@ -2349,6 +2350,44 @@ SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
> INDIRECT_CALLABLE_DECLARE(bool tcp_bpf_bypass_getsockopt(int level,
> int optname));
>
> +static int do_sock_getsockopt_iter(struct socket *sock,
> + const struct proto_ops *ops, int level,
> + int optname, sockptr_t optval,
> + sockptr_t optlen)

If we want to eventually remove sockptr_t, why not make this new handler
work with iov_iters from the beginning? The callers can have some new temporary
sockptr_to_iter() or something?

> +{
> + struct kvec kvec;
> + sockopt_t opt;
> + int koptlen;
> + int err;
> +
> + if (copy_from_sockptr(&koptlen, optlen, sizeof(int)))
> + return -EFAULT;
> +
> + if (optval.is_kernel) {
> + kvec.iov_base = optval.kernel;
> + kvec.iov_len = koptlen;
> + iov_iter_kvec(&opt.iter, ITER_DEST, &kvec, 1, koptlen);
> + } else {
> + iov_iter_ubuf(&opt.iter, ITER_DEST, optval.user, koptlen);
> + }
> + opt.optlen = koptlen;
> +
> + /* iter is initialized as ITER_DEST. Callbacks that need to read
> + * from optval (e.g. PACKET_HDRLEN) must flip data_source to
> + * ITER_SOURCE, then restore ITER_DEST before writing back.
> + */

Have you considered creating two iters? opt.iter_in and opt.iter_out.
That way you don't have to flip the source back and forth in the
handlers.