Skip to content

Commit 1022a54

Browse files
liu-song-6Alexei Starovoitov
authored andcommitted
bpf, x86_64: Use bpf_jit_binary_pack_alloc
Use bpf_jit_binary_pack_alloc in x86_64 jit. The jit engine first writes the program to the rw buffer. When the jit is done, the program is copied to the final location with bpf_jit_binary_pack_finalize. Note that we need to do bpf_tail_call_direct_fixup after finalize. Therefore, the text_live = false logic in __bpf_arch_text_poke is no longer needed. Signed-off-by: Song Liu <songliubraving@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20220204185742.271030-10-song@kernel.org
1 parent 33c9805 commit 1022a54

File tree

1 file changed

+31
-27
lines changed

1 file changed

+31
-27
lines changed

arch/x86/net/bpf_jit_comp.c

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,7 @@ static int emit_jump(u8 **pprog, void *func, void *ip)
330330
}
331331

332332
static int __bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
333-
void *old_addr, void *new_addr,
334-
const bool text_live)
333+
void *old_addr, void *new_addr)
335334
{
336335
const u8 *nop_insn = x86_nops[5];
337336
u8 old_insn[X86_PATCH_SIZE];
@@ -365,10 +364,7 @@ static int __bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
365364
goto out;
366365
ret = 1;
367366
if (memcmp(ip, new_insn, X86_PATCH_SIZE)) {
368-
if (text_live)
369-
text_poke_bp(ip, new_insn, X86_PATCH_SIZE, NULL);
370-
else
371-
memcpy(ip, new_insn, X86_PATCH_SIZE);
367+
text_poke_bp(ip, new_insn, X86_PATCH_SIZE, NULL);
372368
ret = 0;
373369
}
374370
out:
@@ -384,7 +380,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
384380
/* BPF poking in modules is not supported */
385381
return -EINVAL;
386382

387-
return __bpf_arch_text_poke(ip, t, old_addr, new_addr, true);
383+
return __bpf_arch_text_poke(ip, t, old_addr, new_addr);
388384
}
389385

390386
#define EMIT_LFENCE() EMIT3(0x0F, 0xAE, 0xE8)
@@ -558,24 +554,15 @@ static void bpf_tail_call_direct_fixup(struct bpf_prog *prog)
558554
mutex_lock(&array->aux->poke_mutex);
559555
target = array->ptrs[poke->tail_call.key];
560556
if (target) {
561-
/* Plain memcpy is used when image is not live yet
562-
* and still not locked as read-only. Once poke
563-
* location is active (poke->tailcall_target_stable),
564-
* any parallel bpf_arch_text_poke() might occur
565-
* still on the read-write image until we finally
566-
* locked it as read-only. Both modifications on
567-
* the given image are under text_mutex to avoid
568-
* interference.
569-
*/
570557
ret = __bpf_arch_text_poke(poke->tailcall_target,
571558
BPF_MOD_JUMP, NULL,
572559
(u8 *)target->bpf_func +
573-
poke->adj_off, false);
560+
poke->adj_off);
574561
BUG_ON(ret < 0);
575562
ret = __bpf_arch_text_poke(poke->tailcall_bypass,
576563
BPF_MOD_JUMP,
577564
(u8 *)poke->tailcall_target +
578-
X86_PATCH_SIZE, NULL, false);
565+
X86_PATCH_SIZE, NULL);
579566
BUG_ON(ret < 0);
580567
}
581568
WRITE_ONCE(poke->tailcall_target_stable, true);
@@ -866,7 +853,7 @@ static void emit_nops(u8 **pprog, int len)
866853

867854
#define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))
868855

869-
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
856+
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
870857
int oldproglen, struct jit_context *ctx, bool jmp_padding)
871858
{
872859
bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
@@ -893,8 +880,8 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
893880
push_callee_regs(&prog, callee_regs_used);
894881

895882
ilen = prog - temp;
896-
if (image)
897-
memcpy(image + proglen, temp, ilen);
883+
if (rw_image)
884+
memcpy(rw_image + proglen, temp, ilen);
898885
proglen += ilen;
899886
addrs[0] = proglen;
900887
prog = temp;
@@ -1323,6 +1310,9 @@ st: if (is_imm8(insn->off))
13231310
pr_err("extable->insn doesn't fit into 32-bit\n");
13241311
return -EFAULT;
13251312
}
1313+
/* switch ex to rw buffer for writes */
1314+
ex = (void *)rw_image + ((void *)ex - (void *)image);
1315+
13261316
ex->insn = delta;
13271317

13281318
ex->data = EX_TYPE_BPF;
@@ -1705,7 +1695,7 @@ st: if (is_imm8(insn->off))
17051695
pr_err("bpf_jit: fatal error\n");
17061696
return -EFAULT;
17071697
}
1708-
memcpy(image + proglen, temp, ilen);
1698+
memcpy(rw_image + proglen, temp, ilen);
17091699
}
17101700
proglen += ilen;
17111701
addrs[i] = proglen;
@@ -2246,6 +2236,7 @@ int arch_prepare_bpf_dispatcher(void *image, s64 *funcs, int num_funcs)
22462236
}
22472237

22482238
struct x64_jit_data {
2239+
struct bpf_binary_header *rw_header;
22492240
struct bpf_binary_header *header;
22502241
int *addrs;
22512242
u8 *image;
@@ -2258,6 +2249,7 @@ struct x64_jit_data {
22582249

22592250
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
22602251
{
2252+
struct bpf_binary_header *rw_header = NULL;
22612253
struct bpf_binary_header *header = NULL;
22622254
struct bpf_prog *tmp, *orig_prog = prog;
22632255
struct x64_jit_data *jit_data;
@@ -2266,6 +2258,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
22662258
bool tmp_blinded = false;
22672259
bool extra_pass = false;
22682260
bool padding = false;
2261+
u8 *rw_image = NULL;
22692262
u8 *image = NULL;
22702263
int *addrs;
22712264
int pass;
@@ -2301,6 +2294,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
23012294
oldproglen = jit_data->proglen;
23022295
image = jit_data->image;
23032296
header = jit_data->header;
2297+
rw_header = jit_data->rw_header;
2298+
rw_image = (void *)rw_header + ((void *)image - (void *)header);
23042299
extra_pass = true;
23052300
padding = true;
23062301
goto skip_init_addrs;
@@ -2331,12 +2326,12 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
23312326
for (pass = 0; pass < MAX_PASSES || image; pass++) {
23322327
if (!padding && pass >= PADDING_PASSES)
23332328
padding = true;
2334-
proglen = do_jit(prog, addrs, image, oldproglen, &ctx, padding);
2329+
proglen = do_jit(prog, addrs, image, rw_image, oldproglen, &ctx, padding);
23352330
if (proglen <= 0) {
23362331
out_image:
23372332
image = NULL;
23382333
if (header)
2339-
bpf_jit_binary_free(header);
2334+
bpf_jit_binary_pack_free(header, rw_header);
23402335
prog = orig_prog;
23412336
goto out_addrs;
23422337
}
@@ -2360,8 +2355,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
23602355
sizeof(struct exception_table_entry);
23612356

23622357
/* allocate module memory for x86 insns and extable */
2363-
header = bpf_jit_binary_alloc(roundup(proglen, align) + extable_size,
2364-
&image, align, jit_fill_hole);
2358+
header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
2359+
&image, align, &rw_header, &rw_image,
2360+
jit_fill_hole);
23652361
if (!header) {
23662362
prog = orig_prog;
23672363
goto out_addrs;
@@ -2377,14 +2373,22 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
23772373

23782374
if (image) {
23792375
if (!prog->is_func || extra_pass) {
2376+
/*
2377+
* bpf_jit_binary_pack_finalize fails in two scenarios:
2378+
* 1) header is not pointing to proper module memory;
2379+
* 2) the arch doesn't support bpf_arch_text_copy().
2380+
*
2381+
* Both cases are serious bugs that we should not continue.
2382+
*/
2383+
BUG_ON(bpf_jit_binary_pack_finalize(prog, header, rw_header));
23802384
bpf_tail_call_direct_fixup(prog);
2381-
bpf_jit_binary_lock_ro(header);
23822385
} else {
23832386
jit_data->addrs = addrs;
23842387
jit_data->ctx = ctx;
23852388
jit_data->proglen = proglen;
23862389
jit_data->image = image;
23872390
jit_data->header = header;
2391+
jit_data->rw_header = rw_header;
23882392
}
23892393
prog->bpf_func = (void *)image;
23902394
prog->jited = 1;

0 commit comments

Comments
 (0)