Skip to content

Commit f5277ad

Browse files
committed
Merge tag 'for-6.7/io_uring-sockopt-2023-10-30' of git://git.kernel.dk/linux
Pull io_uring {get,set}sockopt support from Jens Axboe: "This adds support for using getsockopt and setsockopt via io_uring. The main use cases for this is to enable use of direct descriptors, rather than first instantiating a normal file descriptor, doing the option tweaking needed, then turning it into a direct descriptor. With this support, we can avoid needing a regular file descriptor completely. The net and bpf bits have been signed off on their side" * tag 'for-6.7/io_uring-sockopt-2023-10-30' of git://git.kernel.dk/linux: selftests/bpf/sockopt: Add io_uring support io_uring/cmd: Introduce SOCKET_URING_OP_SETSOCKOPT io_uring/cmd: Introduce SOCKET_URING_OP_GETSOCKOPT io_uring/cmd: return -EOPNOTSUPP if net is disabled selftests/net: Extract uring helpers to be reusable tools headers: Grab copy of io_uring.h io_uring/cmd: Pass compat mode in issue_flags net/socket: Break down __sys_getsockopt net/socket: Break down __sys_setsockopt bpf: Add sockptr support for setsockopt bpf: Add sockptr support for getsockopt
2 parents ffa059b + b9ec913 commit f5277ad

13 files changed

Lines changed: 1301 additions & 334 deletions

File tree

include/linux/bpf-cgroup.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,12 @@ int __cgroup_bpf_run_filter_sysctl(struct ctl_table_header *head,
143143
enum cgroup_bpf_attach_type atype);
144144

145145
int __cgroup_bpf_run_filter_setsockopt(struct sock *sock, int *level,
146-
int *optname, char __user *optval,
146+
int *optname, sockptr_t optval,
147147
int *optlen, char **kernel_optval);
148+
148149
int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
149-
int optname, char __user *optval,
150-
int __user *optlen, int max_optlen,
150+
int optname, sockptr_t optval,
151+
sockptr_t optlen, int max_optlen,
151152
int retval);
152153

153154
int __cgroup_bpf_run_filter_getsockopt_kern(struct sock *sk, int level,
@@ -392,7 +393,7 @@ static inline bool cgroup_bpf_sock_enabled(struct sock *sk,
392393
({ \
393394
int __ret = 0; \
394395
if (cgroup_bpf_enabled(CGROUP_GETSOCKOPT)) \
395-
get_user(__ret, optlen); \
396+
copy_from_sockptr(&__ret, optlen, sizeof(int)); \
396397
__ret; \
397398
})
398399

include/linux/io_uring.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ enum io_uring_cmd_flags {
2323

2424
/* set when uring wants to cancel a previously issued command */
2525
IO_URING_F_CANCEL = (1 << 11),
26+
IO_URING_F_COMPAT = (1 << 12),
2627
};
2728

2829
/* only top 8 bits of sqe->uring_cmd_flags for kernel internal use */

include/net/sock.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,11 +1864,13 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
18641864
sockptr_t optval, unsigned int optlen);
18651865
int sock_setsockopt(struct socket *sock, int level, int op,
18661866
sockptr_t optval, unsigned int optlen);
1867+
int do_sock_setsockopt(struct socket *sock, bool compat, int level,
1868+
int optname, sockptr_t optval, int optlen);
1869+
int do_sock_getsockopt(struct socket *sock, bool compat, int level,
1870+
int optname, sockptr_t optval, sockptr_t optlen);
18671871

18681872
int sk_getsockopt(struct sock *sk, int level, int optname,
18691873
sockptr_t optval, sockptr_t optlen);
1870-
int sock_getsockopt(struct socket *sock, int level, int op,
1871-
char __user *optval, int __user *optlen);
18721874
int sock_gettstamp(struct socket *sock, void __user *userstamp,
18731875
bool timeval, bool time32);
18741876
struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,

include/uapi/linux/io_uring.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ struct io_uring_sqe {
4343
union {
4444
__u64 addr; /* pointer to buffer or iovecs */
4545
__u64 splice_off_in;
46+
struct {
47+
__u32 level;
48+
__u32 optname;
49+
};
4650
};
4751
__u32 len; /* buffer size or number of iovecs */
4852
union {
@@ -80,6 +84,7 @@ struct io_uring_sqe {
8084
union {
8185
__s32 splice_fd_in;
8286
__u32 file_index;
87+
__u32 optlen;
8388
struct {
8489
__u16 addr_len;
8590
__u16 __pad3[1];
@@ -90,6 +95,7 @@ struct io_uring_sqe {
9095
__u64 addr3;
9196
__u64 __pad2[1];
9297
};
98+
__u64 optval;
9399
/*
94100
* If the ring is initialized with IORING_SETUP_SQE128, then
95101
* this field is used for 80 bytes of arbitrary command data
@@ -736,6 +742,8 @@ struct io_uring_recvmsg_out {
736742
enum {
737743
SOCKET_URING_OP_SIOCINQ = 0,
738744
SOCKET_URING_OP_SIOCOUTQ,
745+
SOCKET_URING_OP_GETSOCKOPT,
746+
SOCKET_URING_OP_SETSOCKOPT,
739747
};
740748

741749
#ifdef __cplusplus

io_uring/uring_cmd.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
175175
issue_flags |= IO_URING_F_SQE128;
176176
if (ctx->flags & IORING_SETUP_CQE32)
177177
issue_flags |= IO_URING_F_CQE32;
178+
if (ctx->compat)
179+
issue_flags |= IO_URING_F_COMPAT;
178180
if (ctx->flags & IORING_SETUP_IOPOLL) {
179181
if (!file->f_op->uring_cmd_iopoll)
180182
return -EOPNOTSUPP;
@@ -212,6 +214,52 @@ int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
212214
}
213215
EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed);
214216

217+
static inline int io_uring_cmd_getsockopt(struct socket *sock,
218+
struct io_uring_cmd *cmd,
219+
unsigned int issue_flags)
220+
{
221+
bool compat = !!(issue_flags & IO_URING_F_COMPAT);
222+
int optlen, optname, level, err;
223+
void __user *optval;
224+
225+
level = READ_ONCE(cmd->sqe->level);
226+
if (level != SOL_SOCKET)
227+
return -EOPNOTSUPP;
228+
229+
optval = u64_to_user_ptr(READ_ONCE(cmd->sqe->optval));
230+
optname = READ_ONCE(cmd->sqe->optname);
231+
optlen = READ_ONCE(cmd->sqe->optlen);
232+
233+
err = do_sock_getsockopt(sock, compat, level, optname,
234+
USER_SOCKPTR(optval),
235+
KERNEL_SOCKPTR(&optlen));
236+
if (err)
237+
return err;
238+
239+
/* On success, return optlen */
240+
return optlen;
241+
}
242+
243+
static inline int io_uring_cmd_setsockopt(struct socket *sock,
244+
struct io_uring_cmd *cmd,
245+
unsigned int issue_flags)
246+
{
247+
bool compat = !!(issue_flags & IO_URING_F_COMPAT);
248+
int optname, optlen, level;
249+
void __user *optval;
250+
sockptr_t optval_s;
251+
252+
optval = u64_to_user_ptr(READ_ONCE(cmd->sqe->optval));
253+
optname = READ_ONCE(cmd->sqe->optname);
254+
optlen = READ_ONCE(cmd->sqe->optlen);
255+
level = READ_ONCE(cmd->sqe->level);
256+
optval_s = USER_SOCKPTR(optval);
257+
258+
return do_sock_setsockopt(sock, compat, level, optname, optval_s,
259+
optlen);
260+
}
261+
262+
#if defined(CONFIG_NET)
215263
int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
216264
{
217265
struct socket *sock = cmd->file->private_data;
@@ -233,8 +281,13 @@ int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
233281
if (ret)
234282
return ret;
235283
return arg;
284+
case SOCKET_URING_OP_GETSOCKOPT:
285+
return io_uring_cmd_getsockopt(sock, cmd, issue_flags);
286+
case SOCKET_URING_OP_SETSOCKOPT:
287+
return io_uring_cmd_setsockopt(sock, cmd, issue_flags);
236288
default:
237289
return -EOPNOTSUPP;
238290
}
239291
}
240292
EXPORT_SYMBOL_GPL(io_uring_cmd_sock);
293+
#endif

kernel/bpf/cgroup.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,7 +1800,7 @@ static bool sockopt_buf_allocated(struct bpf_sockopt_kern *ctx,
18001800
}
18011801

18021802
int __cgroup_bpf_run_filter_setsockopt(struct sock *sk, int *level,
1803-
int *optname, char __user *optval,
1803+
int *optname, sockptr_t optval,
18041804
int *optlen, char **kernel_optval)
18051805
{
18061806
struct cgroup *cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
@@ -1823,7 +1823,8 @@ int __cgroup_bpf_run_filter_setsockopt(struct sock *sk, int *level,
18231823

18241824
ctx.optlen = *optlen;
18251825

1826-
if (copy_from_user(ctx.optval, optval, min(*optlen, max_optlen)) != 0) {
1826+
if (copy_from_sockptr(ctx.optval, optval,
1827+
min(*optlen, max_optlen))) {
18271828
ret = -EFAULT;
18281829
goto out;
18291830
}
@@ -1890,8 +1891,8 @@ int __cgroup_bpf_run_filter_setsockopt(struct sock *sk, int *level,
18901891
}
18911892

18921893
int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
1893-
int optname, char __user *optval,
1894-
int __user *optlen, int max_optlen,
1894+
int optname, sockptr_t optval,
1895+
sockptr_t optlen, int max_optlen,
18951896
int retval)
18961897
{
18971898
struct cgroup *cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
@@ -1918,8 +1919,8 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
19181919
* one that kernel returned as well to let
19191920
* BPF programs inspect the value.
19201921
*/
1921-
1922-
if (get_user(ctx.optlen, optlen)) {
1922+
if (copy_from_sockptr(&ctx.optlen, optlen,
1923+
sizeof(ctx.optlen))) {
19231924
ret = -EFAULT;
19241925
goto out;
19251926
}
@@ -1930,8 +1931,8 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
19301931
}
19311932
orig_optlen = ctx.optlen;
19321933

1933-
if (copy_from_user(ctx.optval, optval,
1934-
min(ctx.optlen, max_optlen)) != 0) {
1934+
if (copy_from_sockptr(ctx.optval, optval,
1935+
min(ctx.optlen, max_optlen))) {
19351936
ret = -EFAULT;
19361937
goto out;
19371938
}
@@ -1945,7 +1946,8 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
19451946
if (ret < 0)
19461947
goto out;
19471948

1948-
if (optval && (ctx.optlen > max_optlen || ctx.optlen < 0)) {
1949+
if (!sockptr_is_null(optval) &&
1950+
(ctx.optlen > max_optlen || ctx.optlen < 0)) {
19491951
if (orig_optlen > PAGE_SIZE && ctx.optlen >= 0) {
19501952
pr_info_once("bpf getsockopt: ignoring program buffer with optlen=%d (max_optlen=%d)\n",
19511953
ctx.optlen, max_optlen);
@@ -1957,11 +1959,12 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
19571959
}
19581960

19591961
if (ctx.optlen != 0) {
1960-
if (optval && copy_to_user(optval, ctx.optval, ctx.optlen)) {
1962+
if (!sockptr_is_null(optval) &&
1963+
copy_to_sockptr(optval, ctx.optval, ctx.optlen)) {
19611964
ret = -EFAULT;
19621965
goto out;
19631966
}
1964-
if (put_user(ctx.optlen, optlen)) {
1967+
if (copy_to_sockptr(optlen, &ctx.optlen, sizeof(ctx.optlen))) {
19651968
ret = -EFAULT;
19661969
goto out;
19671970
}

net/core/sock.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,14 +2003,6 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
20032003
return 0;
20042004
}
20052005

2006-
int sock_getsockopt(struct socket *sock, int level, int optname,
2007-
char __user *optval, int __user *optlen)
2008-
{
2009-
return sk_getsockopt(sock->sk, level, optname,
2010-
USER_SOCKPTR(optval),
2011-
USER_SOCKPTR(optlen));
2012-
}
2013-
20142006
/*
20152007
* Initialize an sk_lock.
20162008
*

0 commit comments

Comments
 (0)