io_uring/bpf_filter.c

Source file repositories/reference/linux-study-clean/io_uring/bpf_filter.c

File Facts

System
Linux kernel
Corpus path
io_uring/bpf_filter.c
Extension
.c
Size
11947 bytes
Lines
458
Domain
Kernel Services
Bucket
io_uring
Inferred role
Kernel Services: implementation source
Status
source implementation candidate

Why This File Exists

Shared kernel service surface used by multiple subsystems, including helpers, cryptography, virtualization support, and async I/O infrastructure.

Dependency Surface

Detected Declarations

Annotated Snippet

struct io_bpf_filter {
	refcount_t		refs;
	struct bpf_prog		*prog;
	struct io_bpf_filter	*next;
};

/* Deny if this is set as the filter */
static const struct io_bpf_filter dummy_filter;

static void io_uring_populate_bpf_ctx(struct io_uring_bpf_ctx *bctx,
				      struct io_kiocb *req)
{
	const struct io_issue_def *def = &io_issue_defs[req->opcode];

	bctx->opcode = req->opcode;
	bctx->sqe_flags = (__force int) req->flags & SQE_VALID_FLAGS;
	bctx->user_data = req->cqe.user_data;
	/* clear residual, anything from pdu_size and below */
	memset((void *) bctx + offsetof(struct io_uring_bpf_ctx, pdu_size), 0,
		sizeof(*bctx) - offsetof(struct io_uring_bpf_ctx, pdu_size));

	/*
	 * Opcodes can provide a handler for populating more data into bctx,
	 * for filters to use.
	 */
	if (def->filter_pdu_size) {
		bctx->pdu_size = def->filter_pdu_size;
		def->filter_populate(bctx, req);
	}
}

/*
 * Run registered filters for a given opcode. For filters, a return of 0 denies
 * execution of the request, a return of 1 allows it. If any filter for an
 * opcode returns 0, filter processing is stopped, and the request is denied.
 * This also stops the processing of filters.
 *
 * __io_uring_run_bpf_filters() returns 0 on success, allow running the
 * request, and -EACCES when a request is denied.
 */
int __io_uring_run_bpf_filters(struct io_bpf_filter __rcu **filters,
			       struct io_kiocb *req)
{
	struct io_bpf_filter *filter;
	struct io_uring_bpf_ctx bpf_ctx;
	int ret;

	/* Fast check for existence of filters outside of RCU */
	if (!rcu_access_pointer(filters[req->opcode]))
		return 0;

	/*
	 * req->opcode has already been validated to be within the range
	 * of what we expect, io_init_req() does this.
	 */
	guard(rcu)();
	filter = rcu_dereference(filters[req->opcode]);
	if (!filter)
		return 0;
	else if (filter == &dummy_filter)
		return -EACCES;

	io_uring_populate_bpf_ctx(&bpf_ctx, req);

	/*
	 * Iterate registered filters. The opcode is allowed IFF all filters
	 * return 1. If any filter returns denied, opcode will be denied.
	 */
	do {
		if (filter == &dummy_filter)
			return -EACCES;
		ret = bpf_prog_run_pin_on_cpu(filter->prog, &bpf_ctx);
		if (!ret)
			return -EACCES;
		filter = filter->next;
	} while (filter);

	return 0;
}

static void io_free_bpf_filters(struct rcu_head *head)
{
	struct io_bpf_filter __rcu **filter;
	struct io_bpf_filters *filters;
	int i;

	filters = container_of(head, struct io_bpf_filters, rcu_head);
	scoped_guard(spinlock, &filters->lock) {
		filter = filters->filters;
		if (!filter)

Annotation

Implementation Notes