Skip to content

Commit 59bb14b

Browse files
committed
Daniel Borkmann says: ==================== pull-request: bpf 2023-06-21 We've added 7 non-merge commits during the last 14 day(s) which contain a total of 7 files changed, 181 insertions(+), 15 deletions(-). The main changes are: 1) Fix a verifier id tracking issue with scalars upon spill, from Maxim Mikityanskiy. 2) Fix NULL dereference if an exception is generated while a BPF subprogram is running, from Krister Johansen. 3) Fix a BTF verification failure when compiling kernel with LLVM_IAS=0, from Florent Revest. 4) Fix expected_attach_type enforcement for kprobe_multi link, from Jiri Olsa. 5) Fix a bpf_jit_dump issue for x86_64 to pick the correct JITed image, from Yonghong Song. * tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: bpf: Force kprobe multi expected_attach_type for kprobe_multi link bpf/btf: Accept function names that contain dots selftests/bpf: add a test for subprogram extables bpf: ensure main program has an extable bpf: Fix a bpf_jit_dump issue for x86_64 with sysctl bpf_jit_enable. selftests/bpf: Add test cases to assert proper ID tracking on spill bpf: Fix verifier id tracking of scalars on spill ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents a129b41 + db8eae6 commit 59bb14b

File tree

7 files changed

+181
-15
lines changed

7 files changed

+181
-15
lines changed

arch/x86/net/bpf_jit_comp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2570,7 +2570,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
25702570
}
25712571

25722572
if (bpf_jit_enable > 1)
2573-
bpf_jit_dump(prog->len, proglen, pass + 1, image);
2573+
bpf_jit_dump(prog->len, proglen, pass + 1, rw_image);
25742574

25752575
if (image) {
25762576
if (!prog->is_func || extra_pass) {

kernel/bpf/btf.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -744,13 +744,12 @@ static bool btf_name_offset_valid(const struct btf *btf, u32 offset)
744744
return offset < btf->hdr.str_len;
745745
}
746746

747-
static bool __btf_name_char_ok(char c, bool first, bool dot_ok)
747+
static bool __btf_name_char_ok(char c, bool first)
748748
{
749749
if ((first ? !isalpha(c) :
750750
!isalnum(c)) &&
751751
c != '_' &&
752-
((c == '.' && !dot_ok) ||
753-
c != '.'))
752+
c != '.')
754753
return false;
755754
return true;
756755
}
@@ -767,38 +766,35 @@ static const char *btf_str_by_offset(const struct btf *btf, u32 offset)
767766
return NULL;
768767
}
769768

770-
static bool __btf_name_valid(const struct btf *btf, u32 offset, bool dot_ok)
769+
static bool __btf_name_valid(const struct btf *btf, u32 offset)
771770
{
772771
/* offset must be valid */
773772
const char *src = btf_str_by_offset(btf, offset);
774773
const char *src_limit;
775774

776-
if (!__btf_name_char_ok(*src, true, dot_ok))
775+
if (!__btf_name_char_ok(*src, true))
777776
return false;
778777

779778
/* set a limit on identifier length */
780779
src_limit = src + KSYM_NAME_LEN;
781780
src++;
782781
while (*src && src < src_limit) {
783-
if (!__btf_name_char_ok(*src, false, dot_ok))
782+
if (!__btf_name_char_ok(*src, false))
784783
return false;
785784
src++;
786785
}
787786

788787
return !*src;
789788
}
790789

791-
/* Only C-style identifier is permitted. This can be relaxed if
792-
* necessary.
793-
*/
794790
static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
795791
{
796-
return __btf_name_valid(btf, offset, false);
792+
return __btf_name_valid(btf, offset);
797793
}
798794

799795
static bool btf_name_valid_section(const struct btf *btf, u32 offset)
800796
{
801-
return __btf_name_valid(btf, offset, true);
797+
return __btf_name_valid(btf, offset);
802798
}
803799

804800
static const char *__btf_name_by_offset(const struct btf *btf, u32 offset)
@@ -4422,7 +4418,7 @@ static s32 btf_var_check_meta(struct btf_verifier_env *env,
44224418
}
44234419

44244420
if (!t->name_off ||
4425-
!__btf_name_valid(env->btf, t->name_off, true)) {
4421+
!__btf_name_valid(env->btf, t->name_off)) {
44264422
btf_verifier_log_type(env, t, "Invalid name");
44274423
return -EINVAL;
44284424
}

kernel/bpf/syscall.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3440,6 +3440,11 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
34403440
return prog->enforce_expected_attach_type &&
34413441
prog->expected_attach_type != attach_type ?
34423442
-EINVAL : 0;
3443+
case BPF_PROG_TYPE_KPROBE:
3444+
if (prog->expected_attach_type == BPF_TRACE_KPROBE_MULTI &&
3445+
attach_type != BPF_TRACE_KPROBE_MULTI)
3446+
return -EINVAL;
3447+
return 0;
34433448
default:
34443449
return 0;
34453450
}

kernel/bpf/verifier.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3868,6 +3868,9 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
38683868
return err;
38693869
}
38703870
save_register_state(state, spi, reg, size);
3871+
/* Break the relation on a narrowing spill. */
3872+
if (fls64(reg->umax_value) > BITS_PER_BYTE * size)
3873+
state->stack[spi].spilled_ptr.id = 0;
38713874
} else if (!reg && !(off % BPF_REG_SIZE) && is_bpf_st_mem(insn) &&
38723875
insn->imm != 0 && env->bpf_capable) {
38733876
struct bpf_reg_state fake_reg = {};
@@ -17214,9 +17217,10 @@ static int jit_subprogs(struct bpf_verifier_env *env)
1721417217
}
1721517218

1721617219
/* finally lock prog and jit images for all functions and
17217-
* populate kallsysm
17220+
* populate kallsysm. Begin at the first subprogram, since
17221+
* bpf_prog_load will add the kallsyms for the main program.
1721817222
*/
17219-
for (i = 0; i < env->subprog_cnt; i++) {
17223+
for (i = 1; i < env->subprog_cnt; i++) {
1722017224
bpf_prog_lock_ro(func[i]);
1722117225
bpf_prog_kallsyms_add(func[i]);
1722217226
}
@@ -17242,6 +17246,8 @@ static int jit_subprogs(struct bpf_verifier_env *env)
1724217246
prog->jited = 1;
1724317247
prog->bpf_func = func[0]->bpf_func;
1724417248
prog->jited_len = func[0]->jited_len;
17249+
prog->aux->extable = func[0]->aux->extable;
17250+
prog->aux->num_exentries = func[0]->aux->num_exentries;
1724517251
prog->aux->func = func;
1724617252
prog->aux->func_cnt = env->subprog_cnt;
1724717253
bpf_prog_jit_attempt_done(prog);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <test_progs.h>
4+
#include "test_subprogs_extable.skel.h"
5+
6+
void test_subprogs_extable(void)
7+
{
8+
const int read_sz = 456;
9+
struct test_subprogs_extable *skel;
10+
int err;
11+
12+
skel = test_subprogs_extable__open_and_load();
13+
if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
14+
return;
15+
16+
err = test_subprogs_extable__attach(skel);
17+
if (!ASSERT_OK(err, "skel_attach"))
18+
goto cleanup;
19+
20+
/* trigger tracepoint */
21+
ASSERT_OK(trigger_module_test_read(read_sz), "trigger_read");
22+
23+
ASSERT_NEQ(skel->bss->triggered, 0, "verify at least one program ran");
24+
25+
test_subprogs_extable__detach(skel);
26+
27+
cleanup:
28+
test_subprogs_extable__destroy(skel);
29+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include "vmlinux.h"
4+
#include <bpf/bpf_helpers.h>
5+
#include <bpf/bpf_tracing.h>
6+
7+
struct {
8+
__uint(type, BPF_MAP_TYPE_ARRAY);
9+
__uint(max_entries, 8);
10+
__type(key, __u32);
11+
__type(value, __u64);
12+
} test_array SEC(".maps");
13+
14+
unsigned int triggered;
15+
16+
static __u64 test_cb(struct bpf_map *map, __u32 *key, __u64 *val, void *data)
17+
{
18+
return 1;
19+
}
20+
21+
SEC("fexit/bpf_testmod_return_ptr")
22+
int BPF_PROG(handle_fexit_ret_subprogs, int arg, struct file *ret)
23+
{
24+
*(volatile long *)ret;
25+
*(volatile int *)&ret->f_mode;
26+
bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
27+
triggered++;
28+
return 0;
29+
}
30+
31+
SEC("fexit/bpf_testmod_return_ptr")
32+
int BPF_PROG(handle_fexit_ret_subprogs2, int arg, struct file *ret)
33+
{
34+
*(volatile long *)ret;
35+
*(volatile int *)&ret->f_mode;
36+
bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
37+
triggered++;
38+
return 0;
39+
}
40+
41+
SEC("fexit/bpf_testmod_return_ptr")
42+
int BPF_PROG(handle_fexit_ret_subprogs3, int arg, struct file *ret)
43+
{
44+
*(volatile long *)ret;
45+
*(volatile int *)&ret->f_mode;
46+
bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
47+
triggered++;
48+
return 0;
49+
}
50+
51+
char _license[] SEC("license") = "GPL";

tools/testing/selftests/bpf/progs/verifier_spill_fill.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,4 +371,83 @@ __naked void and_then_at_fp_8(void)
371371
" ::: __clobber_all);
372372
}
373373

374+
SEC("xdp")
375+
__description("32-bit spill of 64-bit reg should clear ID")
376+
__failure __msg("math between ctx pointer and 4294967295 is not allowed")
377+
__naked void spill_32bit_of_64bit_fail(void)
378+
{
379+
asm volatile (" \
380+
r6 = r1; \
381+
/* Roll one bit to force the verifier to track both branches. */\
382+
call %[bpf_get_prandom_u32]; \
383+
r0 &= 0x8; \
384+
/* Put a large number into r1. */ \
385+
r1 = 0xffffffff; \
386+
r1 <<= 32; \
387+
r1 += r0; \
388+
/* Assign an ID to r1. */ \
389+
r2 = r1; \
390+
/* 32-bit spill r1 to stack - should clear the ID! */\
391+
*(u32*)(r10 - 8) = r1; \
392+
/* 32-bit fill r2 from stack. */ \
393+
r2 = *(u32*)(r10 - 8); \
394+
/* Compare r2 with another register to trigger find_equal_scalars.\
395+
* Having one random bit is important here, otherwise the verifier cuts\
396+
* the corners. If the ID was mistakenly preserved on spill, this would\
397+
* cause the verifier to think that r1 is also equal to zero in one of\
398+
* the branches, and equal to eight on the other branch.\
399+
*/ \
400+
r3 = 0; \
401+
if r2 != r3 goto l0_%=; \
402+
l0_%=: r1 >>= 32; \
403+
/* At this point, if the verifier thinks that r1 is 0, an out-of-bounds\
404+
* read will happen, because it actually contains 0xffffffff.\
405+
*/ \
406+
r6 += r1; \
407+
r0 = *(u32*)(r6 + 0); \
408+
exit; \
409+
" :
410+
: __imm(bpf_get_prandom_u32)
411+
: __clobber_all);
412+
}
413+
414+
SEC("xdp")
415+
__description("16-bit spill of 32-bit reg should clear ID")
416+
__failure __msg("dereference of modified ctx ptr R6 off=65535 disallowed")
417+
__naked void spill_16bit_of_32bit_fail(void)
418+
{
419+
asm volatile (" \
420+
r6 = r1; \
421+
/* Roll one bit to force the verifier to track both branches. */\
422+
call %[bpf_get_prandom_u32]; \
423+
r0 &= 0x8; \
424+
/* Put a large number into r1. */ \
425+
w1 = 0xffff0000; \
426+
r1 += r0; \
427+
/* Assign an ID to r1. */ \
428+
r2 = r1; \
429+
/* 16-bit spill r1 to stack - should clear the ID! */\
430+
*(u16*)(r10 - 8) = r1; \
431+
/* 16-bit fill r2 from stack. */ \
432+
r2 = *(u16*)(r10 - 8); \
433+
/* Compare r2 with another register to trigger find_equal_scalars.\
434+
* Having one random bit is important here, otherwise the verifier cuts\
435+
* the corners. If the ID was mistakenly preserved on spill, this would\
436+
* cause the verifier to think that r1 is also equal to zero in one of\
437+
* the branches, and equal to eight on the other branch.\
438+
*/ \
439+
r3 = 0; \
440+
if r2 != r3 goto l0_%=; \
441+
l0_%=: r1 >>= 16; \
442+
/* At this point, if the verifier thinks that r1 is 0, an out-of-bounds\
443+
* read will happen, because it actually contains 0xffff.\
444+
*/ \
445+
r6 += r1; \
446+
r0 = *(u32*)(r6 + 0); \
447+
exit; \
448+
" :
449+
: __imm(bpf_get_prandom_u32)
450+
: __clobber_all);
451+
}
452+
374453
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)