mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
Merge branch 'net-convert-four-more-protocols-to-getsockopt_iter'
Breno Leitao says: ==================== net: convert four more protocols to getsockopt_iter Continue the work to convert protocols to the new getsockopt_iter API. Convert four additional getsockopt implementations to the new sockopt_t/getsockopt_iter callback: - MCTP - LLC - X.25 - KCM These are mechanical, ABI-preserving conversions following the same pattern as the previously converted protocols (af_packet, can/raw, af_netlink, af_vsock): the (char __user *optval, int __user *optlen) pair is replaced with a single sockopt_t *opt that carries the buffer length on input and the returned size on output, and exposes an iov_iter for the copy-out path. put_user()/copy_to_user() pairs are replaced with a single copy_to_iter() per option, and the wrapper in do_sock_getsockopt() handles writing optlen back to userspace. I picked these four because each is small and self-contained. ==================== Link: https://patch.msgid.link/20260507-getsock_two-v2-0-5873111d9c12@debian.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
7247c92cdc
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
#include <net/kcm.h>
|
||||
#include <net/netns/generic.h>
|
||||
|
|
@ -1167,7 +1168,7 @@ static int kcm_setsockopt(struct socket *sock, int level, int optname,
|
|||
}
|
||||
|
||||
static int kcm_getsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
sockopt_t *opt)
|
||||
{
|
||||
struct kcm_sock *kcm = kcm_sk(sock->sk);
|
||||
int val, len;
|
||||
|
|
@ -1175,9 +1176,7 @@ static int kcm_getsockopt(struct socket *sock, int level, int optname,
|
|||
if (level != SOL_KCM)
|
||||
return -ENOPROTOOPT;
|
||||
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
len = opt->optlen;
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -1191,9 +1190,8 @@ static int kcm_getsockopt(struct socket *sock, int level, int optname,
|
|||
return -ENOPROTOOPT;
|
||||
}
|
||||
|
||||
if (put_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(optval, &val, len))
|
||||
opt->optlen = len;
|
||||
if (copy_to_iter(&val, len, &opt->iter_out) != len)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1755,7 +1753,7 @@ static const struct proto_ops kcm_dgram_ops = {
|
|||
.listen = sock_no_listen,
|
||||
.shutdown = sock_no_shutdown,
|
||||
.setsockopt = kcm_setsockopt,
|
||||
.getsockopt = kcm_getsockopt,
|
||||
.getsockopt_iter = kcm_getsockopt,
|
||||
.sendmsg = kcm_sendmsg,
|
||||
.recvmsg = kcm_recvmsg,
|
||||
.mmap = sock_no_mmap,
|
||||
|
|
@ -1776,7 +1774,7 @@ static const struct proto_ops kcm_seqpacket_ops = {
|
|||
.listen = sock_no_listen,
|
||||
.shutdown = sock_no_shutdown,
|
||||
.setsockopt = kcm_setsockopt,
|
||||
.getsockopt = kcm_getsockopt,
|
||||
.getsockopt_iter = kcm_getsockopt,
|
||||
.sendmsg = kcm_sendmsg,
|
||||
.recvmsg = kcm_recvmsg,
|
||||
.mmap = sock_no_mmap,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
#include <net/llc.h>
|
||||
#include <net/llc_sap.h>
|
||||
|
|
@ -1166,25 +1167,21 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
|
|||
* @sock: Socket to get information from.
|
||||
* @level: Socket level user is requesting operations on.
|
||||
* @optname: Operation name.
|
||||
* @optval: Variable to return operation data in.
|
||||
* @optlen: Length of optval.
|
||||
* @opt: sockopt context with iterator and length for returning data.
|
||||
*
|
||||
* Get connection specific socket information.
|
||||
*/
|
||||
static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
sockopt_t *opt)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct llc_sock *llc = llc_sk(sk);
|
||||
int val = 0, len = 0, rc = -EINVAL;
|
||||
int val = 0, len, rc = -EINVAL;
|
||||
|
||||
lock_sock(sk);
|
||||
if (unlikely(level != SOL_LLC))
|
||||
goto out;
|
||||
rc = get_user(len, optlen);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = -EINVAL;
|
||||
len = opt->optlen;
|
||||
if (len != sizeof(int))
|
||||
goto out;
|
||||
switch (optname) {
|
||||
|
|
@ -1212,7 +1209,8 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
|
|||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
if (put_user(len, optlen) || copy_to_user(optval, &val, len))
|
||||
opt->optlen = len;
|
||||
if (copy_to_iter(&val, len, &opt->iter_out) != len)
|
||||
rc = -EFAULT;
|
||||
out:
|
||||
release_sock(sk);
|
||||
|
|
@ -1239,7 +1237,7 @@ static const struct proto_ops llc_ui_ops = {
|
|||
.listen = llc_ui_listen,
|
||||
.shutdown = llc_ui_shutdown,
|
||||
.setsockopt = llc_ui_setsockopt,
|
||||
.getsockopt = llc_ui_getsockopt,
|
||||
.getsockopt_iter = llc_ui_getsockopt,
|
||||
.sendmsg = llc_ui_sendmsg,
|
||||
.recvmsg = llc_ui_recvmsg,
|
||||
.mmap = sock_no_mmap,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/mctp.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
#include <net/mctp.h>
|
||||
#include <net/mctpdevice.h>
|
||||
|
|
@ -405,7 +406,7 @@ static int mctp_setsockopt(struct socket *sock, int level, int optname,
|
|||
}
|
||||
|
||||
static int mctp_getsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
sockopt_t *opt)
|
||||
{
|
||||
struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk);
|
||||
int len, val;
|
||||
|
|
@ -413,14 +414,13 @@ static int mctp_getsockopt(struct socket *sock, int level, int optname,
|
|||
if (level != SOL_MCTP)
|
||||
return -EINVAL;
|
||||
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
len = opt->optlen;
|
||||
|
||||
if (optname == MCTP_OPT_ADDR_EXT) {
|
||||
if (len != sizeof(int))
|
||||
return -EINVAL;
|
||||
val = !!msk->addr_ext;
|
||||
if (copy_to_user(optval, &val, len))
|
||||
if (copy_to_iter(&val, len, &opt->iter_out) != len)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -639,7 +639,7 @@ static const struct proto_ops mctp_dgram_ops = {
|
|||
.listen = sock_no_listen,
|
||||
.shutdown = sock_no_shutdown,
|
||||
.setsockopt = mctp_setsockopt,
|
||||
.getsockopt = mctp_getsockopt,
|
||||
.getsockopt_iter = mctp_getsockopt,
|
||||
.sendmsg = mctp_sendmsg,
|
||||
.recvmsg = mctp_recvmsg,
|
||||
.mmap = sock_no_mmap,
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
#include <net/x25.h>
|
||||
#include <net/compat.h>
|
||||
|
|
@ -448,7 +449,7 @@ static int x25_setsockopt(struct socket *sock, int level, int optname,
|
|||
}
|
||||
|
||||
static int x25_getsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
sockopt_t *opt)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
int val, len, rc = -ENOPROTOOPT;
|
||||
|
|
@ -456,22 +457,17 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
|
|||
if (level != SOL_X25 || optname != X25_QBITINCL)
|
||||
goto out;
|
||||
|
||||
rc = -EFAULT;
|
||||
if (get_user(len, optlen))
|
||||
goto out;
|
||||
len = opt->optlen;
|
||||
|
||||
rc = -EINVAL;
|
||||
if (len < 0)
|
||||
goto out;
|
||||
|
||||
len = min_t(unsigned int, len, sizeof(int));
|
||||
|
||||
rc = -EFAULT;
|
||||
if (put_user(len, optlen))
|
||||
goto out;
|
||||
opt->optlen = len;
|
||||
|
||||
val = test_bit(X25_Q_BIT_FLAG, &x25_sk(sk)->flags);
|
||||
rc = copy_to_user(optval, &val, len) ? -EFAULT : 0;
|
||||
rc = copy_to_iter(&val, len, &opt->iter_out) != len ? -EFAULT : 0;
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1753,7 +1749,7 @@ static const struct proto_ops x25_proto_ops = {
|
|||
.listen = x25_listen,
|
||||
.shutdown = sock_no_shutdown,
|
||||
.setsockopt = x25_setsockopt,
|
||||
.getsockopt = x25_getsockopt,
|
||||
.getsockopt_iter = x25_getsockopt,
|
||||
.sendmsg = x25_sendmsg,
|
||||
.recvmsg = x25_recvmsg,
|
||||
.mmap = sock_no_mmap,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <unistd.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/time_types.h>
|
||||
#include <linux/vm_sockets.h>
|
||||
#include <sys/socket.h>
|
||||
#include "kselftest_harness.h"
|
||||
|
|
@ -61,8 +62,10 @@ FIXTURE_TEARDOWN(netlink)
|
|||
|
||||
TEST_F(netlink, pktinfo_exact)
|
||||
{
|
||||
socklen_t optlen;
|
||||
int val = -1;
|
||||
socklen_t optlen = sizeof(val);
|
||||
|
||||
optlen = sizeof(val);
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
|
||||
&val, &optlen));
|
||||
|
|
@ -73,7 +76,9 @@ TEST_F(netlink, pktinfo_exact)
|
|||
TEST_F(netlink, pktinfo_oversize_clamped)
|
||||
{
|
||||
char buf[16] = {};
|
||||
socklen_t optlen = sizeof(buf);
|
||||
socklen_t optlen;
|
||||
|
||||
optlen = sizeof(buf);
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
|
||||
buf, &optlen));
|
||||
|
|
@ -83,11 +88,14 @@ TEST_F(netlink, pktinfo_oversize_clamped)
|
|||
TEST_F(netlink, pktinfo_undersize)
|
||||
{
|
||||
char buf[2] = {};
|
||||
socklen_t optlen = sizeof(buf);
|
||||
socklen_t optlen;
|
||||
|
||||
optlen = sizeof(buf);
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
|
||||
buf, &optlen));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
ASSERT_EQ(sizeof(buf), optlen);
|
||||
}
|
||||
|
||||
TEST_F(netlink, list_memberships_size_discovery)
|
||||
|
|
@ -105,7 +113,9 @@ TEST_F(netlink, list_memberships_size_discovery)
|
|||
TEST_F(netlink, list_memberships_full_read)
|
||||
{
|
||||
__u32 buf[64] = {};
|
||||
socklen_t optlen = sizeof(buf);
|
||||
socklen_t optlen;
|
||||
|
||||
optlen = sizeof(buf);
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK,
|
||||
NETLINK_LIST_MEMBERSHIPS,
|
||||
|
|
@ -117,22 +127,28 @@ TEST_F(netlink, list_memberships_full_read)
|
|||
|
||||
TEST_F(netlink, bad_level)
|
||||
{
|
||||
socklen_t optlen;
|
||||
int val;
|
||||
socklen_t optlen = sizeof(val);
|
||||
|
||||
optlen = sizeof(val);
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, SOL_SOCKET + 1, NETLINK_PKTINFO,
|
||||
&val, &optlen));
|
||||
ASSERT_EQ(ENOPROTOOPT, errno);
|
||||
ASSERT_EQ(sizeof(val), optlen);
|
||||
}
|
||||
|
||||
TEST_F(netlink, bad_optname)
|
||||
{
|
||||
socklen_t optlen;
|
||||
int val;
|
||||
socklen_t optlen = sizeof(val);
|
||||
|
||||
optlen = sizeof(val);
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, SOL_NETLINK, 0x7fff,
|
||||
&val, &optlen));
|
||||
ASSERT_EQ(ENOPROTOOPT, errno);
|
||||
ASSERT_EQ(sizeof(val), optlen);
|
||||
}
|
||||
|
||||
/* ---------- vsock ---------- */
|
||||
|
|
@ -157,8 +173,10 @@ FIXTURE_TEARDOWN(vsock)
|
|||
|
||||
TEST_F(vsock, buffer_size_exact)
|
||||
{
|
||||
socklen_t optlen;
|
||||
uint64_t val = 0;
|
||||
socklen_t optlen = sizeof(val);
|
||||
|
||||
optlen = sizeof(val);
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
|
||||
SO_VM_SOCKETS_BUFFER_SIZE,
|
||||
|
|
@ -170,7 +188,9 @@ TEST_F(vsock, buffer_size_exact)
|
|||
TEST_F(vsock, buffer_size_oversize_clamped)
|
||||
{
|
||||
char buf[16] = {};
|
||||
socklen_t optlen = sizeof(buf);
|
||||
socklen_t optlen;
|
||||
|
||||
optlen = sizeof(buf);
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
|
||||
SO_VM_SOCKETS_BUFFER_SIZE,
|
||||
|
|
@ -181,33 +201,100 @@ TEST_F(vsock, buffer_size_oversize_clamped)
|
|||
TEST_F(vsock, buffer_size_undersize)
|
||||
{
|
||||
char buf[4] = {};
|
||||
socklen_t optlen = sizeof(buf);
|
||||
socklen_t optlen;
|
||||
|
||||
optlen = sizeof(buf);
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK,
|
||||
SO_VM_SOCKETS_BUFFER_SIZE,
|
||||
buf, &optlen));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
ASSERT_EQ(sizeof(buf), optlen);
|
||||
}
|
||||
|
||||
TEST_F(vsock, bad_level)
|
||||
{
|
||||
socklen_t optlen;
|
||||
uint64_t val;
|
||||
socklen_t optlen = sizeof(val);
|
||||
|
||||
optlen = sizeof(val);
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, SOL_SOCKET + 1,
|
||||
SO_VM_SOCKETS_BUFFER_SIZE,
|
||||
&val, &optlen));
|
||||
ASSERT_EQ(ENOPROTOOPT, errno);
|
||||
ASSERT_EQ(sizeof(val), optlen);
|
||||
}
|
||||
|
||||
TEST_F(vsock, bad_optname)
|
||||
{
|
||||
socklen_t optlen;
|
||||
uint64_t val;
|
||||
socklen_t optlen = sizeof(val);
|
||||
|
||||
optlen = sizeof(val);
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK, 0x7fff,
|
||||
&val, &optlen));
|
||||
ASSERT_EQ(ENOPROTOOPT, errno);
|
||||
ASSERT_EQ(sizeof(val), optlen);
|
||||
}
|
||||
|
||||
/* SO_VM_SOCKETS_CONNECT_TIMEOUT_{NEW,OLD} return a sock_timeval-shaped
|
||||
* payload, which is wider than u64 on 64-bit. They exercise the path
|
||||
* where the protocol's reported lv (16 bytes) is larger than the
|
||||
* common 8-byte u64 case covered above.
|
||||
*/
|
||||
TEST_F(vsock, connect_timeout_new_exact)
|
||||
{
|
||||
struct __kernel_sock_timeval tv = {};
|
||||
socklen_t optlen;
|
||||
|
||||
optlen = sizeof(tv);
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
|
||||
SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW,
|
||||
&tv, &optlen));
|
||||
ASSERT_EQ(sizeof(tv), optlen);
|
||||
}
|
||||
|
||||
TEST_F(vsock, connect_timeout_new_oversize_clamped)
|
||||
{
|
||||
char buf[sizeof(struct __kernel_sock_timeval) * 2] = {};
|
||||
socklen_t optlen;
|
||||
|
||||
optlen = sizeof(buf);
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
|
||||
SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW,
|
||||
buf, &optlen));
|
||||
ASSERT_EQ(sizeof(struct __kernel_sock_timeval), optlen);
|
||||
}
|
||||
|
||||
TEST_F(vsock, connect_timeout_new_undersize)
|
||||
{
|
||||
socklen_t optlen;
|
||||
uint64_t val;
|
||||
|
||||
optlen = sizeof(val);
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK,
|
||||
SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW,
|
||||
&val, &optlen));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
ASSERT_EQ(sizeof(val), optlen);
|
||||
}
|
||||
|
||||
TEST_F(vsock, connect_timeout_old_exact)
|
||||
{
|
||||
struct __kernel_old_timeval tv = {};
|
||||
socklen_t optlen;
|
||||
|
||||
optlen = sizeof(tv);
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
|
||||
SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD,
|
||||
&tv, &optlen));
|
||||
ASSERT_EQ(sizeof(tv), optlen);
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user