cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bpf_mod_race.c (2642B)


      1// SPDX-License-Identifier: GPL-2.0
      2#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 point
     33 *         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 ret
     44 *
     45 * At this point, module loading thread is blocked, we now load the program:
     46 *
     47 * bpf_check
     48 *   add_kfunc_call/check_pseudo_btf_id
     49 *     btf_try_get_module
     50 *       try_get_module_live == false
     51 *     return -ENXIO
     52 *
     53 * Without the fix (try_get_module_live in btf_try_get_module):
     54 *
     55 * bpf_check
     56 *   add_kfunc_call/check_pseudo_btf_id
     57 *     btf_try_get_module
     58 *       try_get_module == true
     59 *     <store module reference in btf_kfunc_tab or used_btf array>
     60 *   ...
     61 * return fd
     62 *
     63 * Now, if we inject an error in the blocked program, our module will be freed
     64 * (going straight from MODULE_STATE_COMING to MODULE_STATE_GOING).
     65 * Later, when bpf program is freed, it will try to module_put already freed
     66 * module. This is why try_get_module_live returns false if mod->state is not
     67 * 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";