Program type BPF_PROG_TYPE_SYSCALL
Syscall programs can be used to execute syscalls from eBPF.
Usage
The abstract purpose of the syscall program type is to execute syscalls from eBPF. The initial use case for this program type was to offload some of the work of loader libraries to syscall eBPF programs. The program type can also be used by for "HID-BPF" to register a BPF program as a HID device driver.
Loading with light skeletons
This use case revolves around using a BPF_PROG_TYPE_SYSCALL
program to load one or more eBPF programs. The reason behind this is two-fold. First, with a bit of automation in the form of generation tools, loading a program can be made easier. Second, this new structure would make it easier to implement a form of code signing for eBPF programs. However, the code signing use case so far has not been successful.
The way this works is that you write and compile your primary eBPF program as normal. You then feed it to bpftool
with the gen skeleton -L {prog}.o > {prog}.skel.h
command. This will generate a "light skeleton" for the program. Essentially a header file which can be included by a custom userspace program as dependency. It exposes pre-defined function to then load the eBPF program. The header file embeds the essential parts of the primary ELF file and a generated BPF_PROG_TYPE_SYSCALL
program. Parts of the primary program such as its instructions, map definitions, and initial keys/values are part of the generated program or provided as data via existing mechanisms. The syscall program then uses a series of bpf_sys_bpf
helper calls to load the primary program just like a loader would normally do from userspace.
HID-BPF
The use case of HID-BPF is to implement HID device drivers in eBPF, at least partially. This allows HID drivers implemented this way for new devices to work on older kernels without the need for a kernel module.
No special program type was created for this use case, rather the FMOD_RET
tracing program type is repurposed. However, normally these attach to a single instance of a kernel function. For the HID-BPF use case, we want to attach to a specific HID device. This is done by using the hid_bpf_attach_prog
kfunc to attach the program to the HID device. Which bring us to the BPF_PROG_TYPE_SYSCALL
program which is used to actually execute this kfunc.
Context
This program type does not have a set context type, so as long as your eBPF program and userspace are aligned, you can use any context type you want.
Attachment
Syscall programs are never attached to any hook. They can only be executed from the BPF_PROG_RUN
syscall command.
Example
BPF-HID
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2022 Benjamin Tissoires
*/
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "hid_bpf_helpers.h"
struct attach_prog_args {
int prog_fd;
unsigned int hid;
int retval;
};
SEC("syscall")
int attach_prog(struct attach_prog_args *ctx)
{
ctx->retval = hid_bpf_attach_prog(ctx->hid,
ctx->prog_fd,
0);
return 0;
}
Helper functions
Not all helper functions are available in all program types. These are the helper calls available for syscall programs:
Supported helper functions
bpf_btf_find_by_name_kind
bpf_cgrp_storage_delete
bpf_cgrp_storage_get
bpf_copy_from_user
bpf_copy_from_user_task
bpf_current_task_under_cgroup
bpf_dynptr_data
bpf_dynptr_from_mem
bpf_dynptr_read
bpf_dynptr_write
bpf_find_vma
bpf_for_each_map_elem
bpf_get_branch_snapshot
bpf_get_current_ancestor_cgroup_id
bpf_get_current_cgroup_id
bpf_get_current_comm
bpf_get_current_pid_tgid
bpf_get_current_task
bpf_get_current_task_btf
bpf_get_current_uid_gid
bpf_get_func_ip
bpf_get_ns_current_pid_tgid
bpf_get_numa_node_id
bpf_get_prandom_u32
bpf_get_smp_processor_id
bpf_get_task_stack
bpf_jiffies64
bpf_kallsyms_lookup_name
bpf_kptr_xchg
bpf_ktime_get_boot_ns
bpf_ktime_get_ns
bpf_ktime_get_tai_ns
bpf_loop
bpf_map_delete_elem
bpf_map_lookup_elem
bpf_map_lookup_percpu_elem
bpf_map_peek_elem
bpf_map_pop_elem
bpf_map_push_elem
bpf_map_update_elem
bpf_per_cpu_ptr
bpf_perf_event_read
bpf_perf_event_read_value
bpf_probe_read
bpf_probe_read_kernel
bpf_probe_read_kernel_str
bpf_probe_read_str
bpf_probe_read_user
bpf_probe_read_user_str
bpf_probe_write_user
bpf_ringbuf_discard
bpf_ringbuf_discard_dynptr
bpf_ringbuf_output
bpf_ringbuf_query
bpf_ringbuf_reserve
bpf_ringbuf_reserve_dynptr
bpf_ringbuf_submit
bpf_ringbuf_submit_dynptr
bpf_send_signal
bpf_send_signal_thread
bpf_snprintf
bpf_snprintf_btf
bpf_spin_lock
bpf_spin_unlock
bpf_strncmp
bpf_sys_bpf
bpf_sys_close
bpf_tail_call
bpf_task_pt_regs
bpf_task_storage_delete
bpf_task_storage_get
bpf_this_cpu_ptr
bpf_timer_cancel
bpf_timer_init
bpf_timer_set_callback
bpf_timer_start
bpf_trace_printk
bpf_trace_vprintk
bpf_user_ringbuf_drain
KFuncs
Supported kfuncs
bpf_arena_alloc_pages
bpf_arena_free_pages
bpf_cast_to_kern_ctx
bpf_crypto_ctx_acquire
bpf_crypto_ctx_create
bpf_crypto_ctx_release
bpf_dynptr_adjust
bpf_dynptr_clone
bpf_dynptr_is_null
bpf_dynptr_is_rdonly
bpf_dynptr_size
bpf_dynptr_slice
bpf_dynptr_slice_rdwr
bpf_iter_bits_destroy
bpf_iter_bits_new
bpf_iter_bits_next
bpf_iter_css_destroy
bpf_iter_css_new
bpf_iter_css_next
bpf_iter_css_task_destroy
bpf_iter_css_task_new
bpf_iter_css_task_next
bpf_iter_num_destroy
bpf_iter_num_new
bpf_iter_num_next
bpf_iter_task_destroy
bpf_iter_task_new
bpf_iter_task_next
bpf_iter_task_vma_destroy
bpf_iter_task_vma_new
bpf_iter_task_vma_next
bpf_map_sum_elem_count
bpf_preempt_disable
bpf_preempt_enable
bpf_rcu_read_lock
bpf_rcu_read_unlock
bpf_rdonly_cast
bpf_wq_init
bpf_wq_set_callback_impl
bpf_wq_start
hid_bpf_allocate_context
hid_bpf_attach_prog
hid_bpf_hw_output_report
hid_bpf_hw_request
hid_bpf_input_report
hid_bpf_release_context