1d0e437b7SPavel Begunkov /* SPDX-License-Identifier: GPL-2.0 */
2d0e437b7SPavel Begunkov #include <linux/mutex.h>
3d0e437b7SPavel Begunkov #include <linux/bpf.h>
4d0e437b7SPavel Begunkov #include <linux/bpf_verifier.h>
5d0e437b7SPavel Begunkov
6d0e437b7SPavel Begunkov #include "io_uring.h"
7d0e437b7SPavel Begunkov #include "register.h"
898f37634SPavel Begunkov #include "loop.h"
989081924SPavel Begunkov #include "memmap.h"
10d0e437b7SPavel Begunkov #include "bpf-ops.h"
11d0e437b7SPavel Begunkov
1298f37634SPavel Begunkov static DEFINE_MUTEX(io_bpf_ctrl_mutex);
13d0e437b7SPavel Begunkov static const struct btf_type *loop_params_type;
14d0e437b7SPavel Begunkov
1589081924SPavel Begunkov __bpf_kfunc_start_defs();
1689081924SPavel Begunkov
bpf_io_uring_submit_sqes(struct io_ring_ctx * ctx,u32 nr)1789081924SPavel Begunkov __bpf_kfunc int bpf_io_uring_submit_sqes(struct io_ring_ctx *ctx, u32 nr)
1889081924SPavel Begunkov {
1989081924SPavel Begunkov return io_submit_sqes(ctx, nr);
2089081924SPavel Begunkov }
2189081924SPavel Begunkov
2289081924SPavel Begunkov __bpf_kfunc
bpf_io_uring_get_region(struct io_ring_ctx * ctx,__u32 region_id,const size_t rdwr_buf_size)2389081924SPavel Begunkov __u8 *bpf_io_uring_get_region(struct io_ring_ctx *ctx, __u32 region_id,
2489081924SPavel Begunkov const size_t rdwr_buf_size)
2589081924SPavel Begunkov {
2689081924SPavel Begunkov struct io_mapped_region *r;
2789081924SPavel Begunkov
2889081924SPavel Begunkov lockdep_assert_held(&ctx->uring_lock);
2989081924SPavel Begunkov
3089081924SPavel Begunkov switch (region_id) {
3189081924SPavel Begunkov case IOU_REGION_MEM:
3289081924SPavel Begunkov r = &ctx->param_region;
3389081924SPavel Begunkov break;
3489081924SPavel Begunkov case IOU_REGION_CQ:
3589081924SPavel Begunkov r = &ctx->ring_region;
3689081924SPavel Begunkov break;
3789081924SPavel Begunkov case IOU_REGION_SQ:
3889081924SPavel Begunkov r = &ctx->sq_region;
3989081924SPavel Begunkov break;
4089081924SPavel Begunkov default:
4189081924SPavel Begunkov return NULL;
4289081924SPavel Begunkov }
4389081924SPavel Begunkov
4489081924SPavel Begunkov if (unlikely(rdwr_buf_size > io_region_size(r)))
4589081924SPavel Begunkov return NULL;
4689081924SPavel Begunkov return io_region_get_ptr(r);
4789081924SPavel Begunkov }
4889081924SPavel Begunkov
4989081924SPavel Begunkov __bpf_kfunc_end_defs();
5089081924SPavel Begunkov
5189081924SPavel Begunkov BTF_KFUNCS_START(io_uring_kfunc_set)
5289081924SPavel Begunkov BTF_ID_FLAGS(func, bpf_io_uring_submit_sqes, KF_SLEEPABLE);
5389081924SPavel Begunkov BTF_ID_FLAGS(func, bpf_io_uring_get_region, KF_RET_NULL);
5489081924SPavel Begunkov BTF_KFUNCS_END(io_uring_kfunc_set)
5589081924SPavel Begunkov
5689081924SPavel Begunkov static const struct btf_kfunc_id_set bpf_io_uring_kfunc_set = {
5789081924SPavel Begunkov .owner = THIS_MODULE,
5889081924SPavel Begunkov .set = &io_uring_kfunc_set,
5989081924SPavel Begunkov };
6089081924SPavel Begunkov
io_bpf_ops__loop_step(struct io_ring_ctx * ctx,struct iou_loop_params * lp)61d0e437b7SPavel Begunkov static int io_bpf_ops__loop_step(struct io_ring_ctx *ctx,
62d0e437b7SPavel Begunkov struct iou_loop_params *lp)
63d0e437b7SPavel Begunkov {
64d0e437b7SPavel Begunkov return IOU_LOOP_STOP;
65d0e437b7SPavel Begunkov }
66d0e437b7SPavel Begunkov
67d0e437b7SPavel Begunkov static struct io_uring_bpf_ops io_bpf_ops_stubs = {
68d0e437b7SPavel Begunkov .loop_step = io_bpf_ops__loop_step,
69d0e437b7SPavel Begunkov };
70d0e437b7SPavel Begunkov
bpf_io_is_valid_access(int off,int size,enum bpf_access_type type,const struct bpf_prog * prog,struct bpf_insn_access_aux * info)71d0e437b7SPavel Begunkov static bool bpf_io_is_valid_access(int off, int size,
72d0e437b7SPavel Begunkov enum bpf_access_type type,
73d0e437b7SPavel Begunkov const struct bpf_prog *prog,
74d0e437b7SPavel Begunkov struct bpf_insn_access_aux *info)
75d0e437b7SPavel Begunkov {
76d0e437b7SPavel Begunkov if (type != BPF_READ)
77d0e437b7SPavel Begunkov return false;
78d0e437b7SPavel Begunkov if (off < 0 || off >= sizeof(__u64) * MAX_BPF_FUNC_ARGS)
79d0e437b7SPavel Begunkov return false;
80d0e437b7SPavel Begunkov if (off % size != 0)
81d0e437b7SPavel Begunkov return false;
82d0e437b7SPavel Begunkov
83d0e437b7SPavel Begunkov return btf_ctx_access(off, size, type, prog, info);
84d0e437b7SPavel Begunkov }
85d0e437b7SPavel Begunkov
bpf_io_btf_struct_access(struct bpf_verifier_log * log,const struct bpf_reg_state * reg,int off,int size)86d0e437b7SPavel Begunkov static int bpf_io_btf_struct_access(struct bpf_verifier_log *log,
87d0e437b7SPavel Begunkov const struct bpf_reg_state *reg, int off,
88d0e437b7SPavel Begunkov int size)
89d0e437b7SPavel Begunkov {
90d0e437b7SPavel Begunkov const struct btf_type *t = btf_type_by_id(reg->btf, reg->btf_id);
91d0e437b7SPavel Begunkov
92d0e437b7SPavel Begunkov if (t == loop_params_type) {
93d0e437b7SPavel Begunkov if (off + size <= offsetofend(struct iou_loop_params, cq_wait_idx))
94d0e437b7SPavel Begunkov return SCALAR_VALUE;
95d0e437b7SPavel Begunkov }
96d0e437b7SPavel Begunkov
97d0e437b7SPavel Begunkov return -EACCES;
98d0e437b7SPavel Begunkov }
99d0e437b7SPavel Begunkov
100d0e437b7SPavel Begunkov static const struct bpf_verifier_ops bpf_io_verifier_ops = {
101d0e437b7SPavel Begunkov .get_func_proto = bpf_base_func_proto,
102d0e437b7SPavel Begunkov .is_valid_access = bpf_io_is_valid_access,
103d0e437b7SPavel Begunkov .btf_struct_access = bpf_io_btf_struct_access,
104d0e437b7SPavel Begunkov };
105d0e437b7SPavel Begunkov
106d0e437b7SPavel Begunkov static const struct btf_type *
io_lookup_struct_type(struct btf * btf,const char * name)107d0e437b7SPavel Begunkov io_lookup_struct_type(struct btf *btf, const char *name)
108d0e437b7SPavel Begunkov {
109d0e437b7SPavel Begunkov s32 type_id;
110d0e437b7SPavel Begunkov
111d0e437b7SPavel Begunkov type_id = btf_find_by_name_kind(btf, name, BTF_KIND_STRUCT);
112d0e437b7SPavel Begunkov if (type_id < 0)
113d0e437b7SPavel Begunkov return NULL;
114d0e437b7SPavel Begunkov return btf_type_by_id(btf, type_id);
115d0e437b7SPavel Begunkov }
116d0e437b7SPavel Begunkov
bpf_io_init(struct btf * btf)117d0e437b7SPavel Begunkov static int bpf_io_init(struct btf *btf)
118d0e437b7SPavel Begunkov {
11989081924SPavel Begunkov int ret;
12089081924SPavel Begunkov
121d0e437b7SPavel Begunkov loop_params_type = io_lookup_struct_type(btf, "iou_loop_params");
122d0e437b7SPavel Begunkov if (!loop_params_type) {
123d0e437b7SPavel Begunkov pr_err("io_uring: Failed to locate iou_loop_params\n");
124d0e437b7SPavel Begunkov return -EINVAL;
125d0e437b7SPavel Begunkov }
126d0e437b7SPavel Begunkov
12789081924SPavel Begunkov ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS,
12889081924SPavel Begunkov &bpf_io_uring_kfunc_set);
12989081924SPavel Begunkov if (ret) {
13089081924SPavel Begunkov pr_err("io_uring: Failed to register kfuncs (%d)\n", ret);
13189081924SPavel Begunkov return ret;
13289081924SPavel Begunkov }
133d0e437b7SPavel Begunkov return 0;
134d0e437b7SPavel Begunkov }
135d0e437b7SPavel Begunkov
bpf_io_check_member(const struct btf_type * t,const struct btf_member * member,const struct bpf_prog * prog)136d0e437b7SPavel Begunkov static int bpf_io_check_member(const struct btf_type *t,
137d0e437b7SPavel Begunkov const struct btf_member *member,
138d0e437b7SPavel Begunkov const struct bpf_prog *prog)
139d0e437b7SPavel Begunkov {
140d0e437b7SPavel Begunkov return 0;
141d0e437b7SPavel Begunkov }
142d0e437b7SPavel Begunkov
bpf_io_init_member(const struct btf_type * t,const struct btf_member * member,void * kdata,const void * udata)143d0e437b7SPavel Begunkov static int bpf_io_init_member(const struct btf_type *t,
144d0e437b7SPavel Begunkov const struct btf_member *member,
145d0e437b7SPavel Begunkov void *kdata, const void *udata)
146d0e437b7SPavel Begunkov {
14798f37634SPavel Begunkov u32 moff = __btf_member_bit_offset(t, member) / 8;
14898f37634SPavel Begunkov const struct io_uring_bpf_ops *uops = udata;
14998f37634SPavel Begunkov struct io_uring_bpf_ops *ops = kdata;
15098f37634SPavel Begunkov
15198f37634SPavel Begunkov switch (moff) {
15298f37634SPavel Begunkov case offsetof(struct io_uring_bpf_ops, ring_fd):
15398f37634SPavel Begunkov ops->ring_fd = uops->ring_fd;
15498f37634SPavel Begunkov return 1;
15598f37634SPavel Begunkov }
15698f37634SPavel Begunkov return 0;
15798f37634SPavel Begunkov }
15898f37634SPavel Begunkov
io_install_bpf(struct io_ring_ctx * ctx,struct io_uring_bpf_ops * ops)15998f37634SPavel Begunkov static int io_install_bpf(struct io_ring_ctx *ctx, struct io_uring_bpf_ops *ops)
16098f37634SPavel Begunkov {
16198f37634SPavel Begunkov if (ctx->flags & (IORING_SETUP_SQPOLL | IORING_SETUP_IOPOLL))
16298f37634SPavel Begunkov return -EOPNOTSUPP;
16398f37634SPavel Begunkov if (!(ctx->flags & IORING_SETUP_DEFER_TASKRUN))
16498f37634SPavel Begunkov return -EOPNOTSUPP;
16598f37634SPavel Begunkov
16698f37634SPavel Begunkov if (ctx->bpf_ops)
16798f37634SPavel Begunkov return -EBUSY;
16898f37634SPavel Begunkov if (WARN_ON_ONCE(!ops->loop_step))
16998f37634SPavel Begunkov return -EINVAL;
17098f37634SPavel Begunkov
17198f37634SPavel Begunkov ops->priv = ctx;
17298f37634SPavel Begunkov ctx->bpf_ops = ops;
17398f37634SPavel Begunkov ctx->loop_step = ops->loop_step;
174d0e437b7SPavel Begunkov return 0;
175d0e437b7SPavel Begunkov }
176d0e437b7SPavel Begunkov
bpf_io_reg(void * kdata,struct bpf_link * link)177d0e437b7SPavel Begunkov static int bpf_io_reg(void *kdata, struct bpf_link *link)
178d0e437b7SPavel Begunkov {
17998f37634SPavel Begunkov struct io_uring_bpf_ops *ops = kdata;
18098f37634SPavel Begunkov struct io_ring_ctx *ctx;
18198f37634SPavel Begunkov struct file *file;
18298f37634SPavel Begunkov int ret = -EBUSY;
18398f37634SPavel Begunkov
184*c5e9f6a9SJens Axboe file = io_uring_ctx_get_file(ops->ring_fd, false);
18598f37634SPavel Begunkov if (IS_ERR(file))
18698f37634SPavel Begunkov return PTR_ERR(file);
18798f37634SPavel Begunkov ctx = file->private_data;
18898f37634SPavel Begunkov
18998f37634SPavel Begunkov scoped_guard(mutex, &io_bpf_ctrl_mutex) {
19098f37634SPavel Begunkov guard(mutex)(&ctx->uring_lock);
19198f37634SPavel Begunkov ret = io_install_bpf(ctx, ops);
19298f37634SPavel Begunkov }
19398f37634SPavel Begunkov
19498f37634SPavel Begunkov fput(file);
19598f37634SPavel Begunkov return ret;
19698f37634SPavel Begunkov }
19798f37634SPavel Begunkov
io_eject_bpf(struct io_ring_ctx * ctx)19898f37634SPavel Begunkov static void io_eject_bpf(struct io_ring_ctx *ctx)
19998f37634SPavel Begunkov {
20098f37634SPavel Begunkov struct io_uring_bpf_ops *ops = ctx->bpf_ops;
20198f37634SPavel Begunkov
20298f37634SPavel Begunkov if (WARN_ON_ONCE(!ops))
20398f37634SPavel Begunkov return;
20498f37634SPavel Begunkov if (WARN_ON_ONCE(ops->priv != ctx))
20598f37634SPavel Begunkov return;
20698f37634SPavel Begunkov
20798f37634SPavel Begunkov ops->priv = NULL;
20898f37634SPavel Begunkov ctx->bpf_ops = NULL;
20998f37634SPavel Begunkov ctx->loop_step = NULL;
210d0e437b7SPavel Begunkov }
211d0e437b7SPavel Begunkov
bpf_io_unreg(void * kdata,struct bpf_link * link)212d0e437b7SPavel Begunkov static void bpf_io_unreg(void *kdata, struct bpf_link *link)
213d0e437b7SPavel Begunkov {
21498f37634SPavel Begunkov struct io_uring_bpf_ops *ops = kdata;
21598f37634SPavel Begunkov struct io_ring_ctx *ctx;
21698f37634SPavel Begunkov
21798f37634SPavel Begunkov guard(mutex)(&io_bpf_ctrl_mutex);
21898f37634SPavel Begunkov ctx = ops->priv;
21998f37634SPavel Begunkov if (ctx) {
22098f37634SPavel Begunkov guard(mutex)(&ctx->uring_lock);
22198f37634SPavel Begunkov if (WARN_ON_ONCE(ctx->bpf_ops != ops))
22298f37634SPavel Begunkov return;
22398f37634SPavel Begunkov
22498f37634SPavel Begunkov io_eject_bpf(ctx);
22598f37634SPavel Begunkov }
22698f37634SPavel Begunkov }
22798f37634SPavel Begunkov
io_unregister_bpf_ops(struct io_ring_ctx * ctx)22898f37634SPavel Begunkov void io_unregister_bpf_ops(struct io_ring_ctx *ctx)
22998f37634SPavel Begunkov {
23098f37634SPavel Begunkov /*
23198f37634SPavel Begunkov * ->bpf_ops is write protected by io_bpf_ctrl_mutex and uring_lock,
23298f37634SPavel Begunkov * and read protected by either. Try to avoid taking the global lock
23398f37634SPavel Begunkov * for rings that never had any bpf installed.
23498f37634SPavel Begunkov */
23598f37634SPavel Begunkov scoped_guard(mutex, &ctx->uring_lock) {
23698f37634SPavel Begunkov if (!ctx->bpf_ops)
23798f37634SPavel Begunkov return;
23898f37634SPavel Begunkov }
23998f37634SPavel Begunkov
24098f37634SPavel Begunkov guard(mutex)(&io_bpf_ctrl_mutex);
24198f37634SPavel Begunkov guard(mutex)(&ctx->uring_lock);
24298f37634SPavel Begunkov if (ctx->bpf_ops)
24398f37634SPavel Begunkov io_eject_bpf(ctx);
244d0e437b7SPavel Begunkov }
245d0e437b7SPavel Begunkov
246d0e437b7SPavel Begunkov static struct bpf_struct_ops bpf_ring_ops = {
247d0e437b7SPavel Begunkov .verifier_ops = &bpf_io_verifier_ops,
248d0e437b7SPavel Begunkov .reg = bpf_io_reg,
249d0e437b7SPavel Begunkov .unreg = bpf_io_unreg,
250d0e437b7SPavel Begunkov .check_member = bpf_io_check_member,
251d0e437b7SPavel Begunkov .init_member = bpf_io_init_member,
252d0e437b7SPavel Begunkov .init = bpf_io_init,
253d0e437b7SPavel Begunkov .cfi_stubs = &io_bpf_ops_stubs,
254d0e437b7SPavel Begunkov .name = "io_uring_bpf_ops",
255d0e437b7SPavel Begunkov .owner = THIS_MODULE,
256d0e437b7SPavel Begunkov };
257d0e437b7SPavel Begunkov
io_uring_bpf_init(void)258d0e437b7SPavel Begunkov static int __init io_uring_bpf_init(void)
259d0e437b7SPavel Begunkov {
260d0e437b7SPavel Begunkov int ret;
261d0e437b7SPavel Begunkov
262d0e437b7SPavel Begunkov ret = register_bpf_struct_ops(&bpf_ring_ops, io_uring_bpf_ops);
263d0e437b7SPavel Begunkov if (ret) {
264d0e437b7SPavel Begunkov pr_err("io_uring: Failed to register struct_ops (%d)\n", ret);
265d0e437b7SPavel Begunkov return ret;
266d0e437b7SPavel Begunkov }
267d0e437b7SPavel Begunkov
268d0e437b7SPavel Begunkov return 0;
269d0e437b7SPavel Begunkov }
270d0e437b7SPavel Begunkov __initcall(io_uring_bpf_init);
271