Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions arch/arm64/net/bpf_jit_comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2788,6 +2788,9 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
void *image, *tmp;
int ret;

if (tlinks[BPF_TRAMP_SESSION].nr_links)
return -EOPNOTSUPP;

/* image doesn't need to be in module memory range, so we can
* use kvmalloc.
*/
Expand Down
3 changes: 3 additions & 0 deletions arch/loongarch/net/bpf_jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1739,6 +1739,9 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
void *image, *tmp;
struct jit_ctx ctx;

if (tlinks[BPF_TRAMP_SESSION].nr_links)
return -EOPNOTSUPP;

size = ro_image_end - ro_image;
image = kvmalloc(size, GFP_KERNEL);
if (!image)
Expand Down
3 changes: 3 additions & 0 deletions arch/powerpc/net/bpf_jit_comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,9 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
void *rw_image, *tmp;
int ret;

if (tlinks[BPF_TRAMP_SESSION].nr_links)
return -EOPNOTSUPP;

/*
* rw_image doesn't need to be in module memory range, so we can
* use kvmalloc.
Expand Down
3 changes: 3 additions & 0 deletions arch/riscv/net/bpf_jit_comp64.c
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,9 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
struct rv_jit_context ctx;
u32 size = ro_image_end - ro_image;

if (tlinks[BPF_TRAMP_SESSION].nr_links)
return -EOPNOTSUPP;

image = kvmalloc(size, GFP_KERNEL);
if (!image)
return -ENOMEM;
Expand Down
3 changes: 3 additions & 0 deletions arch/s390/net/bpf_jit_comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2924,6 +2924,9 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image,
struct bpf_tramp_jit tjit;
int ret;

if (tlinks[BPF_TRAMP_SESSION].nr_links)
return -EOPNOTSUPP;

/* Compute offsets, check whether the code fits. */
memset(&tjit, 0, sizeof(tjit));
ret = __arch_prepare_bpf_trampoline(im, &tjit, m, flags,
Expand Down
115 changes: 114 additions & 1 deletion arch/x86/net/bpf_jit_comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3108,6 +3108,97 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog,
return 0;
}

static int invoke_bpf_session_entry(const struct btf_func_model *m, u8 **pprog,
struct bpf_tramp_links *tl, int stack_size,
int run_ctx_off, int session_off,
void *image, void *rw_image)
{
u64 session_flags;
u8 *prog = *pprog;
u8 *jmp_insn;
int i;

/* clear the session flags:
*
* xor rax, rax
* mov QWORD PTR [rbp - session_off], rax
*/
EMIT3(0x48, 0x31, 0xC0);
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -session_off);

for (i = 0; i < tl->nr_links; i++) {
if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, run_ctx_off, true,
image, rw_image))
return -EINVAL;

/* fentry prog stored return value into [rbp - 8]. Emit:
* if (*(u64 *)(rbp - 8) != 0)
* *(u64 *)(rbp - session_off) |= (1 << (i + 1));
*/
/* cmp QWORD PTR [rbp - 0x8], 0x0 */
EMIT4(0x48, 0x83, 0x7d, 0xf8); EMIT1(0x00);
/* emit 2 nops that will be replaced with JE insn */
jmp_insn = prog;
emit_nops(&prog, 2);

session_flags = (1ULL << (i + 1));
/* mov rax, $session_flags */
emit_mov_imm64(&prog, BPF_REG_0, session_flags >> 32, (u32) session_flags);
/* or QWORD PTR [rbp - session_off], rax */
EMIT2(0x48, 0x09);
emit_insn_suffix(&prog, BPF_REG_FP, BPF_REG_0, -session_off);

jmp_insn[0] = X86_JE;
jmp_insn[1] = prog - jmp_insn - 2;
}

*pprog = prog;
return 0;
}

static int invoke_bpf_session_exit(const struct btf_func_model *m, u8 **pprog,
struct bpf_tramp_links *tl, int stack_size,
int run_ctx_off, int session_off,
void *image, void *rw_image)
{
u64 session_flags;
u8 *prog = *pprog;
u8 *jmp_insn;
int i;

/* set the bpf_trace_is_exit flag to the session flags */
/* mov rax, 1 */
emit_mov_imm32(&prog, false, BPF_REG_0, 1);
/* or QWORD PTR [rbp - session_off], rax */
EMIT2(0x48, 0x09);
emit_insn_suffix(&prog, BPF_REG_FP, BPF_REG_0, -session_off);

for (i = 0; i < tl->nr_links; i++) {
/* check if (1 << (i+1)) is set in the session flags, and
* skip the execution of the fexit program if it is.
*/
session_flags = 1ULL << (i + 1);
/* mov rax, $session_flags */
emit_mov_imm64(&prog, BPF_REG_1, session_flags >> 32, (u32) session_flags);
/* test QWORD PTR [rbp - session_off], rax */
EMIT2(0x48, 0x85);
emit_insn_suffix(&prog, BPF_REG_FP, BPF_REG_1, -session_off);
/* emit 2 nops that will be replaced with JE insn */
jmp_insn = prog;
emit_nops(&prog, 2);

if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, run_ctx_off, false,
image, rw_image))
return -EINVAL;

jmp_insn[0] = X86_JNE;
jmp_insn[1] = prog - jmp_insn - 2;
}

*pprog = prog;
return 0;
}

/* mov rax, qword ptr [rbp - rounded_stack_depth - 8] */
#define LOAD_TRAMP_TAIL_CALL_CNT_PTR(stack) \
__LOAD_TCC_PTR(-round_up(stack, 8) - 8)
Expand Down Expand Up @@ -3179,8 +3270,10 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
void *func_addr)
{
int i, ret, nr_regs = m->nr_args, stack_size = 0;
int regs_off, nregs_off, ip_off, run_ctx_off, arg_stack_off, rbx_off;
int regs_off, nregs_off, session_off, ip_off, run_ctx_off,
arg_stack_off, rbx_off;
struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY];
struct bpf_tramp_links *session = &tlinks[BPF_TRAMP_SESSION];
struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT];
struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN];
void *orig_call = func_addr;
Expand Down Expand Up @@ -3222,6 +3315,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
*
* RBP - nregs_off [ regs count ] always
*
* RBP - session_off [ session flags ] tracing session
*
* RBP - ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag
*
* RBP - rbx_off [ rbx value ] always
Expand All @@ -3246,6 +3341,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
/* regs count */
stack_size += 8;
nregs_off = stack_size;
stack_size += 8;
session_off = stack_size;

if (flags & BPF_TRAMP_F_IP_ARG)
stack_size += 8; /* room for IP address argument */
Expand Down Expand Up @@ -3345,6 +3442,13 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
return -EINVAL;
}

if (session->nr_links) {
if (invoke_bpf_session_entry(m, &prog, session, regs_off,
run_ctx_off, session_off,
image, rw_image))
return -EINVAL;
}

if (fmod_ret->nr_links) {
branches = kcalloc(fmod_ret->nr_links, sizeof(u8 *),
GFP_KERNEL);
Expand Down Expand Up @@ -3409,6 +3513,15 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
}
}

if (session->nr_links) {
if (invoke_bpf_session_exit(m, &prog, session, regs_off,
run_ctx_off, session_off,
image, rw_image)) {
ret = -EINVAL;
goto cleanup;
}
}

if (flags & BPF_TRAMP_F_RESTORE_REGS)
restore_regs(m, &prog, regs_off);

Expand Down
1 change: 1 addition & 0 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,7 @@ enum bpf_tramp_prog_type {
BPF_TRAMP_FENTRY,
BPF_TRAMP_FEXIT,
BPF_TRAMP_MODIFY_RETURN,
BPF_TRAMP_SESSION,
BPF_TRAMP_MAX,
BPF_TRAMP_REPLACE, /* more than MAX */
};
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,7 @@ enum bpf_attach_type {
BPF_NETKIT_PEER,
BPF_TRACE_KPROBE_SESSION,
BPF_TRACE_UPROBE_SESSION,
BPF_TRACE_SESSION,
__MAX_BPF_ATTACH_TYPE
};

Expand Down
2 changes: 2 additions & 0 deletions kernel/bpf/btf.c
Original file line number Diff line number Diff line change
Expand Up @@ -6107,6 +6107,7 @@ static int btf_validate_prog_ctx_type(struct bpf_verifier_log *log, const struct
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
case BPF_MODIFY_RETURN:
case BPF_TRACE_SESSION:
/* allow u64* as ctx */
if (btf_is_int(t) && t->size == 8)
return 0;
Expand Down Expand Up @@ -6704,6 +6705,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
fallthrough;
case BPF_LSM_CGROUP:
case BPF_TRACE_FEXIT:
case BPF_TRACE_SESSION:
/* When LSM programs are attached to void LSM hooks
* they use FEXIT trampolines and when attached to
* int LSM hooks, they use MODIFY_RETURN trampolines.
Expand Down
2 changes: 2 additions & 0 deletions kernel/bpf/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -3549,6 +3549,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
case BPF_PROG_TYPE_TRACING:
if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
prog->expected_attach_type != BPF_TRACE_FEXIT &&
prog->expected_attach_type != BPF_TRACE_SESSION &&
prog->expected_attach_type != BPF_MODIFY_RETURN) {
err = -EINVAL;
goto out_put_prog;
Expand Down Expand Up @@ -4322,6 +4323,7 @@ attach_type_to_prog_type(enum bpf_attach_type attach_type)
case BPF_TRACE_RAW_TP:
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
case BPF_TRACE_SESSION:
case BPF_MODIFY_RETURN:
return BPF_PROG_TYPE_TRACING;
case BPF_LSM_MAC:
Expand Down
5 changes: 4 additions & 1 deletion kernel/bpf/trampoline.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ bool bpf_prog_has_trampoline(const struct bpf_prog *prog)

return (ptype == BPF_PROG_TYPE_TRACING &&
(eatype == BPF_TRACE_FENTRY || eatype == BPF_TRACE_FEXIT ||
eatype == BPF_MODIFY_RETURN)) ||
eatype == BPF_MODIFY_RETURN || eatype == BPF_TRACE_SESSION)) ||
(ptype == BPF_PROG_TYPE_LSM && eatype == BPF_LSM_MAC);
}

Expand Down Expand Up @@ -418,6 +418,7 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
tr->flags &= (BPF_TRAMP_F_SHARE_IPMODIFY | BPF_TRAMP_F_TAIL_CALL_CTX);

if (tlinks[BPF_TRAMP_FEXIT].nr_links ||
tlinks[BPF_TRAMP_SESSION].nr_links ||
tlinks[BPF_TRAMP_MODIFY_RETURN].nr_links) {
/* NOTE: BPF_TRAMP_F_RESTORE_REGS and BPF_TRAMP_F_SKIP_FRAME
* should not be set together.
Expand Down Expand Up @@ -515,6 +516,8 @@ static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog)
return BPF_TRAMP_MODIFY_RETURN;
case BPF_TRACE_FEXIT:
return BPF_TRAMP_FEXIT;
case BPF_TRACE_SESSION:
return BPF_TRAMP_SESSION;
case BPF_LSM_MAC:
if (!prog->aux->attach_func_proto->type)
/* The function returns void, we cannot modify its
Expand Down
17 changes: 13 additions & 4 deletions kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -12284,6 +12284,7 @@ enum special_kfunc_type {
KF___bpf_trap,
KF_bpf_task_work_schedule_signal,
KF_bpf_task_work_schedule_resume,
KF_bpf_tracing_is_exit,
};

BTF_ID_LIST(special_kfunc_list)
Expand Down Expand Up @@ -12356,6 +12357,7 @@ BTF_ID(func, bpf_res_spin_unlock_irqrestore)
BTF_ID(func, __bpf_trap)
BTF_ID(func, bpf_task_work_schedule_signal)
BTF_ID(func, bpf_task_work_schedule_resume)
BTF_ID(func, bpf_tracing_is_exit)

static bool is_task_work_add_kfunc(u32 func_id)
{
Expand Down Expand Up @@ -12410,7 +12412,8 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
struct bpf_reg_state *reg = &regs[regno];
bool arg_mem_size = false;

if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx])
if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||
meta->func_id == special_kfunc_list[KF_bpf_tracing_is_exit])
return KF_ARG_PTR_TO_CTX;

/* In this function, we verify the kfunc's BTF as per the argument type,
Expand Down Expand Up @@ -17272,6 +17275,7 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char
break;
case BPF_TRACE_RAW_TP:
case BPF_MODIFY_RETURN:
case BPF_TRACE_SESSION:
return 0;
case BPF_TRACE_ITER:
break;
Expand Down Expand Up @@ -22727,6 +22731,7 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
if (prog_type == BPF_PROG_TYPE_TRACING &&
insn->imm == BPF_FUNC_get_func_ret) {
if (eatype == BPF_TRACE_FEXIT ||
eatype == BPF_TRACE_SESSION ||
eatype == BPF_MODIFY_RETURN) {
/* Load nr_args from ctx - 8 */
insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
Expand Down Expand Up @@ -23668,7 +23673,8 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
if (tgt_prog->type == BPF_PROG_TYPE_TRACING &&
prog_extension &&
(tgt_prog->expected_attach_type == BPF_TRACE_FENTRY ||
tgt_prog->expected_attach_type == BPF_TRACE_FEXIT)) {
tgt_prog->expected_attach_type == BPF_TRACE_FEXIT ||
tgt_prog->expected_attach_type == BPF_TRACE_SESSION)) {
/* Program extensions can extend all program types
* except fentry/fexit. The reason is the following.
* The fentry/fexit programs are used for performance
Expand All @@ -23683,7 +23689,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
* beyond reasonable stack size. Hence extending fentry
* is not allowed.
*/
bpf_log(log, "Cannot extend fentry/fexit\n");
bpf_log(log, "Cannot extend fentry/fexit/session\n");
return -EINVAL;
}
} else {
Expand Down Expand Up @@ -23767,6 +23773,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
case BPF_LSM_CGROUP:
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
case BPF_TRACE_SESSION:
if (!btf_type_is_func(t)) {
bpf_log(log, "attach_btf_id %u is not a function\n",
btf_id);
Expand Down Expand Up @@ -23933,6 +23940,7 @@ static bool can_be_sleepable(struct bpf_prog *prog)
case BPF_TRACE_FEXIT:
case BPF_MODIFY_RETURN:
case BPF_TRACE_ITER:
case BPF_TRACE_SESSION:
return true;
default:
return false;
Expand Down Expand Up @@ -24014,9 +24022,10 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
tgt_info.tgt_name);
return -EINVAL;
} else if ((prog->expected_attach_type == BPF_TRACE_FEXIT ||
prog->expected_attach_type == BPF_TRACE_SESSION ||
prog->expected_attach_type == BPF_MODIFY_RETURN) &&
btf_id_set_contains(&noreturn_deny, btf_id)) {
verbose(env, "Attaching fexit/fmod_ret to __noreturn function '%s' is rejected.\n",
verbose(env, "Attaching fexit/session/fmod_ret to __noreturn function '%s' is rejected.\n",
tgt_info.tgt_name);
return -EINVAL;
}
Expand Down
Loading
Loading