Details of BPF

Published:

How seccomp works in kernel

el0_sync –> el0_sync_handler –> el0_svc –> do_el0_svc –> el0_svc_common –> syscall_trace_enter –> secure_computing –> __secure_computing –> __seccomp_filter –> seccomp_run_filters

static inline int secure_computing(void)
{
	if (unlikely(test_thread_flag(TIF_SECCOMP)))
		return  __secure_computing(NULL);
	return 0;
}

这里面可以看到seccomp开关被thread_info中的一个flag控制。

static u32 seccomp_run_filters(const struct seccomp_data *sd)
{
    struct seccomp_filter *f =
			lockless_dereference(current->seccomp.filter);
    ...
    u32 cur_ret = BPF_PROG_RUN(f->prog, (void *)sd);
}

struct seccomp_filter {
	atomic_t usage;
	struct seccomp_filter *prev;
	struct bpf_prog *prog;
};

struct bpf_prog {
	u16			pages;		/* Number of allocated pages */
	...
	unsigned int		(*bpf_func)(const struct sk_buff *skb,
					    const struct bpf_insn *filter);
	/* Instructions for interpreter */
	union {
		struct sock_filter	insns[0];
		struct bpf_insn		insnsi[0];
	};
};

#define BPF_PROG_RUN(filter, ctx)  (*filter->bpf_func)(ctx, filter->insnsi)

可以看到bpf_func运行bpf_prog->insnsi;bpf_func指向 ___bpf_prog_run;核心是个jump table循环。

如何定位bpf_prog->insnsi

如果不能改function pointer,只能改bpf_prog->insnsi,那么如何定位它呢?

static u32 seccomp_run_filters(const struct seccomp_data *sd)
{
    struct seccomp_filter *f =
			lockless_dereference(current->seccomp.filter);
    ...
    u32 cur_ret = BPF_PROG_RUN(f->prog, (void *)sd);
}
struct task_struct {
    struct seccomp			seccomp;
}

struct seccomp {
	int mode;
	atomic_t filter_count;
	struct seccomp_filter *filter;
};

struct seccomp_filter {
	refcount_t refs;
	refcount_t users;
	bool log;
	struct seccomp_filter *prev;
	struct bpf_prog *prog;
	struct notification *notif;
	struct mutex notify_lock;
	wait_queue_head_t wqh;
};

我们可以看到seccomp_filtertask_struct->seccomp中来。一个process可以有多个secomp_filter,每个secomp_filter都有自己的bpf_prog。因此可以简单的定位到bpf_prog->insnsi

BFP program load

Two ways, one is bpf syscall –> bpf_prog_load –> bpf_check

Another way is via prctl syscall –> prctl_set_seccomp –>do_seccomp –>seccomp_set_mode_filter

貌似seccomp的filer没有经过bpf_check,使用qemu动态测试一下