This is not meant to be applied as of now.
This is just to show what I meant for [0].
And of course, this doesn't even compile because you need [0] to be
applied and the branch for-6.10/hid-bpf on the hid tree.
The purpose is to remove the bpf_tail_call from the preloaded bpf at
boot time.
Cheers,
Benjamin
[0] https://lore.kernel.org/bpf/[email protected]/v
Signed-off-by: Benjamin Tissoires <[email protected]>
---
Benjamin Tissoires (7):
HID: bpf: change the prog run logic
selftests/hid: fix bpf programs for the new attachment logic
HID: bpf: allow for sleepable bpf hooks
HID: add source argument to HID low level functions
WIP: add HID-BPF hooks for hid_hw_raw_requests
WIP: selftests/hid: add tests for hid_hw_raw_request HID-BPF hooks
HID: bpf: prevent infinite recursions with hid_hw_raw_requests hooks
drivers/hid/bpf/entrypoints/Makefile | 93 --------
drivers/hid/bpf/entrypoints/README | 4 -
drivers/hid/bpf/entrypoints/entrypoints.bpf.c | 25 --
drivers/hid/bpf/entrypoints/entrypoints.lskel.h | 248 --------------------
drivers/hid/bpf/hid_bpf_dispatch.c | 252 +++++++++++----------
drivers/hid/bpf/hid_bpf_dispatch.h | 12 +-
drivers/hid/bpf/hid_bpf_jmp_table.c | 199 ++++------------
drivers/hid/hid-core.c | 91 +++++---
drivers/hid/hidraw.c | 10 +-
include/linux/hid.h | 6 +
include/linux/hid_bpf.h | 33 ++-
tools/testing/selftests/hid/hid_bpf.c | 61 ++++-
tools/testing/selftests/hid/progs/hid.c | 91 +++++---
.../testing/selftests/hid/progs/hid_bpf_helpers.h | 60 ++++-
14 files changed, 449 insertions(+), 736 deletions(-)
---
base-commit: 89ea968a9d759f71ac7b8d50949a8e5e5bcb1111
change-id: 20240508-hid_bpf_async_fun-25a8b97b5352
Best regards,
--
Benjamin Tissoires <[email protected]>
We were previously relying on a pre-loaded tracing bpf program which runs
bpf_tail_call(). However we can simplify this by a lot by relying on
the new __async suffix which gives us basically a function pointer to
the bpf program itself. This way, we rely on a much simpler process,
ditching entirely the prog fd array and that tracing bpf program.
Note the selftests will break and are handled in the later patch.
Signed-off-by: Benjamin Tissoires <[email protected]>
---
drivers/hid/bpf/entrypoints/Makefile | 93 ---------
drivers/hid/bpf/entrypoints/README | 4 -
drivers/hid/bpf/entrypoints/entrypoints.bpf.c | 25 ---
drivers/hid/bpf/entrypoints/entrypoints.lskel.h | 248 ------------------------
drivers/hid/bpf/hid_bpf_dispatch.c | 94 ++-------
drivers/hid/bpf/hid_bpf_dispatch.h | 8 +-
drivers/hid/bpf/hid_bpf_jmp_table.c | 174 +++--------------
include/linux/hid_bpf.h | 3 -
8 files changed, 51 insertions(+), 598 deletions(-)
diff --git a/drivers/hid/bpf/entrypoints/Makefile b/drivers/hid/bpf/entrypoints/Makefile
deleted file mode 100644
index 43b99b5575cf..000000000000
--- a/drivers/hid/bpf/entrypoints/Makefile
+++ /dev/null
@@ -1,93 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-OUTPUT := .output
-abs_out := $(abspath $(OUTPUT))
-
-CLANG ?= clang
-LLC ?= llc
-LLVM_STRIP ?= llvm-strip
-
-TOOLS_PATH := $(abspath ../../../../tools)
-BPFTOOL_SRC := $(TOOLS_PATH)/bpf/bpftool
-BPFTOOL_OUTPUT := $(abs_out)/bpftool
-DEFAULT_BPFTOOL := $(BPFTOOL_OUTPUT)/bootstrap/bpftool
-BPFTOOL ?= $(DEFAULT_BPFTOOL)
-
-LIBBPF_SRC := $(TOOLS_PATH)/lib/bpf
-LIBBPF_OUTPUT := $(abs_out)/libbpf
-LIBBPF_DESTDIR := $(LIBBPF_OUTPUT)
-LIBBPF_INCLUDE := $(LIBBPF_DESTDIR)/include
-BPFOBJ := $(LIBBPF_OUTPUT)/libbpf.a
-
-INCLUDES := -I$(OUTPUT) -I$(LIBBPF_INCLUDE) -I$(TOOLS_PATH)/include/uapi
-CFLAGS := -g -Wall
-
-VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
- $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
- ../../../../vmlinux \
- /sys/kernel/btf/vmlinux \
- /boot/vmlinux-$(shell uname -r)
-VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS))))
-ifeq ($(VMLINUX_BTF),)
-$(error Cannot find a vmlinux for VMLINUX_BTF at any of "$(VMLINUX_BTF_PATHS)")
-endif
-
-ifeq ($(V),1)
-Q =
-msg =
-else
-Q = @
-msg = @printf ' %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
-MAKEFLAGS += --no-print-directory
-submake_extras := feature_display=0
-endif
-
-.DELETE_ON_ERROR:
-
-.PHONY: all clean
-
-all: entrypoints.lskel.h
-
-clean:
- $(call msg,CLEAN)
- $(Q)rm -rf $(OUTPUT) entrypoints
-
-entrypoints.lskel.h: $(OUTPUT)/entrypoints.bpf.o | $(BPFTOOL)
- $(call msg,GEN-SKEL,$@)
- $(Q)$(BPFTOOL) gen skeleton -L $< > $@
-
-
-$(OUTPUT)/entrypoints.bpf.o: entrypoints.bpf.c $(OUTPUT)/vmlinux.h $(BPFOBJ) | $(OUTPUT)
- $(call msg,BPF,$@)
- $(Q)$(CLANG) -g -O2 --target=bpf $(INCLUDES) \
- -c $(filter %.c,$^) -o $@ && \
- $(LLVM_STRIP) -g $@
-
-$(OUTPUT)/vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) | $(INCLUDE_DIR)
-ifeq ($(VMLINUX_H),)
- $(call msg,GEN,,$@)
- $(Q)$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@
-else
- $(call msg,CP,,$@)
- $(Q)cp "$(VMLINUX_H)" $@
-endif
-
-$(OUTPUT) $(LIBBPF_OUTPUT) $(BPFTOOL_OUTPUT):
- $(call msg,MKDIR,$@)
- $(Q)mkdir -p $@
-
-$(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OUTPUT)
- $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) \
- OUTPUT=$(abspath $(dir $@))/ prefix= \
- DESTDIR=$(LIBBPF_DESTDIR) $(abspath $@) install_headers
-
-ifeq ($(CROSS_COMPILE),)
-$(DEFAULT_BPFTOOL): $(BPFOBJ) | $(BPFTOOL_OUTPUT)
- $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \
- OUTPUT=$(BPFTOOL_OUTPUT)/ \
- LIBBPF_BOOTSTRAP_OUTPUT=$(LIBBPF_OUTPUT)/ \
- LIBBPF_BOOTSTRAP_DESTDIR=$(LIBBPF_DESTDIR)/ bootstrap
-else
-$(DEFAULT_BPFTOOL): | $(BPFTOOL_OUTPUT)
- $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \
- OUTPUT=$(BPFTOOL_OUTPUT)/ bootstrap
-endif
diff --git a/drivers/hid/bpf/entrypoints/README b/drivers/hid/bpf/entrypoints/README
deleted file mode 100644
index 147e0d41509f..000000000000
--- a/drivers/hid/bpf/entrypoints/README
+++ /dev/null
@@ -1,4 +0,0 @@
-WARNING:
-If you change "entrypoints.bpf.c" do "make -j" in this directory to rebuild "entrypoints.skel.h".
-Make sure to have clang 10 installed.
-See Documentation/bpf/bpf_devel_QA.rst
diff --git a/drivers/hid/bpf/entrypoints/entrypoints.bpf.c b/drivers/hid/bpf/entrypoints/entrypoints.bpf.c
deleted file mode 100644
index c22921125a1a..000000000000
--- a/drivers/hid/bpf/entrypoints/entrypoints.bpf.c
+++ /dev/null
@@ -1,25 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (c) 2022 Benjamin Tissoires */
-
-#include ".output/vmlinux.h"
-#include <bpf/bpf_helpers.h>
-#include <bpf/bpf_tracing.h>
-
-#define HID_BPF_MAX_PROGS 1024
-
-struct {
- __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
- __uint(max_entries, HID_BPF_MAX_PROGS);
- __uint(key_size, sizeof(__u32));
- __uint(value_size, sizeof(__u32));
-} hid_jmp_table SEC(".maps");
-
-SEC("fmod_ret/__hid_bpf_tail_call")
-int BPF_PROG(hid_tail_call, struct hid_bpf_ctx *hctx)
-{
- bpf_tail_call(ctx, &hid_jmp_table, hctx->index);
-
- return 0;
-}
-
-char LICENSE[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/entrypoints/entrypoints.lskel.h b/drivers/hid/bpf/entrypoints/entrypoints.lskel.h
deleted file mode 100644
index 35618051598c..000000000000
--- a/drivers/hid/bpf/entrypoints/entrypoints.lskel.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
-/* THIS FILE IS AUTOGENERATED BY BPFTOOL! */
-#ifndef __ENTRYPOINTS_BPF_SKEL_H__
-#define __ENTRYPOINTS_BPF_SKEL_H__
-
-#include <bpf/skel_internal.h>
-
-struct entrypoints_bpf {
- struct bpf_loader_ctx ctx;
- struct {
- struct bpf_map_desc hid_jmp_table;
- } maps;
- struct {
- struct bpf_prog_desc hid_tail_call;
- } progs;
- struct {
- int hid_tail_call_fd;
- } links;
-};
-
-static inline int
-entrypoints_bpf__hid_tail_call__attach(struct entrypoints_bpf *skel)
-{
- int prog_fd = skel->progs.hid_tail_call.prog_fd;
- int fd = skel_raw_tracepoint_open(NULL, prog_fd);
-
- if (fd > 0)
- skel->links.hid_tail_call_fd = fd;
- return fd;
-}
-
-static inline int
-entrypoints_bpf__attach(struct entrypoints_bpf *skel)
-{
- int ret = 0;
-
- ret = ret < 0 ? ret : entrypoints_bpf__hid_tail_call__attach(skel);
- return ret < 0 ? ret : 0;
-}
-
-static inline void
-entrypoints_bpf__detach(struct entrypoints_bpf *skel)
-{
- skel_closenz(skel->links.hid_tail_call_fd);
-}
-static void
-entrypoints_bpf__destroy(struct entrypoints_bpf *skel)
-{
- if (!skel)
- return;
- entrypoints_bpf__detach(skel);
- skel_closenz(skel->progs.hid_tail_call.prog_fd);
- skel_closenz(skel->maps.hid_jmp_table.map_fd);
- skel_free(skel);
-}
-static inline struct entrypoints_bpf *
-entrypoints_bpf__open(void)
-{
- struct entrypoints_bpf *skel;
-
- skel = skel_alloc(sizeof(*skel));
- if (!skel)
- goto cleanup;
- skel->ctx.sz = (void *)&skel->links - (void *)skel;
- return skel;
-cleanup:
- entrypoints_bpf__destroy(skel);
- return NULL;
-}
-
-static inline int
-entrypoints_bpf__load(struct entrypoints_bpf *skel)
-{
- struct bpf_load_and_run_opts opts = {};
- int err;
-
- opts.ctx = (struct bpf_loader_ctx *)skel;
- opts.data_sz = 2856;
- opts.data = (void *)"\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9f\xeb\x01\0\
-\x18\0\0\0\0\0\0\0\x60\x02\0\0\x60\x02\0\0\x12\x02\0\0\0\0\0\0\0\0\0\x02\x03\0\
-\0\0\x01\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\
-\0\0\x04\0\0\0\x03\0\0\0\x05\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\
-\x02\x06\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\0\x04\0\0\0\0\0\0\
-\0\0\0\x02\x08\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x04\0\0\0\0\
-\0\0\0\x04\0\0\x04\x20\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\
-\x40\0\0\0\x2a\0\0\0\x07\0\0\0\x80\0\0\0\x33\0\0\0\x07\0\0\0\xc0\0\0\0\x3e\0\0\
-\0\0\0\0\x0e\x09\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\x02\x0c\0\0\0\x4c\0\0\0\0\0\0\
-\x01\x08\0\0\0\x40\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\x5f\0\0\0\x0b\0\0\0\x63\
-\0\0\0\x01\0\0\x0c\x0d\0\0\0\x09\x01\0\0\x05\0\0\x04\x20\0\0\0\x15\x01\0\0\x10\
-\0\0\0\0\0\0\0\x1b\x01\0\0\x12\0\0\0\x40\0\0\0\x1f\x01\0\0\x10\0\0\0\x80\0\0\0\
-\x2e\x01\0\0\x14\0\0\0\xa0\0\0\0\0\0\0\0\x15\0\0\0\xc0\0\0\0\x3a\x01\0\0\0\0\0\
-\x08\x11\0\0\0\x40\x01\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\x02\x13\
-\0\0\0\0\0\0\0\0\0\0\x0a\x1c\0\0\0\x4d\x01\0\0\x04\0\0\x06\x04\0\0\0\x5d\x01\0\
-\0\0\0\0\0\x6e\x01\0\0\x01\0\0\0\x80\x01\0\0\x02\0\0\0\x93\x01\0\0\x03\0\0\0\0\
-\0\0\0\x02\0\0\x05\x04\0\0\0\xa4\x01\0\0\x16\0\0\0\0\0\0\0\xab\x01\0\0\x16\0\0\
-\0\0\0\0\0\xb0\x01\0\0\0\0\0\x08\x02\0\0\0\xec\x01\0\0\0\0\0\x01\x01\0\0\0\x08\
-\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x17\0\0\0\x04\0\0\0\x04\0\0\0\xf1\x01\0\0\0\
-\0\0\x0e\x18\0\0\0\x01\0\0\0\xf9\x01\0\0\x01\0\0\x0f\x20\0\0\0\x0a\0\0\0\0\0\0\
-\0\x20\0\0\0\xff\x01\0\0\x01\0\0\x0f\x04\0\0\0\x19\0\0\0\0\0\0\0\x04\0\0\0\x07\
-\x02\0\0\0\0\0\x07\0\0\0\0\0\x69\x6e\x74\0\x5f\x5f\x41\x52\x52\x41\x59\x5f\x53\
-\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x74\x79\x70\x65\0\x6d\x61\x78\x5f\
-\x65\x6e\x74\x72\x69\x65\x73\0\x6b\x65\x79\x5f\x73\x69\x7a\x65\0\x76\x61\x6c\
-\x75\x65\x5f\x73\x69\x7a\x65\0\x68\x69\x64\x5f\x6a\x6d\x70\x5f\x74\x61\x62\x6c\
-\x65\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\x67\
-\0\x63\x74\x78\0\x68\x69\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\x66\x6d\
-\x6f\x64\x5f\x72\x65\x74\x2f\x5f\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\x74\x61\
-\x69\x6c\x5f\x63\x61\x6c\x6c\0\x2f\x68\x6f\x6d\x65\x2f\x62\x74\x69\x73\x73\x6f\
-\x69\x72\x2f\x53\x72\x63\x2f\x68\x69\x64\x2f\x64\x72\x69\x76\x65\x72\x73\x2f\
-\x68\x69\x64\x2f\x62\x70\x66\x2f\x65\x6e\x74\x72\x79\x70\x6f\x69\x6e\x74\x73\
-\x2f\x65\x6e\x74\x72\x79\x70\x6f\x69\x6e\x74\x73\x2e\x62\x70\x66\x2e\x63\0\x69\
-\x6e\x74\x20\x42\x50\x46\x5f\x50\x52\x4f\x47\x28\x68\x69\x64\x5f\x74\x61\x69\
-\x6c\x5f\x63\x61\x6c\x6c\x2c\x20\x73\x74\x72\x75\x63\x74\x20\x68\x69\x64\x5f\
-\x62\x70\x66\x5f\x63\x74\x78\x20\x2a\x68\x63\x74\x78\x29\0\x68\x69\x64\x5f\x62\
-\x70\x66\x5f\x63\x74\x78\0\x69\x6e\x64\x65\x78\0\x68\x69\x64\0\x61\x6c\x6c\x6f\
-\x63\x61\x74\x65\x64\x5f\x73\x69\x7a\x65\0\x72\x65\x70\x6f\x72\x74\x5f\x74\x79\
-\x70\x65\0\x5f\x5f\x75\x33\x32\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\
-\x74\0\x68\x69\x64\x5f\x72\x65\x70\x6f\x72\x74\x5f\x74\x79\x70\x65\0\x48\x49\
-\x44\x5f\x49\x4e\x50\x55\x54\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x4f\
-\x55\x54\x50\x55\x54\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x46\x45\x41\
-\x54\x55\x52\x45\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x52\x45\x50\x4f\
-\x52\x54\x5f\x54\x59\x50\x45\x53\0\x72\x65\x74\x76\x61\x6c\0\x73\x69\x7a\x65\0\
-\x5f\x5f\x73\x33\x32\0\x30\x3a\x30\0\x09\x62\x70\x66\x5f\x74\x61\x69\x6c\x5f\
-\x63\x61\x6c\x6c\x28\x63\x74\x78\x2c\x20\x26\x68\x69\x64\x5f\x6a\x6d\x70\x5f\
-\x74\x61\x62\x6c\x65\x2c\x20\x68\x63\x74\x78\x2d\x3e\x69\x6e\x64\x65\x78\x29\
-\x3b\0\x63\x68\x61\x72\0\x4c\x49\x43\x45\x4e\x53\x45\0\x2e\x6d\x61\x70\x73\0\
-\x6c\x69\x63\x65\x6e\x73\x65\0\x68\x69\x64\x5f\x64\x65\x76\x69\x63\x65\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8a\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\
-\0\0\0\x04\0\0\0\x04\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x69\x64\x5f\
-\x6a\x6d\x70\x5f\x74\x61\x62\x6c\x65\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\x47\x50\x4c\0\0\0\0\0\x79\x12\0\0\0\0\0\0\x61\x23\0\0\0\0\
-\0\0\x18\x52\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\0\0\0\x0c\0\0\0\xb7\0\0\0\0\0\0\0\
-\x95\0\0\0\0\0\0\0\0\0\0\0\x0e\0\0\0\0\0\0\0\x8e\0\0\0\xd3\0\0\0\x05\x48\0\0\
-\x01\0\0\0\x8e\0\0\0\xba\x01\0\0\x02\x50\0\0\x05\0\0\0\x8e\0\0\0\xd3\0\0\0\x05\
-\x48\0\0\x08\0\0\0\x0f\0\0\0\xb6\x01\0\0\0\0\0\0\x1a\0\0\0\x07\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x69\
-\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\0\0\0\0\0\0\x1a\0\0\0\0\0\0\0\
-\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\x01\0\
-\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x5f\
-\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\0\0\
-\0\0";
- opts.insns_sz = 1192;
- opts.insns = (void *)"\
-\xbf\x16\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x78\xff\xff\xff\xb7\x02\0\
-\0\x88\0\0\0\xb7\x03\0\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x05\0\x11\0\0\0\0\0\x61\
-\xa1\x78\xff\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x7c\xff\
-\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x80\xff\0\0\0\0\xd5\
-\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\
-\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\
-\xbf\x70\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\
-\0\0\0\0\0\xa8\x09\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\
-\0\0\0\0\0\0\0\xa4\x09\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\
-\0\0\0\0\0\0\0\0\0\x98\x09\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\
-\0\x05\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\x09\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\
-\0\0\x12\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x90\x09\0\0\xb7\x03\0\0\x1c\0\0\0\
-\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xd7\xff\0\0\0\0\x63\x7a\x78\
-\xff\0\0\0\0\x61\x60\x1c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\
-\0\0\xbc\x09\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\
-\0\0\0\xb0\x09\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\
-\0\xc5\x07\xca\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x71\0\0\0\0\
-\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf8\x09\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\
-\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x0a\0\0\x18\x61\0\0\
-\0\0\0\0\0\0\0\0\x88\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\
-\x38\x0a\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd0\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\
-\x60\0\0\0\0\0\0\0\0\0\0\x40\x0a\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xe0\x0a\0\0\
-\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x70\x0a\0\0\x18\x61\0\0\0\0\0\
-\0\0\0\0\0\0\x0b\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\x18\x61\0\0\0\0\0\0\0\0\0\0\xf8\x0a\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\0\
-\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x98\x0a\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\
-\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x9c\x0a\0\0\x63\x01\0\0\0\0\0\0\x79\x60\
-\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa0\x0a\0\0\x7b\x01\0\0\0\0\0\0\x61\
-\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc8\x0a\0\0\x63\x01\0\0\0\0\0\
-\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x10\x0b\0\0\xb7\x02\0\0\x14\0\0\0\xb7\x03\0\0\
-\x0c\0\0\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\
-\x91\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x80\x0a\0\0\x63\x70\x6c\0\0\0\0\0\
-\x77\x07\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\0\x18\x62\0\0\
-\0\0\0\0\0\0\0\0\x80\x0a\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\
-\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf0\x0a\0\0\x61\x01\0\0\0\0\0\0\xd5\
-\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\x7f\xff\0\0\
-\0\0\x63\x7a\x80\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\
-\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa0\x80\xff\0\0\0\0\x63\x06\x28\0\0\0\
-\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x18\0\0\0\
-\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0";
- err = bpf_load_and_run(&opts);
- if (err < 0)
- return err;
- return 0;
-}
-
-static inline struct entrypoints_bpf *
-entrypoints_bpf__open_and_load(void)
-{
- struct entrypoints_bpf *skel;
-
- skel = entrypoints_bpf__open();
- if (!skel)
- return NULL;
- if (entrypoints_bpf__load(skel)) {
- entrypoints_bpf__destroy(skel);
- return NULL;
- }
- return skel;
-}
-
-__attribute__((unused)) static void
-entrypoints_bpf__assert(struct entrypoints_bpf *s __attribute__((unused)))
-{
-#ifdef __cplusplus
-#define _Static_assert static_assert
-#endif
-#ifdef __cplusplus
-#undef _Static_assert
-#endif
-}
-
-#endif /* __ENTRYPOINTS_BPF_SKEL_H__ */
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index 10289f44d0cc..81073db6c617 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -10,6 +10,7 @@
#include <linux/bitops.h>
#include <linux/btf.h>
#include <linux/btf_ids.h>
+#include <linux/fdtable.h>
#include <linux/filter.h>
#include <linux/hid.h>
#include <linux/hid_bpf.h>
@@ -19,7 +20,6 @@
#include <linux/module.h>
#include <linux/workqueue.h>
#include "hid_bpf_dispatch.h"
-#include "entrypoints/entrypoints.lskel.h"
struct hid_bpf_ops *hid_bpf_ops;
EXPORT_SYMBOL(hid_bpf_ops);
@@ -203,25 +203,17 @@ int hid_bpf_reconnect(struct hid_device *hdev)
return 0;
}
-static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct bpf_prog *prog,
+static int do_hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
+ hid_bpf_cb_t prog_fn, struct bpf_prog *prog,
__u32 flags)
{
- int fd, err, prog_type;
+ int fd, err;
- prog_type = hid_bpf_get_prog_attach_type(prog);
- if (prog_type < 0)
- return prog_type;
+ err = hid_bpf_allocate_event_data(hdev);
+ if (err)
+ return err;
- if (prog_type >= HID_BPF_PROG_TYPE_MAX)
- return -EINVAL;
-
- if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) {
- err = hid_bpf_allocate_event_data(hdev);
- if (err)
- return err;
- }
-
- fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, prog, flags);
+ fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fn, prog, flags);
if (fd < 0)
return fd;
@@ -277,10 +269,12 @@ hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr
*/
/* called from syscall */
__bpf_kfunc int
-hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
+hid_bpf_attach_prog_impl(unsigned int hid_id, enum hid_bpf_prog_type prog_type,
+ hid_bpf_cb_t prog_fn__async, __u32 flags, void *prog__aux)
{
+ struct bpf_prog_aux *aux = (struct bpf_prog_aux *)prog__aux;
+ struct bpf_prog *prog = aux->prog;
struct hid_device *hdev;
- struct bpf_prog *prog;
struct device *dev;
int err, fd;
@@ -290,6 +284,9 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
if ((flags & ~HID_BPF_FLAG_MASK))
return -EINVAL;
+ if (prog_type < 0 || prog_type >= HID_BPF_PROG_TYPE_MAX)
+ return -EINVAL;
+
dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id);
if (!dev)
return -EINVAL;
@@ -300,13 +297,13 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
* take a ref on the prog itself, it will be released
* on errors or when it'll be detached
*/
- prog = bpf_prog_get(prog_fd);
+ prog = bpf_prog_inc_not_zero(prog);
if (IS_ERR(prog)) {
err = PTR_ERR(prog);
goto out_dev_put;
}
- fd = do_hid_bpf_attach_prog(hdev, prog_fd, prog, flags);
+ fd = do_hid_bpf_attach_prog(hdev, prog_type, prog_fn__async, prog, flags);
if (fd < 0) {
err = fd;
goto out_prog_put;
@@ -538,12 +535,9 @@ hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf
}
__bpf_kfunc_end_defs();
-/*
- * The following set contains all functions we agree BPF programs
- * can use.
- */
BTF_KFUNCS_START(hid_bpf_kfunc_ids)
BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL)
+BTF_ID_FLAGS(func, hid_bpf_attach_prog_impl, KF_SLEEPABLE)
BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)
BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE | KF_SLEEPABLE)
BTF_ID_FLAGS(func, hid_bpf_hw_request, KF_SLEEPABLE)
@@ -556,33 +550,6 @@ static const struct btf_kfunc_id_set hid_bpf_kfunc_set = {
.set = &hid_bpf_kfunc_ids,
};
-/* our HID-BPF entrypoints */
-BTF_SET8_START(hid_bpf_fmodret_ids)
-BTF_ID_FLAGS(func, hid_bpf_device_event)
-BTF_ID_FLAGS(func, hid_bpf_rdesc_fixup)
-BTF_ID_FLAGS(func, __hid_bpf_tail_call)
-BTF_SET8_END(hid_bpf_fmodret_ids)
-
-static const struct btf_kfunc_id_set hid_bpf_fmodret_set = {
- .owner = THIS_MODULE,
- .set = &hid_bpf_fmodret_ids,
-};
-
-/* for syscall HID-BPF */
-BTF_KFUNCS_START(hid_bpf_syscall_kfunc_ids)
-BTF_ID_FLAGS(func, hid_bpf_attach_prog)
-BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL)
-BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE)
-BTF_ID_FLAGS(func, hid_bpf_hw_request)
-BTF_ID_FLAGS(func, hid_bpf_hw_output_report)
-BTF_ID_FLAGS(func, hid_bpf_input_report)
-BTF_KFUNCS_END(hid_bpf_syscall_kfunc_ids)
-
-static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {
- .owner = THIS_MODULE,
- .set = &hid_bpf_syscall_kfunc_ids,
-};
-
int hid_bpf_connect_device(struct hid_device *hdev)
{
struct hid_bpf_prog_list *prog_list;
@@ -636,29 +603,9 @@ static int __init hid_bpf_init(void)
* will not be available, so nobody will be able to use the functionality.
*/
- err = register_btf_fmodret_id_set(&hid_bpf_fmodret_set);
- if (err) {
- pr_warn("error while registering fmodret entrypoints: %d", err);
- return 0;
- }
-
- err = hid_bpf_preload_skel();
- if (err) {
- pr_warn("error while preloading HID BPF dispatcher: %d", err);
- return 0;
- }
-
- /* register tracing kfuncs after we are sure we can load our preloaded bpf program */
- err = register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &hid_bpf_kfunc_set);
- if (err) {
- pr_warn("error while setting HID BPF tracing kfuncs: %d", err);
- return 0;
- }
-
- /* register syscalls after we are sure we can load our preloaded bpf program */
- err = register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &hid_bpf_syscall_kfunc_set);
+ err = register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &hid_bpf_kfunc_set);
if (err) {
- pr_warn("error while setting HID BPF syscall kfuncs: %d", err);
+ pr_warn("error while setting HID BPF kfuncs: %d", err);
return 0;
}
@@ -670,7 +617,6 @@ static void __exit hid_bpf_exit(void)
/* HID depends on us, so if we hit that code, we are guaranteed that hid
* has been removed and thus we do not need to clear the HID devices
*/
- hid_bpf_free_links_and_skel();
}
late_initcall(hid_bpf_init);
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.h b/drivers/hid/bpf/hid_bpf_dispatch.h
index fbe0639d09f2..60455a2af216 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.h
+++ b/drivers/hid/bpf/hid_bpf_dispatch.h
@@ -10,10 +10,10 @@ struct hid_bpf_ctx_kern {
u8 *data;
};
-int hid_bpf_preload_skel(void);
-void hid_bpf_free_links_and_skel(void);
-int hid_bpf_get_prog_attach_type(struct bpf_prog *prog);
-int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, int prog_fd,
+typedef int (*hid_bpf_cb_t)(struct hid_bpf_ctx *hid_ctx);
+
+int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
+ int (prog_fn__async)(struct hid_bpf_ctx *hid_ctx),
struct bpf_prog *prog, __u32 flags);
void __hid_bpf_destroy_device(struct hid_device *hdev);
int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c
index aa8e1c79cdf5..8d53d41b599b 100644
--- a/drivers/hid/bpf/hid_bpf_jmp_table.c
+++ b/drivers/hid/bpf/hid_bpf_jmp_table.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/workqueue.h>
#include "hid_bpf_dispatch.h"
-#include "entrypoints/entrypoints.lskel.h"
#define HID_BPF_MAX_PROGS 1024 /* keep this in sync with preloaded bpf,
* needs to be a power of 2 as we use it as
@@ -37,11 +36,15 @@ struct hid_bpf_prog_entry {
u16 idx;
};
+struct hid_bpf_prog_cb {
+ struct bpf_prog *prog;
+ void *fn;
+};
+
struct hid_bpf_jmp_table {
- struct bpf_map *map;
struct hid_bpf_prog_entry entries[HID_BPF_MAX_PROGS]; /* compacted list, circular buffer */
int tail, head;
- struct bpf_prog *progs[HID_BPF_MAX_PROGS]; /* idx -> progs mapping */
+ struct hid_bpf_prog_cb prog_cbs[HID_BPF_MAX_PROGS]; /* idx -> progs mapping */
unsigned long enabled[BITS_TO_LONGS(HID_BPF_MAX_PROGS)];
};
@@ -56,10 +59,6 @@ static void hid_bpf_release_progs(struct work_struct *work);
static DECLARE_WORK(release_work, hid_bpf_release_progs);
-BTF_ID_LIST(hid_bpf_btf_ids)
-BTF_ID(func, hid_bpf_device_event) /* HID_BPF_PROG_TYPE_DEVICE_EVENT */
-BTF_ID(func, hid_bpf_rdesc_fixup) /* HID_BPF_PROG_TYPE_RDESC_FIXUP */
-
static int hid_bpf_max_programs(enum hid_bpf_prog_type type)
{
switch (type) {
@@ -99,15 +98,11 @@ static int hid_bpf_program_count(struct hid_device *hdev,
return n;
}
-__weak noinline int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx)
-{
- return 0;
-}
-
int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
struct hid_bpf_ctx_kern *ctx_kern)
{
struct hid_bpf_prog_list *prog_list;
+ bpf_callback_t prog_fn;
int i, idx, err = 0;
rcu_read_lock();
@@ -123,7 +118,10 @@ int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
continue;
ctx_kern->ctx.index = idx;
- err = __hid_bpf_tail_call(&ctx_kern->ctx);
+ prog_fn = jmp_table.prog_cbs[idx].fn;
+ migrate_disable();
+ err = prog_fn((u64)(long)&ctx_kern->ctx, 0, 0, 0, 0);
+ migrate_enable();
if (err < 0)
break;
if (err)
@@ -187,25 +185,18 @@ static int hid_bpf_populate_hdev(struct hid_device *hdev, enum hid_bpf_prog_type
return 0;
}
-static void __hid_bpf_do_release_prog(int map_fd, unsigned int idx)
+static void __hid_bpf_do_release_prog(unsigned int idx)
{
- skel_map_delete_elem(map_fd, &idx);
- jmp_table.progs[idx] = NULL;
+ bpf_prog_put(jmp_table.prog_cbs[idx].prog);
+ jmp_table.prog_cbs[idx].prog = NULL;
+ jmp_table.prog_cbs[idx].fn = NULL;
}
static void hid_bpf_release_progs(struct work_struct *work)
{
- int i, j, n, map_fd = -1;
+ int i, j, n;
bool hdev_destroyed;
- if (!jmp_table.map)
- return;
-
- /* retrieve a fd of our prog_array map in BPF */
- map_fd = skel_map_get_fd_by_id(jmp_table.map->id);
- if (map_fd < 0)
- return;
-
mutex_lock(&hid_bpf_attach_lock); /* protects against attaching new programs */
/* detach unused progs from HID devices */
@@ -264,7 +255,7 @@ static void hid_bpf_release_progs(struct work_struct *work)
continue;
if (entry->prog)
- __hid_bpf_do_release_prog(map_fd, entry->idx);
+ __hid_bpf_do_release_prog(entry->idx);
}
/* compact the entry list */
@@ -282,46 +273,22 @@ static void hid_bpf_release_progs(struct work_struct *work)
jmp_table.head = n;
mutex_unlock(&hid_bpf_attach_lock);
-
- if (map_fd >= 0)
- close_fd(map_fd);
-}
-
-static void hid_bpf_release_prog_at(int idx)
-{
- int map_fd = -1;
-
- /* retrieve a fd of our prog_array map in BPF */
- map_fd = skel_map_get_fd_by_id(jmp_table.map->id);
- if (map_fd < 0)
- return;
-
- __hid_bpf_do_release_prog(map_fd, idx);
-
- close(map_fd);
}
/*
- * Insert the given BPF program represented by its fd in the jmp table.
+ * Insert the given BPF program represented by its function call in the jmp table.
* Returns the index in the jump table or a negative error.
*/
-static int hid_bpf_insert_prog(int prog_fd, struct bpf_prog *prog)
+static int hid_bpf_insert_prog(struct bpf_prog *prog, hid_bpf_cb_t prog_fn)
{
- int i, index = -1, map_fd = -1, err = -EINVAL;
-
- /* retrieve a fd of our prog_array map in BPF */
- map_fd = skel_map_get_fd_by_id(jmp_table.map->id);
-
- if (map_fd < 0) {
- err = -EINVAL;
- goto out;
- }
+ int i, index = -1, err = -EINVAL;
/* find the first available index in the jmp_table */
for (i = 0; i < HID_BPF_MAX_PROGS; i++) {
- if (!jmp_table.progs[i] && index < 0) {
+ if (!jmp_table.prog_cbs[i].prog && index < 0) {
/* mark the index as used */
- jmp_table.progs[i] = prog;
+ jmp_table.prog_cbs[i].fn = prog_fn;
+ jmp_table.prog_cbs[i].prog = prog;
index = i;
__set_bit(i, jmp_table.enabled);
}
@@ -331,37 +298,15 @@ static int hid_bpf_insert_prog(int prog_fd, struct bpf_prog *prog)
goto out;
}
- /* insert the program in the jump table */
- err = skel_map_update_elem(map_fd, &index, &prog_fd, 0);
- if (err)
- goto out;
-
/* return the index */
err = index;
out:
if (err < 0)
- __hid_bpf_do_release_prog(map_fd, index);
- if (map_fd >= 0)
- close_fd(map_fd);
+ __hid_bpf_do_release_prog(index);
return err;
}
-int hid_bpf_get_prog_attach_type(struct bpf_prog *prog)
-{
- int prog_type = HID_BPF_PROG_TYPE_UNDEF;
- int i;
-
- for (i = 0; i < HID_BPF_PROG_TYPE_MAX; i++) {
- if (hid_bpf_btf_ids[i] == prog->aux->attach_btf_id) {
- prog_type = i;
- break;
- }
- }
-
- return prog_type;
-}
-
static void hid_bpf_link_release(struct bpf_link *link)
{
struct hid_bpf_link *hid_link =
@@ -395,7 +340,7 @@ static const struct bpf_link_ops hid_bpf_link_lops = {
/* called from syscall */
noinline int
__hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
- int prog_fd, struct bpf_prog *prog, __u32 flags)
+ hid_bpf_cb_t prog_fn, struct bpf_prog *prog, __u32 flags)
{
struct bpf_link_primer link_primer;
struct hid_bpf_link *link;
@@ -425,7 +370,7 @@ __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
goto err_unlock;
}
- prog_table_idx = hid_bpf_insert_prog(prog_fd, prog);
+ prog_table_idx = hid_bpf_insert_prog(prog, prog_fn);
/* if the jmp table is full, abort */
if (prog_table_idx < 0) {
err = prog_table_idx;
@@ -451,7 +396,7 @@ __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
/* finally store the index in the device list */
err = hid_bpf_populate_hdev(hdev, prog_type);
if (err) {
- hid_bpf_release_prog_at(prog_table_idx);
+ __hid_bpf_do_release_prog(prog_table_idx);
goto err_unlock;
}
@@ -498,68 +443,3 @@ void __hid_bpf_destroy_device(struct hid_device *hdev)
/* schedule release of all detached progs */
schedule_work(&release_work);
}
-
-#define HID_BPF_PROGS_COUNT 1
-
-static struct bpf_link *links[HID_BPF_PROGS_COUNT];
-static struct entrypoints_bpf *skel;
-
-void hid_bpf_free_links_and_skel(void)
-{
- int i;
-
- /* the following is enough to release all programs attached to hid */
- if (jmp_table.map)
- bpf_map_put_with_uref(jmp_table.map);
-
- for (i = 0; i < ARRAY_SIZE(links); i++) {
- if (!IS_ERR_OR_NULL(links[i]))
- bpf_link_put(links[i]);
- }
- entrypoints_bpf__destroy(skel);
-}
-
-#define ATTACH_AND_STORE_LINK(__name) do { \
- err = entrypoints_bpf__##__name##__attach(skel); \
- if (err) \
- goto out; \
- \
- links[idx] = bpf_link_get_from_fd(skel->links.__name##_fd); \
- if (IS_ERR(links[idx])) { \
- err = PTR_ERR(links[idx]); \
- goto out; \
- } \
- \
- /* Avoid taking over stdin/stdout/stderr of init process. Zeroing out \
- * makes skel_closenz() a no-op later in iterators_bpf__destroy(). \
- */ \
- close_fd(skel->links.__name##_fd); \
- skel->links.__name##_fd = 0; \
- idx++; \
-} while (0)
-
-int hid_bpf_preload_skel(void)
-{
- int err, idx = 0;
-
- skel = entrypoints_bpf__open();
- if (!skel)
- return -ENOMEM;
-
- err = entrypoints_bpf__load(skel);
- if (err)
- goto out;
-
- jmp_table.map = bpf_map_get_with_uref(skel->maps.hid_jmp_table.map_fd);
- if (IS_ERR(jmp_table.map)) {
- err = PTR_ERR(jmp_table.map);
- goto out;
- }
-
- ATTACH_AND_STORE_LINK(hid_tail_call);
-
- return 0;
-out:
- hid_bpf_free_links_and_skel();
- return err;
-}
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
index 17b08f500098..99ebe7bbb02a 100644
--- a/include/linux/hid_bpf.h
+++ b/include/linux/hid_bpf.h
@@ -81,9 +81,6 @@ int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx);
* Below is HID internal
*/
-/* internal function to call eBPF programs, not to be used by anybody */
-int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx);
-
#define HID_BPF_MAX_PROGS_PER_DEV 64
#define HID_BPF_FLAG_MASK (((HID_BPF_FLAG_MAX - 1) << 1) - 1)
--
2.44.0
Now each program needs to ship its own attach prog. To make things
simpler we define __HID_BPF_PROG() and the various sub-macros per
hid-bpf type of program.
Signed-off-by: Benjamin Tissoires <[email protected]>
---
tools/testing/selftests/hid/hid_bpf.c | 6 +---
tools/testing/selftests/hid/progs/hid.c | 40 +++++-----------------
.../testing/selftests/hid/progs/hid_bpf_helpers.h | 29 +++++++++++++++-
3 files changed, 37 insertions(+), 38 deletions(-)
diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c
index f825623e3edc..7fed9f599b62 100644
--- a/tools/testing/selftests/hid/hid_bpf.c
+++ b/tools/testing/selftests/hid/hid_bpf.c
@@ -90,7 +90,6 @@ static unsigned char rdesc[] = {
static __u8 feature_data[] = { 1, 2 };
struct attach_prog_args {
- int prog_fd;
unsigned int hid;
int retval;
int insert_head;
@@ -556,9 +555,6 @@ static void load_programs(const struct test_program programs[],
err = hid__load(self->skel);
ASSERT_OK(err) TH_LOG("hid_skel_load failed: %d", err);
- attach_fd = bpf_program__fd(self->skel->progs.attach_prog);
- ASSERT_GE(attach_fd, 0) TH_LOG("locate attach_prog: %d", attach_fd);
-
for (int i = 0; i < progs_count; i++) {
struct bpf_program *prog;
@@ -566,7 +562,7 @@ static void load_programs(const struct test_program programs[],
programs[i].name);
ASSERT_OK_PTR(prog) TH_LOG("can not find program by name '%s'", programs[i].name);
- args.prog_fd = bpf_program__fd(prog);
+ attach_fd = bpf_program__fd(prog);
args.hid = self->hid_id;
args.insert_head = programs[i].insert_head;
err = bpf_prog_test_run_opts(attach_fd, &tattr);
diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c
index f67d35def142..b721d1256836 100644
--- a/tools/testing/selftests/hid/progs/hid.c
+++ b/tools/testing/selftests/hid/progs/hid.c
@@ -4,18 +4,10 @@
char _license[] SEC("license") = "GPL";
-struct attach_prog_args {
- int prog_fd;
- unsigned int hid;
- int retval;
- int insert_head;
-};
-
__u64 callback_check = 52;
__u64 callback2_check = 52;
-SEC("?fmod_ret/hid_bpf_device_event")
-int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx)
+HID_BPF_DEVICE_EVENT(hid_first_event, struct hid_bpf_ctx *hid_ctx)
{
__u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */);
@@ -29,8 +21,7 @@ int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx)
return hid_ctx->size;
}
-SEC("?fmod_ret/hid_bpf_device_event")
-int BPF_PROG(hid_second_event, struct hid_bpf_ctx *hid_ctx)
+HID_BPF_DEVICE_EVENT(hid_second_event, struct hid_bpf_ctx *hid_ctx)
{
__u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
@@ -42,8 +33,7 @@ int BPF_PROG(hid_second_event, struct hid_bpf_ctx *hid_ctx)
return hid_ctx->size;
}
-SEC("?fmod_ret/hid_bpf_device_event")
-int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx)
+HID_BPF_DEVICE_EVENT(hid_change_report_id, struct hid_bpf_ctx *hid_ctx)
{
__u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */);
@@ -55,16 +45,6 @@ int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx)
return 9;
}
-SEC("syscall")
-int attach_prog(struct attach_prog_args *ctx)
-{
- ctx->retval = hid_bpf_attach_prog(ctx->hid,
- ctx->prog_fd,
- ctx->insert_head ? HID_BPF_FLAG_INSERT_HEAD :
- HID_BPF_FLAG_NONE);
- return 0;
-}
-
struct hid_hw_request_syscall_args {
/* data needs to come at offset 0 so we can use it in calls */
__u8 data[10];
@@ -181,13 +161,12 @@ static const __u8 rdesc[] = {
0xc0, /* END_COLLECTION */
};
-SEC("?fmod_ret/hid_bpf_rdesc_fixup")
-int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx)
+HID_BPF_RDESC_FIXUP(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx)
{
__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4096 /* size */);
if (!data)
- return 0; /* EPERM check */
+ return -22; /* EPERM check */
callback2_check = data[4];
@@ -200,8 +179,7 @@ int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx)
return sizeof(rdesc) + 73;
}
-SEC("?fmod_ret/hid_bpf_device_event")
-int BPF_PROG(hid_test_insert1, struct hid_bpf_ctx *hid_ctx)
+HID_BPF_DEVICE_EVENT(hid_test_insert1, struct hid_bpf_ctx *hid_ctx)
{
__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
@@ -217,8 +195,7 @@ int BPF_PROG(hid_test_insert1, struct hid_bpf_ctx *hid_ctx)
return 0;
}
-SEC("?fmod_ret/hid_bpf_device_event")
-int BPF_PROG(hid_test_insert2, struct hid_bpf_ctx *hid_ctx)
+HID_BPF_DEVICE_EVENT(hid_test_insert2, struct hid_bpf_ctx *hid_ctx)
{
__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
@@ -234,8 +211,7 @@ int BPF_PROG(hid_test_insert2, struct hid_bpf_ctx *hid_ctx)
return 0;
}
-SEC("?fmod_ret/hid_bpf_device_event")
-int BPF_PROG(hid_test_insert3, struct hid_bpf_ctx *hid_ctx)
+HID_BPF_DEVICE_EVENT(hid_test_insert3, struct hid_bpf_ctx *hid_ctx)
{
__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
index 9cd56821d0f1..9826880e88d1 100644
--- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
+++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
@@ -82,11 +82,20 @@ enum hid_bpf_attach_flags {
HID_BPF_FLAG_MAX,
};
+struct attach_prog_args {
+ unsigned int hid;
+ int retval;
+ int insert_head;
+};
+
/* following are kfuncs exported by HID for HID-BPF */
extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
unsigned int offset,
const size_t __sz) __ksym;
-extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __ksym;
+extern int hid_bpf_attach_prog_impl(unsigned int hid_id,
+ enum hid_bpf_prog_type type,
+ int (prog_fn)(struct hid_bpf_ctx *hid_ctx),
+ u32 flags, void *aux) __ksym;
extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym;
extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym;
extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
@@ -101,4 +110,22 @@ extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
__u8 *data,
size_t buf__sz) __ksym;
+#define __HID_BPF_PROG(type, name, arg) \
+ static int __##name(arg); \
+ SEC("syscall") \
+ int name(struct attach_prog_args *ctx) \
+ { \
+ ctx->retval = hid_bpf_attach_prog_impl(ctx->hid, \
+ type, \
+ __##name, \
+ ctx->insert_head ? HID_BPF_FLAG_INSERT_HEAD : \
+ HID_BPF_FLAG_NONE, \
+ NULL); \
+ return 0; \
+ } \
+ static int __##name(arg)
+
+#define HID_BPF_DEVICE_EVENT(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_DEVICE_EVENT, name, arg)
+#define HID_BPF_RDESC_FIXUP(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_RDESC_FIXUP, name, arg)
+
#endif /* __HID_BPF_HELPERS_H */
--
2.44.0
Signed-off-by: Benjamin Tissoires <[email protected]>
---
drivers/hid/bpf/hid_bpf_dispatch.c | 111 ++++++++++++++++++++++--------------
drivers/hid/bpf/hid_bpf_dispatch.h | 4 +-
drivers/hid/bpf/hid_bpf_jmp_table.c | 30 +++++++---
3 files changed, 92 insertions(+), 53 deletions(-)
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index 81073db6c617..7ede657f459b 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -70,7 +70,7 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
memset(ctx_kern.data, 0, hdev->bpf.allocated_data);
memcpy(ctx_kern.data, data, *size);
- ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern);
+ ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern, false);
if (ret < 0)
return ERR_PTR(ret);
@@ -122,7 +122,7 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s
memcpy(ctx_kern.data, rdesc, min_t(unsigned int, *size, HID_MAX_DESCRIPTOR_SIZE));
- ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RDESC_FIXUP, &ctx_kern);
+ ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RDESC_FIXUP, &ctx_kern, false);
if (ret < 0)
goto ignore_bpf;
@@ -205,7 +205,7 @@ int hid_bpf_reconnect(struct hid_device *hdev)
static int do_hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
hid_bpf_cb_t prog_fn, struct bpf_prog *prog,
- __u32 flags)
+ __u32 flags, bool sleepable)
{
int fd, err;
@@ -213,7 +213,7 @@ static int do_hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_typ
if (err)
return err;
- fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fn, prog, flags);
+ fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fn, prog, flags, sleepable);
if (fd < 0)
return fd;
@@ -228,6 +228,56 @@ static int do_hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_typ
return fd;
}
+static int
+hid_bpf_attach_prog(unsigned int hid_id, enum hid_bpf_prog_type prog_type,
+ hid_bpf_cb_t prog_fn, __u32 flags, void *prog__aux,
+ bool sleepable)
+{
+ struct bpf_prog_aux *aux = (struct bpf_prog_aux *)prog__aux;
+ struct bpf_prog *prog = aux->prog;
+ struct hid_device *hdev;
+ struct device *dev;
+ int err, fd;
+
+ if (!hid_bpf_ops)
+ return -EINVAL;
+
+ if ((flags & ~HID_BPF_FLAG_MASK))
+ return -EINVAL;
+
+ if (prog_type < 0 || prog_type >= HID_BPF_PROG_TYPE_MAX)
+ return -EINVAL;
+
+ dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id);
+ if (!dev)
+ return -EINVAL;
+
+ hdev = to_hid_device(dev);
+
+ /*
+ * take a ref on the prog itself, it will be released
+ * on errors or when it'll be detached
+ */
+ prog = bpf_prog_inc_not_zero(prog);
+ if (IS_ERR(prog)) {
+ err = PTR_ERR(prog);
+ goto out_dev_put;
+ }
+
+ fd = do_hid_bpf_attach_prog(hdev, prog_type, prog_fn, prog, flags, sleepable);
+ if (fd < 0) {
+ err = fd;
+ goto out_prog_put;
+ }
+
+ return fd;
+
+ out_prog_put:
+ bpf_prog_put(prog);
+ out_dev_put:
+ put_device(dev);
+ return err;
+}
/* Disables missing prototype warnings */
__bpf_kfunc_start_defs();
@@ -272,50 +322,22 @@ __bpf_kfunc int
hid_bpf_attach_prog_impl(unsigned int hid_id, enum hid_bpf_prog_type prog_type,
hid_bpf_cb_t prog_fn__async, __u32 flags, void *prog__aux)
{
- struct bpf_prog_aux *aux = (struct bpf_prog_aux *)prog__aux;
- struct bpf_prog *prog = aux->prog;
- struct hid_device *hdev;
- struct device *dev;
- int err, fd;
-
- if (!hid_bpf_ops)
- return -EINVAL;
-
- if ((flags & ~HID_BPF_FLAG_MASK))
- return -EINVAL;
-
- if (prog_type < 0 || prog_type >= HID_BPF_PROG_TYPE_MAX)
- return -EINVAL;
+ return hid_bpf_attach_prog(hid_id, prog_type, prog_fn__async, flags, prog__aux, false);
+}
- dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id);
- if (!dev)
+__bpf_kfunc int
+hid_bpf_attach_sleepable_prog_impl(unsigned int hid_id, enum hid_bpf_prog_type prog_type,
+ hid_bpf_cb_t prog_fn__s_async, __u32 flags, void *prog__aux)
+{
+ switch (prog_type) {
+ case HID_BPF_PROG_TYPE_RAW_REQUEST:
+ /* OK */
+ break;
+ default:
return -EINVAL;
-
- hdev = to_hid_device(dev);
-
- /*
- * take a ref on the prog itself, it will be released
- * on errors or when it'll be detached
- */
- prog = bpf_prog_inc_not_zero(prog);
- if (IS_ERR(prog)) {
- err = PTR_ERR(prog);
- goto out_dev_put;
- }
-
- fd = do_hid_bpf_attach_prog(hdev, prog_type, prog_fn__async, prog, flags);
- if (fd < 0) {
- err = fd;
- goto out_prog_put;
}
- return fd;
-
- out_prog_put:
- bpf_prog_put(prog);
- out_dev_put:
- put_device(dev);
- return err;
+ return hid_bpf_attach_prog(hid_id, prog_type, prog_fn__s_async, flags, prog__aux, true);
}
/**
@@ -538,6 +560,7 @@ __bpf_kfunc_end_defs();
BTF_KFUNCS_START(hid_bpf_kfunc_ids)
BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL)
BTF_ID_FLAGS(func, hid_bpf_attach_prog_impl, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_attach_sleepable_prog_impl, KF_SLEEPABLE)
BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)
BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE | KF_SLEEPABLE)
BTF_ID_FLAGS(func, hid_bpf_hw_request, KF_SLEEPABLE)
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.h b/drivers/hid/bpf/hid_bpf_dispatch.h
index 60455a2af216..f9833603e49f 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.h
+++ b/drivers/hid/bpf/hid_bpf_dispatch.h
@@ -14,10 +14,10 @@ typedef int (*hid_bpf_cb_t)(struct hid_bpf_ctx *hid_ctx);
int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
int (prog_fn__async)(struct hid_bpf_ctx *hid_ctx),
- struct bpf_prog *prog, __u32 flags);
+ struct bpf_prog *prog, __u32 flags, bool sleepable);
void __hid_bpf_destroy_device(struct hid_device *hdev);
int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
- struct hid_bpf_ctx_kern *ctx_kern);
+ struct hid_bpf_ctx_kern *ctx_kern, bool is_sleepable);
int hid_bpf_reconnect(struct hid_device *hdev);
struct bpf_prog;
diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c
index 8d53d41b599b..4cceff354962 100644
--- a/drivers/hid/bpf/hid_bpf_jmp_table.c
+++ b/drivers/hid/bpf/hid_bpf_jmp_table.c
@@ -39,6 +39,7 @@ struct hid_bpf_prog_entry {
struct hid_bpf_prog_cb {
struct bpf_prog *prog;
void *fn;
+ bool sleepable;
};
struct hid_bpf_jmp_table {
@@ -99,14 +100,20 @@ static int hid_bpf_program_count(struct hid_device *hdev,
}
int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
- struct hid_bpf_ctx_kern *ctx_kern)
+ struct hid_bpf_ctx_kern *ctx_kern, bool is_sleepable)
{
struct hid_bpf_prog_list *prog_list;
bpf_callback_t prog_fn;
int i, idx, err = 0;
- rcu_read_lock();
- prog_list = rcu_dereference(hdev->bpf.progs[type]);
+ if (is_sleepable) {
+ prog_list = READ_ONCE(hdev->bpf.progs[type]);
+ rcu_read_lock_trace();
+ might_fault();
+ } else {
+ rcu_read_lock();
+ prog_list = rcu_dereference(hdev->bpf.progs[type]);
+ }
if (!prog_list)
goto out_unlock;
@@ -117,6 +124,10 @@ int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
if (!test_bit(idx, jmp_table.enabled))
continue;
+ /* prevent a sleepable program to be run in a non sleepable context */
+ if (!is_sleepable && jmp_table.prog_cbs[idx].sleepable)
+ continue;
+
ctx_kern->ctx.index = idx;
prog_fn = jmp_table.prog_cbs[idx].fn;
migrate_disable();
@@ -129,7 +140,10 @@ int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
}
out_unlock:
- rcu_read_unlock();
+ if (is_sleepable)
+ rcu_read_unlock_trace();
+ else
+ rcu_read_unlock();
return err;
}
@@ -279,7 +293,7 @@ static void hid_bpf_release_progs(struct work_struct *work)
* Insert the given BPF program represented by its function call in the jmp table.
* Returns the index in the jump table or a negative error.
*/
-static int hid_bpf_insert_prog(struct bpf_prog *prog, hid_bpf_cb_t prog_fn)
+static int hid_bpf_insert_prog(struct bpf_prog *prog, hid_bpf_cb_t prog_fn, bool sleepable)
{
int i, index = -1, err = -EINVAL;
@@ -289,6 +303,7 @@ static int hid_bpf_insert_prog(struct bpf_prog *prog, hid_bpf_cb_t prog_fn)
/* mark the index as used */
jmp_table.prog_cbs[i].fn = prog_fn;
jmp_table.prog_cbs[i].prog = prog;
+ jmp_table.prog_cbs[i].sleepable = sleepable;
index = i;
__set_bit(i, jmp_table.enabled);
}
@@ -340,7 +355,8 @@ static const struct bpf_link_ops hid_bpf_link_lops = {
/* called from syscall */
noinline int
__hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
- hid_bpf_cb_t prog_fn, struct bpf_prog *prog, __u32 flags)
+ hid_bpf_cb_t prog_fn, struct bpf_prog *prog, __u32 flags,
+ bool sleepable)
{
struct bpf_link_primer link_primer;
struct hid_bpf_link *link;
@@ -370,7 +386,7 @@ __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
goto err_unlock;
}
- prog_table_idx = hid_bpf_insert_prog(prog, prog_fn);
+ prog_table_idx = hid_bpf_insert_prog(prog, prog_fn, sleepable);
/* if the jmp table is full, abort */
if (prog_table_idx < 0) {
err = prog_table_idx;
--
2.44.0
---
drivers/hid/bpf/hid_bpf_dispatch.c | 51 +++++++++++++++++++++++++++++++++++++
drivers/hid/bpf/hid_bpf_jmp_table.c | 1 +
drivers/hid/hid-core.c | 8 +++++-
include/linux/hid_bpf.h | 14 ++++++++++
4 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index 55c9e74c2465..7aeab3f9f2c7 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -45,6 +45,11 @@ __weak noinline int hid_bpf_device_event(struct hid_bpf_ctx *ctx)
return 0;
}
+__weak noinline int hid_bpf_raw_request(struct hid_bpf_ctx *ctx)
+{
+ return 0;
+}
+
u8 *
dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data,
u32 *size, int interrupt, u64 source)
@@ -71,6 +76,9 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
memset(ctx_kern.data, 0, hdev->bpf.allocated_data);
memcpy(ctx_kern.data, data, *size);
+ if (*size)
+ ctx_kern.ctx.reportnum = data[0];
+
ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern, false);
if (ret < 0)
return ERR_PTR(ret);
@@ -86,6 +94,49 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
}
EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event);
+u8 *
+dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
+ unsigned char reportnum, u8 *buf,
+ u32 *size, enum hid_report_type rtype,
+ enum hid_class_request reqtype,
+ u64 source)
+{
+ struct hid_bpf_ctx_kern ctx_kern = {
+ .ctx = {
+ .hid = hdev,
+ .report_type = rtype,
+ .reqtype = reqtype,
+ .allocated_size = *size,
+ .size = *size,
+ .source = source,
+ .reportnum = reportnum,
+ },
+ .data = buf,
+ };
+ int ret;
+
+ if (rtype >= HID_REPORT_TYPES)
+ return ERR_PTR(-EINVAL);
+
+ /* no program has been attached yet */
+ // if (!hdev->bpf.device_data)
+ // return buf;
+
+ ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RAW_REQUEST, &ctx_kern, true);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ if (ret) {
+ if (ret > ctx_kern.ctx.allocated_size)
+ return ERR_PTR(-EINVAL);
+
+ *size = ret;
+ }
+
+ return ctx_kern.data;
+}
+EXPORT_SYMBOL_GPL(dispatch_hid_bpf_raw_requests);
+
/**
* hid_bpf_rdesc_fixup - Called when the probe function parses the report
* descriptor of the HID device
diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c
index 4cceff354962..e183dc2835c7 100644
--- a/drivers/hid/bpf/hid_bpf_jmp_table.c
+++ b/drivers/hid/bpf/hid_bpf_jmp_table.c
@@ -64,6 +64,7 @@ static int hid_bpf_max_programs(enum hid_bpf_prog_type type)
{
switch (type) {
case HID_BPF_PROG_TYPE_DEVICE_EVENT:
+ case HID_BPF_PROG_TYPE_RAW_REQUEST:
return HID_BPF_MAX_PROGS_PER_DEV;
case HID_BPF_PROG_TYPE_RDESC_FIXUP:
return 1;
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index b8414ce62e7b..7d468f6dbefe 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2407,6 +2407,7 @@ int __hid_hw_raw_request(struct hid_device *hdev,
__u64 source)
{
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
+ u32 size = (u32)len; /* max_buffer_size is 16 KB */
if (hdev->ll_driver->max_buffer_size)
max_buffer_size = hdev->ll_driver->max_buffer_size;
@@ -2414,7 +2415,12 @@ int __hid_hw_raw_request(struct hid_device *hdev,
if (len < 1 || len > max_buffer_size || !buf)
return -EINVAL;
- return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
+ buf = dispatch_hid_bpf_raw_requests(hdev, reportnum, buf, &size, rtype,
+ reqtype, source);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ return hdev->ll_driver->raw_request(hdev, reportnum, buf, size,
rtype, reqtype);
}
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
index 6bcaf19f1cc2..1cd36bfdd608 100644
--- a/include/linux/hid_bpf.h
+++ b/include/linux/hid_bpf.h
@@ -52,10 +52,12 @@ struct hid_bpf_ctx {
__u64 source;
const struct hid_device *hid;
enum hid_report_type report_type;
+ enum hid_class_request reqtype; /* for HID_BPF_PROG_TYPE_RAW_REQUEST */
union {
__s32 retval;
__s32 size;
};
+ __u8 reportnum;
};
/**
@@ -77,6 +79,7 @@ enum hid_bpf_attach_flags {
/* Following functions are tracepoints that BPF programs can attach to */
int hid_bpf_device_event(struct hid_bpf_ctx *ctx);
int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx);
+int hid_bpf_raw_request(struct hid_bpf_ctx *ctx);
/*
* Below is HID internal
@@ -90,6 +93,7 @@ enum hid_bpf_prog_type {
HID_BPF_PROG_TYPE_UNDEF = -1,
HID_BPF_PROG_TYPE_DEVICE_EVENT, /* an event is emitted from the device */
HID_BPF_PROG_TYPE_RDESC_FIXUP,
+ HID_BPF_PROG_TYPE_RAW_REQUEST,
HID_BPF_PROG_TYPE_MAX,
};
@@ -140,6 +144,11 @@ struct hid_bpf_link {
#ifdef CONFIG_HID_BPF
u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
u32 *size, int interrupt, u64 source);
+u8 *dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
+ unsigned char reportnum, __u8 *buf,
+ u32 *size, enum hid_report_type rtype,
+ enum hid_class_request reqtype,
+ __u64 source);
int hid_bpf_connect_device(struct hid_device *hdev);
void hid_bpf_disconnect_device(struct hid_device *hdev);
void hid_bpf_destroy_device(struct hid_device *hid);
@@ -149,6 +158,11 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
u8 *data, u32 *size, int interrupt,
u64 source) { return data; }
+static inline u8 *dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
+ unsigned char reportnum, u8 *buf,
+ u32 *size, enum hid_report_type rtype,
+ enum hid_class_request reqtype,
+ u64 source) { return buf; }
static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
--
2.44.0
Signed-off-by: Benjamin Tissoires <[email protected]>
---
tools/testing/selftests/hid/hid_bpf.c | 55 ++++++++++++++++++++++
tools/testing/selftests/hid/progs/hid.c | 51 ++++++++++++++++++++
.../testing/selftests/hid/progs/hid_bpf_helpers.h | 39 +++++++++------
3 files changed, 130 insertions(+), 15 deletions(-)
diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c
index 7fed9f599b62..522fc32a5c38 100644
--- a/tools/testing/selftests/hid/hid_bpf.c
+++ b/tools/testing/selftests/hid/hid_bpf.c
@@ -469,6 +469,8 @@ static void detach_bpf(FIXTURE_DATA(hid_bpf) * self)
close(self->hidraw_fd);
self->hidraw_fd = 0;
+ // hid__detach(self->skel);
+
for (i = 0; i < ARRAY_SIZE(self->hid_links); i++) {
if (self->hid_links[i])
close(self->hid_links[i]);
@@ -572,6 +574,8 @@ static void load_programs(const struct test_program programs[],
self->hid_links[i] = args.retval;
}
+ // hid__attach(self->skel);
+
self->hidraw_fd = open_hidraw(self->dev_id);
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
}
@@ -871,6 +875,57 @@ TEST_F(hid_bpf, test_hid_user_raw_request_call)
ASSERT_EQ(args.data[1], 2);
}
+/*
+ * Call hid_hw_raw_request against the given uhid device,
+ * check that the program is called and does the expected.
+ */
+TEST_F(hid_bpf, test_hid_filter_raw_request_call)
+{
+ const struct test_program progs[] = {
+ { .name = "hid_test_filter_raw_request" },
+ { .name = "hid_test_raw_request" },
+ };
+ __u8 buf[10] = {0};
+ int err;
+
+ LOAD_PROGRAMS(progs);
+
+ /* first check that we did not attach to device_event */
+
+ /* inject one event */
+ buf[0] = 1;
+ buf[1] = 42;
+ uhid_send_event(_metadata, self->uhid_fd, buf, 6);
+
+ /* read the data from hidraw */
+ memset(buf, 0, sizeof(buf));
+ err = read(self->hidraw_fd, buf, sizeof(buf));
+ ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
+ ASSERT_EQ(buf[0], 1);
+ ASSERT_EQ(buf[1], 42);
+ ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");
+
+ /* now check that our program is preventing hid_hw_raw_request() */
+
+ /* emit hid_hw_raw_request from hidraw */
+ /* Get Feature */
+ memset(buf, 0, sizeof(buf));
+ buf[0] = 0x1; /* Report Number */
+ err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);
+ ASSERT_LT(err, 0) TH_LOG("unexpected success while reading HIDIOCGFEATURE: %d", err);
+
+ /* remove our bpf program and check that we can now emit commands */
+
+ /* detach the program */
+ detach_bpf(self);
+
+ self->hidraw_fd = open_hidraw(self->dev_id);
+ ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
+
+ err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);
+ ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGFEATURE: %d", err);
+}
+
/*
* Attach hid_insert{0,1,2} to the given uhid device,
* retrieve and open the matching hidraw node,
diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c
index b721d1256836..64aaa279bec4 100644
--- a/tools/testing/selftests/hid/progs/hid.c
+++ b/tools/testing/selftests/hid/progs/hid.c
@@ -226,3 +226,54 @@ HID_BPF_DEVICE_EVENT(hid_test_insert3, struct hid_bpf_ctx *hid_ctx)
return 0;
}
+
+// SEC("fentry/hidraw_open")
+// int BPF_PROG(hidraw_open, struct inode *inode, struct file *file)
+// {
+// bpf_printk("inode: %llx, file: %llx", (u64)inode, (u64)file);
+// return 0;
+// }
+
+HID_BPF_RAW_REQUEST(hid_test_filter_raw_request, struct hid_bpf_ctx *hctx)
+{
+ bpf_printk("in %s:%d", __func__, __LINE__);
+ return 0;
+}
+
+HID_BPF_SLEEPABLE_RAW_REQUEST(hid_test_raw_request, struct hid_bpf_ctx *hctx)
+{
+ struct test_report buf = {
+ .data = {2, 3, 4, 5, 6, 7},
+ };
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 2 /* size */);
+ int ret;
+
+ bpf_printk("in %s, hctx: %llx source: %llx", __func__, (u64)hctx, hctx->source);
+
+ if (!data)
+ return 0; /* EPERM check */
+ bpf_printk("in %s:%d", __func__, __LINE__);
+
+ if (hctx->source) {
+ hid_bpf_input_report(hctx, HID_INPUT_REPORT, buf.data, sizeof(buf.data));
+
+ /* still forward the request as-is to the device, hid-bpf will not
+ * call us again.
+ */
+
+ data[0] = hctx->reportnum;
+
+ ret = hid_bpf_hw_request(hctx,
+ data,
+ 2,
+ hctx->report_type,
+ hctx->reqtype);
+ bpf_printk("ret: %d", ret);
+ if (ret)
+ return ret;
+ return -1;
+ }
+
+ bpf_printk("in %s:%d", __func__, __LINE__);
+ return 0;
+}
diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
index 9826880e88d1..779ec151c717 100644
--- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
+++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
@@ -56,17 +56,6 @@ enum hid_report_type {
HID_REPORT_TYPES,
};
-struct hid_bpf_ctx {
- __u32 index;
- const struct hid_device *hid;
- __u32 allocated_size;
- enum hid_report_type report_type;
- union {
- __s32 retval;
- __s32 size;
- };
-} __attribute__((preserve_access_index));
-
enum hid_class_request {
HID_REQ_GET_REPORT = 0x01,
HID_REQ_GET_IDLE = 0x02,
@@ -88,6 +77,20 @@ struct attach_prog_args {
int insert_head;
};
+struct hid_bpf_ctx {
+ __u32 index;
+ __u32 allocated_size;
+ __u64 source;
+ const struct hid_device *hid;
+ enum hid_report_type report_type;
+ enum hid_class_request reqtype; /* for HID_BPF_PROG_TYPE_RAW_REQUEST */
+ union {
+ __s32 retval;
+ __s32 size;
+ };
+ __u8 reportnum;
+} __attribute__((preserve_access_index));
+
/* following are kfuncs exported by HID for HID-BPF */
extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
unsigned int offset,
@@ -96,6 +99,10 @@ extern int hid_bpf_attach_prog_impl(unsigned int hid_id,
enum hid_bpf_prog_type type,
int (prog_fn)(struct hid_bpf_ctx *hid_ctx),
u32 flags, void *aux) __ksym;
+extern int hid_bpf_attach_sleepable_prog_impl(unsigned int hid_id,
+ enum hid_bpf_prog_type type,
+ int (prog_fn)(struct hid_bpf_ctx *hid_ctx),
+ u32 flags, void *aux) __ksym;
extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym;
extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym;
extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
@@ -110,12 +117,12 @@ extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
__u8 *data,
size_t buf__sz) __ksym;
-#define __HID_BPF_PROG(type, name, arg) \
+#define __HID_BPF_PROG(type, name, arg, sleepable) \
static int __##name(arg); \
SEC("syscall") \
int name(struct attach_prog_args *ctx) \
{ \
- ctx->retval = hid_bpf_attach_prog_impl(ctx->hid, \
+ ctx->retval = hid_bpf_attach_##sleepable##prog_impl(ctx->hid, \
type, \
__##name, \
ctx->insert_head ? HID_BPF_FLAG_INSERT_HEAD : \
@@ -125,7 +132,9 @@ extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
} \
static int __##name(arg)
-#define HID_BPF_DEVICE_EVENT(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_DEVICE_EVENT, name, arg)
-#define HID_BPF_RDESC_FIXUP(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_RDESC_FIXUP, name, arg)
+#define HID_BPF_DEVICE_EVENT(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_DEVICE_EVENT, name, arg, )
+#define HID_BPF_RDESC_FIXUP(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_RDESC_FIXUP, name, arg, )
+#define HID_BPF_RAW_REQUEST(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_RAW_REQUEST, name, arg, )
+#define HID_BPF_SLEEPABLE_RAW_REQUEST(name, arg) __HID_BPF_PROG(HID_BPF_PROG_TYPE_RAW_REQUEST, name, arg, sleepable_)
#endif /* __HID_BPF_HELPERS_H */
--
2.44.0
When we attach a sleepable hook to hid_hw_raw_requests, we can (and in
many cases should) call ourself hid_bpf_raw_request(), to actaully fetch
data from the device itself.
However, this means that we might enter an infinite loop between
hid_hw_raw_requests trace and hid_bpf_raw_request() call.
To prevent that, if a hid_bpf_raw_request() call is emitted, we prevent
any sleepable bpf trace to hid_hw_raw_requests(). This way we can always
trace/monitor/filter the incoming bpf requests, while preventing those
loops to happen.
Signed-off-by: Benjamin Tissoires <[email protected]>
---
drivers/hid/bpf/hid_bpf_dispatch.c | 7 ++++---
drivers/hid/hid-core.c | 6 +++---
drivers/hid/hidraw.c | 4 ++--
include/linux/hid.h | 2 +-
include/linux/hid_bpf.h | 6 +++---
5 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index 7aeab3f9f2c7..79cac293ba29 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -99,7 +99,7 @@ dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
unsigned char reportnum, u8 *buf,
u32 *size, enum hid_report_type rtype,
enum hid_class_request reqtype,
- u64 source)
+ u64 source, bool from_bpf)
{
struct hid_bpf_ctx_kern ctx_kern = {
.ctx = {
@@ -122,7 +122,7 @@ dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
// if (!hdev->bpf.device_data)
// return buf;
- ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RAW_REQUEST, &ctx_kern, true);
+ ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RAW_REQUEST, &ctx_kern, !from_bpf);
if (ret < 0)
return ERR_PTR(ret);
@@ -536,7 +536,8 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
size,
rtype,
reqtype,
- (__u64)ctx);
+ (__u64)ctx,
+ true); /* prevent infinite recursions */
if (ret > 0)
memcpy(buf, dma_data, ret);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 7d468f6dbefe..d53f465a4ccb 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2404,7 +2404,7 @@ int __hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype,
enum hid_class_request reqtype,
- __u64 source)
+ __u64 source, bool from_bpf)
{
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
u32 size = (u32)len; /* max_buffer_size is 16 KB */
@@ -2416,7 +2416,7 @@ int __hid_hw_raw_request(struct hid_device *hdev,
return -EINVAL;
buf = dispatch_hid_bpf_raw_requests(hdev, reportnum, buf, &size, rtype,
- reqtype, source);
+ reqtype, source, from_bpf);
if (IS_ERR(buf))
return PTR_ERR(buf);
@@ -2442,7 +2442,7 @@ int hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype, enum hid_class_request reqtype)
{
- return __hid_hw_raw_request(hdev, reportnum, buf, len, rtype, reqtype, 0);
+ return __hid_hw_raw_request(hdev, reportnum, buf, len, rtype, reqtype, 0, false);
}
EXPORT_SYMBOL_GPL(hid_hw_raw_request);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 6d2a6d38e42a..4ba3131de614 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -151,7 +151,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
}
ret = __hid_hw_raw_request(dev, buf[0], buf, count, report_type,
- HID_REQ_SET_REPORT, (__u64)file);
+ HID_REQ_SET_REPORT, (__u64)file, false);
out_free:
kfree(buf);
@@ -228,7 +228,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
}
ret = __hid_hw_raw_request(dev, report_number, buf, count, report_type,
- HID_REQ_GET_REPORT, (__u64)file);
+ HID_REQ_GET_REPORT, (__u64)file, false);
if (ret < 0)
goto out_free;
diff --git a/include/linux/hid.h b/include/linux/hid.h
index dac2804b4562..24d0d7c0bd33 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1129,7 +1129,7 @@ int __hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype,
enum hid_class_request reqtype,
- __u64 source);
+ __u64 source, bool from_bpf);
int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source);
int hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
index 1cd36bfdd608..6b2ac815572c 100644
--- a/include/linux/hid_bpf.h
+++ b/include/linux/hid_bpf.h
@@ -105,7 +105,7 @@ struct hid_bpf_ops {
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype,
enum hid_class_request reqtype,
- __u64 source);
+ __u64 source, bool from_bpf);
int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len,
__u64 source);
int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type,
@@ -148,7 +148,7 @@ u8 *dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
u32 *size, enum hid_report_type rtype,
enum hid_class_request reqtype,
- __u64 source);
+ __u64 source, bool from_bpf);
int hid_bpf_connect_device(struct hid_device *hdev);
void hid_bpf_disconnect_device(struct hid_device *hdev);
void hid_bpf_destroy_device(struct hid_device *hid);
@@ -162,7 +162,7 @@ static inline u8 *dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
unsigned char reportnum, u8 *buf,
u32 *size, enum hid_report_type rtype,
enum hid_class_request reqtype,
- u64 source) { return buf; }
+ u64 source, bool from_bpf) { return buf; }
static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
--
2.44.0
This allows to know who actually sent what when we process the request
to the device.
This will be useful for a BPF firewall program to allow or not requests
coming from a dedicated hidraw node client.
Signed-off-by: Benjamin Tissoires <[email protected]>
---
drivers/hid/bpf/hid_bpf_dispatch.c | 11 +++--
drivers/hid/hid-core.c | 85 ++++++++++++++++++++++++--------------
drivers/hid/hidraw.c | 10 ++---
include/linux/hid.h | 6 +++
include/linux/hid_bpf.h | 16 ++++---
5 files changed, 81 insertions(+), 47 deletions(-)
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index 7ede657f459b..55c9e74c2465 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -47,7 +47,7 @@ __weak noinline int hid_bpf_device_event(struct hid_bpf_ctx *ctx)
u8 *
dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data,
- u32 *size, int interrupt)
+ u32 *size, int interrupt, u64 source)
{
struct hid_bpf_ctx_kern ctx_kern = {
.ctx = {
@@ -55,6 +55,7 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
.report_type = type,
.allocated_size = hdev->bpf.allocated_data,
.size = *size,
+ .source = source,
},
.data = hdev->bpf.device_data,
};
@@ -483,7 +484,8 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
dma_data,
size,
rtype,
- reqtype);
+ reqtype,
+ (__u64)ctx);
if (ret > 0)
memcpy(buf, dma_data, ret);
@@ -522,7 +524,8 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
ret = hid_bpf_ops->hid_hw_output_report(hdev,
dma_data,
- size);
+ size,
+ (__u64)ctx);
kfree(dma_data);
return ret;
@@ -553,7 +556,7 @@ hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf
hdev = (struct hid_device *)ctx->hid; /* discard const */
- return hid_bpf_ops->hid_input_report(hdev, type, buf, size, 0);
+ return hid_bpf_ops->hid_input_report(hdev, type, buf, size, 0, (__u64)ctx);
}
__bpf_kfunc_end_defs();
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index b1fa0378e8f4..b8414ce62e7b 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2026,19 +2026,9 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
}
EXPORT_SYMBOL_GPL(hid_report_raw_event);
-/**
- * hid_input_report - report data from lower layer (usb, bt...)
- *
- * @hid: hid device
- * @type: HID report type (HID_*_REPORT)
- * @data: report contents
- * @size: size of data parameter
- * @interrupt: distinguish between interrupt and control transfers
- *
- * This is data entry for lower layers.
- */
-int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
- int interrupt)
+
+static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
+ u8 *data, u32 size, int interrupt, u64 source)
{
struct hid_report_enum *report_enum;
struct hid_driver *hdrv;
@@ -2058,7 +2048,7 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data
report_enum = hid->report_enum + type;
hdrv = hid->driver;
- data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt);
+ data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt, source);
if (IS_ERR(data)) {
ret = PTR_ERR(data);
goto unlock;
@@ -2093,6 +2083,23 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data
up(&hid->driver_input_lock);
return ret;
}
+
+/**
+ * hid_input_report - report data from lower layer (usb, bt...)
+ *
+ * @hid: hid device
+ * @type: HID report type (HID_*_REPORT)
+ * @data: report contents
+ * @size: size of data parameter
+ * @interrupt: distinguish between interrupt and control transfers
+ *
+ * This is data entry for lower layers.
+ */
+int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
+ int interrupt)
+{
+ return __hid_input_report(hid, type, data, size, interrupt, 0);
+}
EXPORT_SYMBOL_GPL(hid_input_report);
bool hid_match_one_id(const struct hid_device *hdev,
@@ -2393,6 +2400,24 @@ void hid_hw_request(struct hid_device *hdev,
}
EXPORT_SYMBOL_GPL(hid_hw_request);
+int __hid_hw_raw_request(struct hid_device *hdev,
+ unsigned char reportnum, __u8 *buf,
+ size_t len, enum hid_report_type rtype,
+ enum hid_class_request reqtype,
+ __u64 source)
+{
+ unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
+
+ if (hdev->ll_driver->max_buffer_size)
+ max_buffer_size = hdev->ll_driver->max_buffer_size;
+
+ if (len < 1 || len > max_buffer_size || !buf)
+ return -EINVAL;
+
+ return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
+ rtype, reqtype);
+}
+
/**
* hid_hw_raw_request - send report request to device
*
@@ -2410,6 +2435,12 @@ EXPORT_SYMBOL_GPL(hid_hw_request);
int hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype, enum hid_class_request reqtype)
+{
+ return __hid_hw_raw_request(hdev, reportnum, buf, len, rtype, reqtype, 0);
+}
+EXPORT_SYMBOL_GPL(hid_hw_raw_request);
+
+int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source)
{
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
@@ -2419,10 +2450,11 @@ int hid_hw_raw_request(struct hid_device *hdev,
if (len < 1 || len > max_buffer_size || !buf)
return -EINVAL;
- return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
- rtype, reqtype);
+ if (hdev->ll_driver->output_report)
+ return hdev->ll_driver->output_report(hdev, buf, len);
+
+ return -ENOSYS;
}
-EXPORT_SYMBOL_GPL(hid_hw_raw_request);
/**
* hid_hw_output_report - send output report to device
@@ -2435,18 +2467,7 @@ EXPORT_SYMBOL_GPL(hid_hw_raw_request);
*/
int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len)
{
- unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
-
- if (hdev->ll_driver->max_buffer_size)
- max_buffer_size = hdev->ll_driver->max_buffer_size;
-
- if (len < 1 || len > max_buffer_size || !buf)
- return -EINVAL;
-
- if (hdev->ll_driver->output_report)
- return hdev->ll_driver->output_report(hdev, buf, len);
-
- return -ENOSYS;
+ return __hid_hw_output_report(hdev, buf, len, 0);
}
EXPORT_SYMBOL_GPL(hid_hw_output_report);
@@ -2973,9 +2994,9 @@ EXPORT_SYMBOL_GPL(hid_check_keys_pressed);
#ifdef CONFIG_HID_BPF
static struct hid_bpf_ops hid_ops = {
.hid_get_report = hid_get_report,
- .hid_hw_raw_request = hid_hw_raw_request,
- .hid_hw_output_report = hid_hw_output_report,
- .hid_input_report = hid_input_report,
+ .hid_hw_raw_request = __hid_hw_raw_request,
+ .hid_hw_output_report = __hid_hw_output_report,
+ .hid_input_report = __hid_input_report,
.owner = THIS_MODULE,
.bus_type = &hid_bus_type,
};
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 2bc762d31ac7..6d2a6d38e42a 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -140,7 +140,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
if ((report_type == HID_OUTPUT_REPORT) &&
!(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) {
- ret = hid_hw_output_report(dev, buf, count);
+ ret = __hid_hw_output_report(dev, buf, count, (__u64)file);
/*
* compatibility with old implementation of USB-HID and I2C-HID:
* if the device does not support receiving output reports,
@@ -150,8 +150,8 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
goto out_free;
}
- ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type,
- HID_REQ_SET_REPORT);
+ ret = __hid_hw_raw_request(dev, buf[0], buf, count, report_type,
+ HID_REQ_SET_REPORT, (__u64)file);
out_free:
kfree(buf);
@@ -227,8 +227,8 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
goto out_free;
}
- ret = hid_hw_raw_request(dev, report_number, buf, count, report_type,
- HID_REQ_GET_REPORT);
+ ret = __hid_hw_raw_request(dev, report_number, buf, count, report_type,
+ HID_REQ_GET_REPORT, (__u64)file);
if (ret < 0)
goto out_free;
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 8e06d89698e6..dac2804b4562 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1125,6 +1125,12 @@ int __must_check hid_hw_open(struct hid_device *hdev);
void hid_hw_close(struct hid_device *hdev);
void hid_hw_request(struct hid_device *hdev,
struct hid_report *report, enum hid_class_request reqtype);
+int __hid_hw_raw_request(struct hid_device *hdev,
+ unsigned char reportnum, __u8 *buf,
+ size_t len, enum hid_report_type rtype,
+ enum hid_class_request reqtype,
+ __u64 source);
+int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source);
int hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype,
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
index 99ebe7bbb02a..6bcaf19f1cc2 100644
--- a/include/linux/hid_bpf.h
+++ b/include/linux/hid_bpf.h
@@ -48,8 +48,9 @@ struct hid_device;
*/
struct hid_bpf_ctx {
__u32 index;
- const struct hid_device *hid;
__u32 allocated_size;
+ __u64 source;
+ const struct hid_device *hid;
enum hid_report_type report_type;
union {
__s32 retval;
@@ -99,10 +100,12 @@ struct hid_bpf_ops {
int (*hid_hw_raw_request)(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype,
- enum hid_class_request reqtype);
- int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len);
+ enum hid_class_request reqtype,
+ __u64 source);
+ int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len,
+ __u64 source);
int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type,
- u8 *data, u32 size, int interrupt);
+ u8 *data, u32 size, int interrupt, u64 source);
struct module *owner;
const struct bus_type *bus_type;
};
@@ -136,7 +139,7 @@ struct hid_bpf_link {
#ifdef CONFIG_HID_BPF
u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
- u32 *size, int interrupt);
+ u32 *size, int interrupt, u64 source);
int hid_bpf_connect_device(struct hid_device *hdev);
void hid_bpf_disconnect_device(struct hid_device *hdev);
void hid_bpf_destroy_device(struct hid_device *hid);
@@ -144,7 +147,8 @@ void hid_bpf_device_init(struct hid_device *hid);
u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size);
#else /* CONFIG_HID_BPF */
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
- u8 *data, u32 *size, int interrupt) { return data; }
+ u8 *data, u32 *size, int interrupt,
+ u64 source) { return data; }
static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
--
2.44.0