Skip to content

Commit 52531b3

Browse files
image-dragonKernel Patches Daemon
authored andcommitted
bpf: implement "jmp" mode for trampoline
Implement the "jmp" mode for the bpf trampoline. For the ftrace_managed case, we need only to set the FTRACE_OPS_FL_JMP on the tr->fops if "jmp" is needed. For the bpf poke case, we will check the origin poke type with the "origin_flags", and current poke type with "tr->flags". The function bpf_trampoline_update_fentry() is introduced to do the job. The "jmp" mode will only be enabled with CONFIG_DYNAMIC_FTRACE_WITH_JMP enabled and BPF_TRAMP_F_SHARE_IPMODIFY is not set. With BPF_TRAMP_F_SHARE_IPMODIFY, we need to get the origin call ip from the stack, so we can't use the "jmp" mode. Signed-off-by: Menglong Dong <[email protected]>
1 parent 820987b commit 52531b3

File tree

1 file changed

+58
-17
lines changed

1 file changed

+58
-17
lines changed

kernel/bpf/trampoline.c

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -175,24 +175,42 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
175175
return tr;
176176
}
177177

178-
static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
178+
static int bpf_trampoline_update_fentry(struct bpf_trampoline *tr, u32 orig_flags,
179+
void *old_addr, void *new_addr)
179180
{
181+
enum bpf_text_poke_type new_t = BPF_MOD_CALL, old_t = BPF_MOD_CALL;
180182
void *ip = tr->func.addr;
183+
184+
if (!new_addr)
185+
new_t = BPF_MOD_NOP;
186+
else if (bpf_trampoline_use_jmp(tr->flags))
187+
new_t = BPF_MOD_JUMP;
188+
189+
if (!old_addr)
190+
old_t = BPF_MOD_NOP;
191+
else if (bpf_trampoline_use_jmp(orig_flags))
192+
old_t = BPF_MOD_JUMP;
193+
194+
return bpf_arch_text_poke(ip, old_t, new_t, old_addr, new_addr);
195+
}
196+
197+
static int unregister_fentry(struct bpf_trampoline *tr, u32 orig_flags,
198+
void *old_addr)
199+
{
181200
int ret;
182201

183202
if (tr->func.ftrace_managed)
184203
ret = unregister_ftrace_direct(tr->fops, (long)old_addr, false);
185204
else
186-
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, BPF_MOD_NOP,
187-
old_addr, NULL);
205+
ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr, NULL);
188206

189207
return ret;
190208
}
191209

192-
static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_addr,
210+
static int modify_fentry(struct bpf_trampoline *tr, u32 orig_flags,
211+
void *old_addr, void *new_addr,
193212
bool lock_direct_mutex)
194213
{
195-
void *ip = tr->func.addr;
196214
int ret;
197215

198216
if (tr->func.ftrace_managed) {
@@ -201,10 +219,8 @@ static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_ad
201219
else
202220
ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
203221
} else {
204-
ret = bpf_arch_text_poke(ip,
205-
old_addr ? BPF_MOD_CALL : BPF_MOD_NOP,
206-
new_addr ? BPF_MOD_CALL : BPF_MOD_NOP,
207-
old_addr, new_addr);
222+
ret = bpf_trampoline_update_fentry(tr, orig_flags, old_addr,
223+
new_addr);
208224
}
209225
return ret;
210226
}
@@ -229,8 +245,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
229245
return ret;
230246
ret = register_ftrace_direct(tr->fops, (long)new_addr);
231247
} else {
232-
ret = bpf_arch_text_poke(ip, BPF_MOD_NOP, BPF_MOD_CALL,
233-
NULL, new_addr);
248+
ret = bpf_trampoline_update_fentry(tr, 0, NULL, new_addr);
234249
}
235250

236251
return ret;
@@ -416,7 +431,7 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
416431
return PTR_ERR(tlinks);
417432

418433
if (total == 0) {
419-
err = unregister_fentry(tr, tr->cur_image->image);
434+
err = unregister_fentry(tr, orig_flags, tr->cur_image->image);
420435
bpf_tramp_image_put(tr->cur_image);
421436
tr->cur_image = NULL;
422437
goto out;
@@ -440,9 +455,20 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
440455

441456
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
442457
again:
443-
if ((tr->flags & BPF_TRAMP_F_SHARE_IPMODIFY) &&
444-
(tr->flags & BPF_TRAMP_F_CALL_ORIG))
445-
tr->flags |= BPF_TRAMP_F_ORIG_STACK;
458+
if (tr->flags & BPF_TRAMP_F_CALL_ORIG) {
459+
if (tr->flags & BPF_TRAMP_F_SHARE_IPMODIFY) {
460+
/* The BPF_TRAMP_F_SKIP_FRAME can be cleared in the
461+
* first try, reset it in the second try.
462+
*/
463+
tr->flags |= BPF_TRAMP_F_ORIG_STACK | BPF_TRAMP_F_SKIP_FRAME;
464+
} else if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_JMP)) {
465+
/* Use "jmp" instead of "call" for the trampoline
466+
* in the origin call case, and we don't need to
467+
* skip the frame.
468+
*/
469+
tr->flags &= ~BPF_TRAMP_F_SKIP_FRAME;
470+
}
471+
}
446472
#endif
447473

448474
size = arch_bpf_trampoline_size(&tr->func.model, tr->flags,
@@ -473,10 +499,18 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
473499
if (err)
474500
goto out_free;
475501

502+
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP
503+
if (bpf_trampoline_use_jmp(tr->flags))
504+
tr->fops->flags |= FTRACE_OPS_FL_JMP;
505+
else
506+
tr->fops->flags &= ~FTRACE_OPS_FL_JMP;
507+
#endif
508+
476509
WARN_ON(tr->cur_image && total == 0);
477510
if (tr->cur_image)
478511
/* progs already running at this address */
479-
err = modify_fentry(tr, tr->cur_image->image, im->image, lock_direct_mutex);
512+
err = modify_fentry(tr, orig_flags, tr->cur_image->image,
513+
im->image, lock_direct_mutex);
480514
else
481515
/* first time registering */
482516
err = register_fentry(tr, im->image);
@@ -499,8 +533,15 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
499533
tr->cur_image = im;
500534
out:
501535
/* If any error happens, restore previous flags */
502-
if (err)
536+
if (err) {
503537
tr->flags = orig_flags;
538+
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_JMP
539+
if (bpf_trampoline_use_jmp(tr->flags))
540+
tr->fops->flags |= FTRACE_OPS_FL_JMP;
541+
else
542+
tr->fops->flags &= ~FTRACE_OPS_FL_JMP;
543+
#endif
544+
}
504545
kfree(tlinks);
505546
return err;
506547

0 commit comments

Comments
 (0)