-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Declare an entry point that can use fmod_ret BPF programs, and also an API to access and change the incoming data. A simpler implementation would consist in just calling hid_bpf_device_event() for any incoming event and let users deal with the fact that they will be called for any event of any device. The goal of HID-BPF is to partially replace drivers, so this situation can be problematic because we might have programs which will step on each other toes. For that, we add a new API hid_bpf_attach_prog() that can be called from a syscall and we manually deal with a jump table in hid-bpf. Whenever we add a program to the jump table (in other words, when we attach a program to a HID device), we keep the number of time we added this program in the jump table so we can release it whenever there are no other users. HID devices have an RCU protected list of available programs in the jump table, and those programs are called one after the other thanks to bpf_tail_call(). To achieve the detection of users losing their fds on the programs we attached, we add 2 tracing facilities on bpf_prog_release() (for when a fd is closed) and bpf_free_inode() (for when a pinned program gets unpinned). Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
- Loading branch information
Benjamin Tissoires
authored and
Jiri Kosina
committed
Nov 15, 2022
1 parent
25621bc
commit f5c27da
Showing
14 changed files
with
1,804 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# SPDX-License-Identifier: GPL-2.0-only | ||
menu "HID-BPF support" | ||
|
||
config HID_BPF | ||
bool "HID-BPF support" | ||
default HID_SUPPORT | ||
depends on BPF && BPF_SYSCALL | ||
help | ||
This option allows to support eBPF programs on the HID subsystem. | ||
eBPF programs can fix HID devices in a lighter way than a full | ||
kernel patch and allow a lot more flexibility. | ||
|
||
For documentation, see Documentation/hid/hid-bpf.rst | ||
|
||
If unsure, say Y. | ||
|
||
endmenu |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# SPDX-License-Identifier: GPL-2.0 | ||
# | ||
# Makefile for HID-BPF | ||
# | ||
|
||
LIBBPF_INCLUDE = $(srctree)/tools/lib | ||
|
||
obj-$(CONFIG_HID_BPF) += hid_bpf.o | ||
CFLAGS_hid_bpf_dispatch.o += -I$(LIBBPF_INCLUDE) | ||
CFLAGS_hid_bpf_jmp_table.o += -I$(LIBBPF_INCLUDE) | ||
hid_bpf-objs += hid_bpf_dispatch.o hid_bpf_jmp_table.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// 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 | ||
|
||
extern bool call_hid_bpf_prog_release(u64 prog, int table_cnt) __ksym; | ||
|
||
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"); | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_HASH); | ||
__uint(max_entries, HID_BPF_MAX_PROGS * HID_BPF_PROG_TYPE_MAX); | ||
__type(key, void *); | ||
__type(value, __u8); | ||
} progs_map 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; | ||
} | ||
|
||
static void release_prog(u64 prog) | ||
{ | ||
u8 *value; | ||
|
||
value = bpf_map_lookup_elem(&progs_map, &prog); | ||
if (!value) | ||
return; | ||
|
||
if (call_hid_bpf_prog_release(prog, *value)) | ||
bpf_map_delete_elem(&progs_map, &prog); | ||
} | ||
|
||
SEC("fexit/bpf_prog_release") | ||
int BPF_PROG(hid_prog_release, struct inode *inode, struct file *filp) | ||
{ | ||
u64 prog = (u64)filp->private_data; | ||
|
||
release_prog(prog); | ||
|
||
return 0; | ||
} | ||
|
||
SEC("fexit/bpf_free_inode") | ||
int BPF_PROG(hid_free_inode, struct inode *inode) | ||
{ | ||
u64 prog = (u64)inode->i_private; | ||
|
||
release_prog(prog); | ||
|
||
return 0; | ||
} | ||
|
||
char LICENSE[] SEC("license") = "GPL"; |
Oops, something went wrong.