brintos

brintos / linux-shallow public Read only

0
0
Text · 2.6 KiB · 82a5c6c Raw
101 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <vmlinux.h>3#include <bpf/bpf_helpers.h>4#include <bpf/bpf_tracing.h>5 6const volatile struct {7	/* thread to activate trace programs for */8	pid_t tgid;9	/* return error from __init function */10	int inject_error;11	/* uffd monitored range start address */12	void *fault_addr;13} bpf_mod_race_config = { -1 };14 15int bpf_blocking = 0;16int res_try_get_module = -1;17 18static __always_inline bool check_thread_id(void)19{20	struct task_struct *task = bpf_get_current_task_btf();21 22	return task->tgid == bpf_mod_race_config.tgid;23}24 25/* The trace of execution is something like this:26 *27 * finit_module()28 *   load_module()29 *     prepare_coming_module()30 *       notifier_call(MODULE_STATE_COMING)31 *         btf_parse_module()32 *         btf_alloc_id()		// Visible to userspace at this point33 *         list_add(btf_mod->list, &btf_modules)34 *     do_init_module()35 *       freeinit = kmalloc()36 *       ret = mod->init()37 *         bpf_prog_widen_race()38 *           bpf_copy_from_user()39 *             ...<sleep>...40 *       if (ret < 0)41 *         ...42 *         free_module()43 * return ret44 *45 * At this point, module loading thread is blocked, we now load the program:46 *47 * bpf_check48 *   add_kfunc_call/check_pseudo_btf_id49 *     btf_try_get_module50 *       try_get_module_live == false51 *     return -ENXIO52 *53 * Without the fix (try_get_module_live in btf_try_get_module):54 *55 * bpf_check56 *   add_kfunc_call/check_pseudo_btf_id57 *     btf_try_get_module58 *       try_get_module == true59 *     <store module reference in btf_kfunc_tab or used_btf array>60 *   ...61 * return fd62 *63 * Now, if we inject an error in the blocked program, our module will be freed64 * (going straight from MODULE_STATE_COMING to MODULE_STATE_GOING).65 * Later, when bpf program is freed, it will try to module_put already freed66 * module. This is why try_get_module_live returns false if mod->state is not67 * MODULE_STATE_LIVE.68 */69 70SEC("fmod_ret.s/bpf_fentry_test1")71int BPF_PROG(widen_race, int a, int ret)72{73	char dst;74 75	if (!check_thread_id())76		return 0;77	/* Indicate that we will attempt to block */78	bpf_blocking = 1;79	bpf_copy_from_user(&dst, 1, bpf_mod_race_config.fault_addr);80	return bpf_mod_race_config.inject_error;81}82 83SEC("fexit/do_init_module")84int BPF_PROG(fexit_init_module, struct module *mod, int ret)85{86	if (!check_thread_id())87		return 0;88	/* Indicate that we finished blocking */89	bpf_blocking = 2;90	return 0;91}92 93SEC("fexit/btf_try_get_module")94int BPF_PROG(fexit_module_get, const struct btf *btf, struct module *mod)95{96	res_try_get_module = !!mod;97	return 0;98}99 100char _license[] SEC("license") = "GPL";101