From: Breno Leitao <leitao@debian.org>
To: David Ahern <dsahern@kernel.org>,
Ido Schimmel <idosch@nvidia.com>,
"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>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Jiri Olsa <jolsa@kernel.org>,
Emil Tsalapatis <emil@etsalapatis.com>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
John Fastabend <john.fastabend@gmail.com>,
Stanislav Fomichev <sdf@fomichev.me>,
Shuah Khan <shuah@kernel.org>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
david.laight.linux@gmail.com, Breno Leitao <leitao@debian.org>,
kernel-team@meta.com
Subject: [PATCH net-next 4/6] ipv4: convert do_ip_getsockopt() to sockopt_t
Date: Fri, 25 Sep 2026 08:55:19 -0700 [thread overview]
Message-ID: <20260925-sockopt_expand_out_v2-v1-4-c3ef2e3bb5c0@debian.org> (raw)
In-Reply-To: <20260925-sockopt_expand_out_v2-v1-0-c3ef2e3bb5c0@debian.org>
Convert the SOL_IP switch and ip_mroute_getsockopt(), its last leaf on
a sockptr_t pair. The IP_MSFILTER and MCAST_MSFILTER bridges go away.
ip_getsockopt() builds the sockopt_t with sockopt_init_user() and
writes optlen back unconditionally, because IP_OPTIONS and others
report a length then fail; ip_mc_msfget() therefore stores its length
last. IP_PKTOPTIONS takes its buffer off iter_out. The argument is
sopt, since IP_OPTIONS already has an ip_options local named opt.
Validating optlen now precedes the level check and the MRT_* dispatch,
so a negative optlen wins over -EOPNOTSUPP there.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
include/linux/mroute.h | 4 +--
include/net/ip.h | 3 +-
net/core/filter.c | 18 ++++++++---
net/ipv4/igmp.c | 3 +-
net/ipv4/ip_sockglue.c | 87 +++++++++++++++++++-------------------------------
net/ipv4/ipmr.c | 11 +++----
6 files changed, 56 insertions(+), 70 deletions(-)
diff --git a/include/linux/mroute.h b/include/linux/mroute.h
index 4c5003afee6c51..c1c21e61c81c37 100644
--- a/include/linux/mroute.h
+++ b/include/linux/mroute.h
@@ -17,7 +17,7 @@ static inline int ip_mroute_opt(int opt)
}
int ip_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int);
-int ip_mroute_getsockopt(struct sock *, int, sockptr_t, sockptr_t);
+int ip_mroute_getsockopt(struct sock *sk, int optname, sockopt_t *opt);
int ipmr_ioctl(struct sock *sk, int cmd, void *arg);
int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
int ip_mr_init(void);
@@ -31,7 +31,7 @@ static inline int ip_mroute_setsockopt(struct sock *sock, int optname,
}
static inline int ip_mroute_getsockopt(struct sock *sk, int optname,
- sockptr_t optval, sockptr_t optlen)
+ sockopt_t *opt)
{
return -ENOPROTOOPT;
}
diff --git a/include/net/ip.h b/include/net/ip.h
index 6f602df72ee621..81aef4b98430bf 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -823,8 +823,7 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen);
int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen);
-int do_ip_getsockopt(struct sock *sk, int level, int optname,
- sockptr_t optval, sockptr_t optlen);
+int do_ip_getsockopt(struct sock *sk, int level, int optname, sockopt_t *sopt);
int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
int __user *optlen);
int ip_ra_control(struct sock *sk, unsigned char on,
diff --git a/net/core/filter.c b/net/core/filter.c
index 70dc621672f2e9..9a706ec1f7f122 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -5737,10 +5737,20 @@ static int sol_ip_sockopt(struct sock *sk, int optname,
return -EINVAL;
}
- if (getopt)
- return do_ip_getsockopt(sk, SOL_IP, optname,
- KERNEL_SOCKPTR(optval),
- KERNEL_SOCKPTR(optlen));
+ if (getopt) {
+ struct kvec kvec;
+ sockopt_t opt;
+ int err;
+
+ err = sockptr_to_sockopt(&opt, KERNEL_SOCKPTR(optval),
+ KERNEL_SOCKPTR(optlen), &kvec);
+ if (err)
+ return err;
+
+ err = do_ip_getsockopt(sk, SOL_IP, optname, &opt);
+ *optlen = opt.optlen;
+ return err;
+ }
return do_ip_setsockopt(sk, SOL_IP, optname,
KERNEL_SOCKPTR(optval), *optlen);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index d573c5bf8f038b..bf00810cdd7a13 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -2763,12 +2763,13 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, sockopt_t *opt)
if (err)
return err;
- opt->optlen = msf_size;
if (copy_to_iter(msf, IP_MSFILTER_SIZE(0), &opt->iter_out) !=
IP_MSFILTER_SIZE(0))
return -EFAULT;
if (len && copy_to_iter(psl->sl_addr, len, &opt->iter_out) != len)
return -EFAULT;
+
+ opt->optlen = msf_size;
return 0;
done:
return err;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 1f452b6ea86e9d..2e78b11d294a9f 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1509,8 +1509,7 @@ static int compat_ip_get_mcast_msfilter(struct sock *sk, sockopt_t *opt)
return 0;
}
-int do_ip_getsockopt(struct sock *sk, int level, int optname,
- sockptr_t optval, sockptr_t optlen)
+int do_ip_getsockopt(struct sock *sk, int level, int optname, sockopt_t *sopt)
{
struct inet_sock *inet = inet_sk(sk);
bool needs_rtnl = getsockopt_needs_rtnl(optname);
@@ -1521,10 +1520,9 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
return -EOPNOTSUPP;
if (ip_mroute_opt(optname))
- return ip_mroute_getsockopt(sk, optname, optval, optlen);
+ return ip_mroute_getsockopt(sk, optname, sopt);
- if (copy_from_sockptr(&len, optlen, sizeof(int)))
- return -EFAULT;
+ len = sopt->optlen;
if (len < 0)
return -EINVAL;
@@ -1620,16 +1618,15 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
rcu_read_unlock();
if (opt->optlen == 0) {
- len = 0;
- return copy_to_sockptr(optlen, &len, sizeof(int));
+ sopt->optlen = 0;
+ return 0;
}
ip_options_undo(opt);
len = min_t(unsigned int, len, opt->optlen);
- if (copy_to_sockptr(optlen, &len, sizeof(int)))
- return -EFAULT;
- if (copy_to_sockptr(optval, opt->__data, len))
+ sopt->optlen = len;
+ if (copy_to_iter(opt->__data, len, &sopt->iter_out) != len)
return -EFAULT;
return 0;
}
@@ -1653,12 +1650,12 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
if (sk->sk_type != SOCK_STREAM)
return -ENOPROTOOPT;
- if (optval.is_kernel) {
+ if (iov_iter_is_kvec(&sopt->iter_out)) {
msg.msg_control_is_user = false;
- msg.msg_control = optval.kernel;
+ msg.msg_control = sopt->iter_out.kvec->iov_base;
} else {
msg.msg_control_is_user = true;
- msg.msg_control_user = optval.user;
+ msg.msg_control_user = sopt->iter_out.ubuf;
}
msg.msg_controllen = len;
msg.msg_flags = in_compat_syscall() ? MSG_CMSG_COMPAT : 0;
@@ -1680,8 +1677,8 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
int tos = READ_ONCE(inet->rcv_tos);
put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos);
}
- len -= msg.msg_controllen;
- return copy_to_sockptr(optlen, &len, sizeof(int));
+ sopt->optlen = len - msg.msg_controllen;
+ return 0;
}
case IP_UNICAST_IF:
val = (__force int)htonl((__u32) READ_ONCE(inet->uc_index));
@@ -1692,9 +1689,8 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
len = min_t(unsigned int, len, sizeof(struct in_addr));
addr.s_addr = READ_ONCE(inet->mc_addr);
- if (copy_to_sockptr(optlen, &len, sizeof(int)))
- return -EFAULT;
- if (copy_to_sockptr(optval, &addr, len))
+ sopt->optlen = len;
+ if (copy_to_iter(&addr, len, &sopt->iter_out) != len)
return -EFAULT;
return 0;
}
@@ -1711,43 +1707,25 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
case IP_MSFILTER:
{
struct ip_msfilter msf;
- struct kvec kvec;
- sockopt_t opt;
if (len < IP_MSFILTER_SIZE(0)) {
err = -EINVAL;
goto out;
}
- if (copy_from_sockptr(&msf, optval, IP_MSFILTER_SIZE(0))) {
+ if (copy_from_iter(&msf, IP_MSFILTER_SIZE(0), &sopt->iter_in) !=
+ IP_MSFILTER_SIZE(0)) {
err = -EFAULT;
goto out;
}
- err = sockptr_to_sockopt(&opt, optval, optlen, &kvec);
- if (err)
- goto out;
-
- err = ip_mc_msfget(sk, &msf, &opt);
- if (!err && copy_to_sockptr(optlen, &opt.optlen, sizeof(int)))
- err = -EFAULT;
+ err = ip_mc_msfget(sk, &msf, sopt);
goto out;
}
case MCAST_MSFILTER:
- {
- struct kvec kvec;
- sockopt_t opt;
-
- err = sockptr_to_sockopt(&opt, optval, optlen, &kvec);
- if (err)
- goto out;
-
if (in_compat_syscall())
- err = compat_ip_get_mcast_msfilter(sk, &opt);
+ err = compat_ip_get_mcast_msfilter(sk, sopt);
else
- err = ip_get_mcast_msfilter(sk, &opt);
- if (!err && copy_to_sockptr(optlen, &opt.optlen, sizeof(int)))
- err = -EFAULT;
+ err = ip_get_mcast_msfilter(sk, sopt);
goto out;
- }
case IP_PROTOCOL:
val = inet_sk(sk)->inet_num;
break;
@@ -1759,16 +1737,14 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
copyval:
if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) {
unsigned char ucval = (unsigned char)val;
- len = 1;
- if (copy_to_sockptr(optlen, &len, sizeof(int)))
- return -EFAULT;
- if (copy_to_sockptr(optval, &ucval, 1))
+
+ sopt->optlen = 1;
+ if (copy_to_iter(&ucval, 1, &sopt->iter_out) != 1)
return -EFAULT;
} else {
len = min_t(unsigned int, sizeof(int), len);
- if (copy_to_sockptr(optlen, &len, sizeof(int)))
- return -EFAULT;
- if (copy_to_sockptr(optval, &val, len))
+ sopt->optlen = len;
+ if (copy_to_iter(&val, len, &sopt->iter_out) != len)
return -EFAULT;
}
return 0;
@@ -1783,19 +1759,22 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
int ip_getsockopt(struct sock *sk, int level,
int optname, char __user *optval, int __user *optlen)
{
+ sockopt_t opt;
int err;
- err = do_ip_getsockopt(sk, level, optname,
- USER_SOCKPTR(optval), USER_SOCKPTR(optlen));
+ err = sockopt_init_user(&opt, optval, optlen);
+ if (err)
+ return err;
+
+ err = do_ip_getsockopt(sk, level, optname, &opt);
+ if (put_user(opt.optlen, optlen))
+ return -EFAULT;
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
!ip_mroute_opt(optname)) {
- int len;
-
- if (get_user(len, optlen))
- return -EFAULT;
+ int len = opt.optlen;
err = nf_getsockopt(sk, PF_INET, optname, optval, &len);
if (err >= 0)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index e4c51ca473019c..f249569b4bf8b9 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1638,8 +1638,7 @@ int ipmr_sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
}
/* Getsock opt support for the multicast routing system. */
-int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,
- sockptr_t optlen)
+int ip_mroute_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
{
int olr;
int val;
@@ -1670,16 +1669,14 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,
return -ENOPROTOOPT;
}
- if (copy_from_sockptr(&olr, optlen, sizeof(int)))
- return -EFAULT;
+ olr = opt->optlen;
if (olr < 0)
return -EINVAL;
olr = min_t(unsigned int, olr, sizeof(int));
- if (copy_to_sockptr(optlen, &olr, sizeof(int)))
- return -EFAULT;
- if (copy_to_sockptr(optval, &val, olr))
+ opt->optlen = olr;
+ if (copy_to_iter(&val, olr, &opt->iter_out) != olr)
return -EFAULT;
return 0;
}
--
2.53.0-Meta
next prev parent reply other threads:[~2026-09-25 15:56 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-25 15:55 [PATCH net-next 0/6] ipv4,ipv6: convert the getsockopt switches " Breno Leitao
2026-09-25 15:55 ` [PATCH net-next 1/6] ipv6: reject a negative optlen in do_ipv6_getsockopt() Breno Leitao
2026-09-25 19:02 ` Stanislav Fomichev
2026-09-27 6:53 ` David Laight
2026-09-29 12:14 ` Breno Leitao
2026-09-28 18:55 ` netdev-bot+sashiko
2026-09-25 15:55 ` [PATCH net-next 2/6] ipv6: mcast: convert ip6_mc_msfget() to sockopt_t Breno Leitao
2026-09-28 18:55 ` netdev-bot+sashiko
2026-09-25 15:55 ` [PATCH net-next 3/6] ipv4: igmp: convert ip_mc_gsfget() " Breno Leitao
2026-09-28 18:55 ` netdev-bot+sashiko
2026-09-25 15:55 ` Breno Leitao [this message]
2026-09-28 18:55 ` [PATCH net-next 4/6] ipv4: convert do_ip_getsockopt() " netdev-bot+sashiko
2026-09-25 15:55 ` [PATCH net-next 5/6] ipv6: convert do_ipv6_getsockopt() " Breno Leitao
2026-09-28 18:55 ` netdev-bot+sashiko
2026-09-25 15:55 ` [PATCH net-next 6/6] selftests: net: getsockopt_iter: cover ip and ipv6 Breno Leitao
2026-09-28 18:55 ` netdev-bot+sashiko
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=20260925-sockopt_expand_out_v2-v1-4-c3ef2e3bb5c0@debian.org \
--to=leitao@debian.org \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=david.laight.linux@gmail.com \
--cc=dsahern@kernel.org \
--cc=eddyz87@gmail.com \
--cc=edumazet@google.com \
--cc=emil@etsalapatis.com \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=ihor.solodrai@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kernel-team@meta.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®