Skip to content

Commit 4ba40ca

Browse files
image-dragonKernel Patches Daemon
authored andcommitted
bpf,x86: add tracing session supporting for x86_64
Add BPF_TRACE_SESSION supporting to x86_64. invoke_bpf_session_entry and invoke_bpf_session_exit is introduced for this purpose. In invoke_bpf_session_entry(), we will check if the return value of the fentry is 0, and set the corresponding session flag if not. And in invoke_bpf_session_exit(), we will check if the corresponding flag is set. If set, the fexit will be skipped. As designed, the session flags and session cookie address is stored after the return value, and the stack look like this: cookie ptr -> 8 bytes session flags -> 8 bytes return value -> 8 bytes argN -> 8 bytes ... arg1 -> 8 bytes nr_args -> 8 bytes ... cookieN -> 8 bytes cookie1 -> 8 bytes In the entry of the session, we will clear the return value, so the fentry will always get 0 with ctx[nr_args] or bpf_get_func_ret(). Before the execution of the BPF prog, the "cookie ptr" will be filled with the corresponding cookie address, which is done in invoke_bpf_session_entry() and invoke_bpf_session_exit(). Signed-off-by: Menglong Dong <[email protected]> Co-developed-by: Leon Hwang <[email protected]> Signed-off-by: Leon Hwang <[email protected]>
1 parent fa495bc commit 4ba40ca

File tree

1 file changed

+181
-4
lines changed

1 file changed

+181
-4
lines changed

arch/x86/net/bpf_jit_comp.c

Lines changed: 181 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3109,6 +3109,148 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog,
31093109
return 0;
31103110
}
31113111

3112+
static int invoke_bpf_session_entry(const struct btf_func_model *m, u8 **pprog,
3113+
struct bpf_tramp_links *tl, int stack_size,
3114+
int run_ctx_off, int ret_off, int sflags_off,
3115+
int cookies_off, void *image, void *rw_image)
3116+
{
3117+
int i, j = 0, cur_cookie_off;
3118+
u64 session_flags;
3119+
u8 *prog = *pprog;
3120+
u8 *jmp_insn;
3121+
3122+
/* clear the session flags:
3123+
* xor rax, rax
3124+
* mov QWORD PTR [rbp - sflags_off], rax
3125+
*/
3126+
EMIT3(0x48, 0x31, 0xC0);
3127+
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -sflags_off);
3128+
/*
3129+
* clear the return value to make sure bpf_get_func_ret() always
3130+
* get 0 in fentry:
3131+
* mov QWORD PTR [rbp - 0x8], rax
3132+
*/
3133+
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -ret_off);
3134+
/* clear all the cookies in the cookie array */
3135+
for (i = 0; i < tl->nr_links; i++) {
3136+
if (tl->links[i]->link.prog->call_session_cookie) {
3137+
cur_cookie_off = -cookies_off + j * 8;
3138+
/* mov QWORD PTR [rbp - sflags_off], rax */
3139+
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0,
3140+
cur_cookie_off);
3141+
j++;
3142+
}
3143+
}
3144+
3145+
j = 0;
3146+
for (i = 0; i < tl->nr_links; i++) {
3147+
if (tl->links[i]->link.prog->call_session_cookie) {
3148+
cur_cookie_off = -cookies_off + j * 8;
3149+
/*
3150+
* save the cookie address to rbp - sflags_off + 8:
3151+
* lea rax, [rbp - cur_cookie_off]
3152+
* mov QWORD PTR [rbp - sflags_off + 8], rax
3153+
*/
3154+
if (!is_imm8(cur_cookie_off))
3155+
EMIT3_off32(0x48, 0x8D, 0x85, cur_cookie_off);
3156+
else
3157+
EMIT4(0x48, 0x8D, 0x45, cur_cookie_off);
3158+
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -sflags_off + 8);
3159+
j++;
3160+
}
3161+
if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, run_ctx_off, true,
3162+
ret_off, image, rw_image))
3163+
return -EINVAL;
3164+
3165+
/* fentry prog stored return value into [rbp - 8]. Emit:
3166+
* if (*(u64 *)(rbp - ret_off) != 0) {
3167+
* *(u64 *)(rbp - sflags_off) |= (1 << (i + 1));
3168+
* *(u64 *)(rbp - ret_off) = 0;
3169+
* }
3170+
*/
3171+
/* cmp QWORD PTR [rbp - ret_off], 0x0 */
3172+
EMIT4(0x48, 0x83, 0x7d, -ret_off); EMIT1(0x00);
3173+
/* emit 2 nops that will be replaced with JE insn */
3174+
jmp_insn = prog;
3175+
emit_nops(&prog, 2);
3176+
3177+
session_flags = (1ULL << (i + 1));
3178+
/* mov rax, $session_flags */
3179+
emit_mov_imm64(&prog, BPF_REG_0, session_flags >> 32, (u32) session_flags);
3180+
/* or QWORD PTR [rbp - sflags_off], rax */
3181+
EMIT2(0x48, 0x09);
3182+
emit_insn_suffix(&prog, BPF_REG_FP, BPF_REG_0, -sflags_off);
3183+
3184+
/* mov QWORD PTR [rbp - ret_off], 0x0 */
3185+
EMIT4(0x48, 0xC7, 0x45, -ret_off); EMIT4(0x00, 0x00, 0x00, 0x00);
3186+
3187+
jmp_insn[0] = X86_JE;
3188+
jmp_insn[1] = prog - jmp_insn - 2;
3189+
}
3190+
3191+
*pprog = prog;
3192+
return 0;
3193+
}
3194+
3195+
static int invoke_bpf_session_exit(const struct btf_func_model *m, u8 **pprog,
3196+
struct bpf_tramp_links *tl, int stack_size,
3197+
int run_ctx_off, int ret_off, int sflags_off,
3198+
int cookies_off, void *image, void *rw_image)
3199+
{
3200+
int i, j = 0, cur_cookie_off;
3201+
u64 session_flags;
3202+
u8 *prog = *pprog;
3203+
u8 *jmp_insn;
3204+
3205+
/*
3206+
* set the bpf_trace_is_exit flag to the session flags:
3207+
* mov rax, 1
3208+
* or QWORD PTR [rbp - sflags_off], rax
3209+
*/
3210+
emit_mov_imm32(&prog, false, BPF_REG_0, 1);
3211+
EMIT2(0x48, 0x09);
3212+
emit_insn_suffix(&prog, BPF_REG_FP, BPF_REG_0, -sflags_off);
3213+
3214+
for (i = 0; i < tl->nr_links; i++) {
3215+
if (tl->links[i]->link.prog->call_session_cookie) {
3216+
cur_cookie_off = -cookies_off + j * 8;
3217+
/*
3218+
* save the cookie address to rbp - sflags_off + 8:
3219+
* lea rax, [rbp - cur_cookie_off]
3220+
* mov QWORD PTR [rbp - sflags_off + 8], rax
3221+
*/
3222+
if (!is_imm8(cur_cookie_off))
3223+
EMIT3_off32(0x48, 0x8D, 0x85, cur_cookie_off);
3224+
else
3225+
EMIT4(0x48, 0x8D, 0x45, cur_cookie_off);
3226+
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -sflags_off + 8);
3227+
j++;
3228+
}
3229+
/* check if (1 << (i+1)) is set in the session flags, and
3230+
* skip the execution of the fexit program if it is.
3231+
*/
3232+
session_flags = 1ULL << (i + 1);
3233+
/* mov rax, $session_flags */
3234+
emit_mov_imm64(&prog, BPF_REG_0, session_flags >> 32, (u32) session_flags);
3235+
/* test QWORD PTR [rbp - sflags_off], rax */
3236+
EMIT2(0x48, 0x85);
3237+
emit_insn_suffix(&prog, BPF_REG_FP, BPF_REG_0, -sflags_off);
3238+
/* emit 2 nops that will be replaced with JE insn */
3239+
jmp_insn = prog;
3240+
emit_nops(&prog, 2);
3241+
3242+
if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, run_ctx_off, false,
3243+
ret_off, image, rw_image))
3244+
return -EINVAL;
3245+
3246+
jmp_insn[0] = X86_JNE;
3247+
jmp_insn[1] = prog - jmp_insn - 2;
3248+
}
3249+
3250+
*pprog = prog;
3251+
return 0;
3252+
}
3253+
31123254
/* mov rax, qword ptr [rbp - rounded_stack_depth - 8] */
31133255
#define LOAD_TRAMP_TAIL_CALL_CNT_PTR(stack) \
31143256
__LOAD_TCC_PTR(-round_up(stack, 8) - 8)
@@ -3181,8 +3323,9 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
31813323
{
31823324
int i, ret, nr_regs = m->nr_args, stack_size = 0;
31833325
int ret_off, regs_off, nregs_off, ip_off, run_ctx_off, arg_stack_off,
3184-
rbx_off;
3326+
rbx_off, sflags_off = 0, cookies_off;
31853327
struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY];
3328+
struct bpf_tramp_links *session = &tlinks[BPF_TRAMP_SESSION];
31863329
struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT];
31873330
struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN];
31883331
void *orig_call = func_addr;
@@ -3215,6 +3358,9 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
32153358
* RBP + 8 [ return address ]
32163359
* RBP + 0 [ RBP ]
32173360
*
3361+
* [ cookie ptr ] tracing session
3362+
* RBP - sflags_off [ session flags ] tracing session
3363+
*
32183364
* RBP - ret_off [ return value ] BPF_TRAMP_F_CALL_ORIG or
32193365
* BPF_TRAMP_F_RET_FENTRY_RET flags
32203366
*
@@ -3230,13 +3376,23 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
32303376
*
32313377
* RBP - run_ctx_off [ bpf_tramp_run_ctx ]
32323378
*
3379+
* [ session cookieN ]
3380+
* [ ... ]
3381+
* RBP - cookies_off [ session cookie1 ] tracing session
3382+
*
32333383
* [ stack_argN ] BPF_TRAMP_F_CALL_ORIG
32343384
* [ ... ]
32353385
* [ stack_arg2 ]
32363386
* RBP - arg_stack_off [ stack_arg1 ]
32373387
* RSP [ tail_call_cnt_ptr ] BPF_TRAMP_F_TAIL_CALL_CTX
32383388
*/
32393389

3390+
/* room for session flags and cookie ptr */
3391+
if (session->nr_links) {
3392+
stack_size += 8 + 8;
3393+
sflags_off = stack_size;
3394+
}
3395+
32403396
/* room for return value of orig_call or fentry prog */
32413397
save_ret = flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET);
32423398
if (save_ret)
@@ -3261,6 +3417,14 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
32613417
stack_size += (sizeof(struct bpf_tramp_run_ctx) + 7) & ~0x7;
32623418
run_ctx_off = stack_size;
32633419

3420+
if (session->nr_links) {
3421+
for (i = 0; i < session->nr_links; i++) {
3422+
if (session->links[i]->link.prog->call_session_cookie)
3423+
stack_size += 8;
3424+
}
3425+
}
3426+
cookies_off = stack_size;
3427+
32643428
if (nr_regs > 6 && (flags & BPF_TRAMP_F_CALL_ORIG)) {
32653429
/* the space that used to pass arguments on-stack */
32663430
stack_size += (nr_regs - get_nr_used_regs(m)) * 8;
@@ -3349,6 +3513,13 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
33493513
return -EINVAL;
33503514
}
33513515

3516+
if (session->nr_links) {
3517+
if (invoke_bpf_session_entry(m, &prog, session, regs_off,
3518+
run_ctx_off, ret_off, sflags_off,
3519+
cookies_off, image, rw_image))
3520+
return -EINVAL;
3521+
}
3522+
33523523
if (fmod_ret->nr_links) {
33533524
branches = kcalloc(fmod_ret->nr_links, sizeof(u8 *),
33543525
GFP_KERNEL);
@@ -3414,6 +3585,15 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
34143585
}
34153586
}
34163587

3588+
if (session->nr_links) {
3589+
if (invoke_bpf_session_exit(m, &prog, session, regs_off,
3590+
run_ctx_off, ret_off, sflags_off,
3591+
cookies_off, image, rw_image)) {
3592+
ret = -EINVAL;
3593+
goto cleanup;
3594+
}
3595+
}
3596+
34173597
if (flags & BPF_TRAMP_F_RESTORE_REGS)
34183598
restore_regs(m, &prog, regs_off);
34193599

@@ -3483,9 +3663,6 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
34833663
int ret;
34843664
u32 size = image_end - image;
34853665

3486-
if (tlinks[BPF_TRAMP_SESSION].nr_links)
3487-
return -EOPNOTSUPP;
3488-
34893666
/* rw_image doesn't need to be in module memory range, so we can
34903667
* use kvmalloc.
34913668
*/

0 commit comments

Comments
 (0)