Skip to content

Commit eb415c9

Browse files
author
Alexei Starovoitov
committed
Merge branch 'bpf_line_info-in-verifier'
Martin Lau says: ==================== This patch set provides bpf_line_info during the verifier's verbose log. Please see individual patch for details. ==================== Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2 parents 28c1272 + d9762e8 commit eb415c9

File tree

4 files changed

+92
-19
lines changed

4 files changed

+92
-19
lines changed

include/linux/bpf_verifier.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ struct bpf_verifier_env {
224224
bool allow_ptr_leaks;
225225
bool seen_direct_write;
226226
struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
227+
const struct bpf_line_info *prev_linfo;
227228
struct bpf_verifier_log log;
228229
struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1];
229230
u32 subprog_cnt;

include/linux/btf.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,
4646
struct seq_file *m);
4747
int btf_get_fd_by_id(u32 id);
4848
u32 btf_id(const struct btf *btf);
49-
bool btf_name_offset_valid(const struct btf *btf, u32 offset);
5049
bool btf_type_is_reg_int(const struct btf_type *t, u32 expected_size);
5150

5251
#ifdef CONFIG_BPF_SYSCALL

kernel/bpf/btf.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
474474
return !*src;
475475
}
476476

477-
const char *btf_name_by_offset(const struct btf *btf, u32 offset)
477+
static const char *__btf_name_by_offset(const struct btf *btf, u32 offset)
478478
{
479479
if (!offset)
480480
return "(anon)";
@@ -484,6 +484,14 @@ const char *btf_name_by_offset(const struct btf *btf, u32 offset)
484484
return "(invalid-name-offset)";
485485
}
486486

487+
const char *btf_name_by_offset(const struct btf *btf, u32 offset)
488+
{
489+
if (offset < btf->hdr.str_len)
490+
return &btf->strings[offset];
491+
492+
return NULL;
493+
}
494+
487495
const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id)
488496
{
489497
if (type_id > btf->nr_types)
@@ -576,7 +584,7 @@ __printf(4, 5) static void __btf_verifier_log_type(struct btf_verifier_env *env,
576584
__btf_verifier_log(log, "[%u] %s %s%s",
577585
env->log_type_id,
578586
btf_kind_str[kind],
579-
btf_name_by_offset(btf, t->name_off),
587+
__btf_name_by_offset(btf, t->name_off),
580588
log_details ? " " : "");
581589

582590
if (log_details)
@@ -620,7 +628,7 @@ static void btf_verifier_log_member(struct btf_verifier_env *env,
620628
btf_verifier_log_type(env, struct_type, NULL);
621629

622630
__btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u",
623-
btf_name_by_offset(btf, member->name_off),
631+
__btf_name_by_offset(btf, member->name_off),
624632
member->type, member->offset);
625633

626634
if (fmt && *fmt) {
@@ -1872,7 +1880,7 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
18721880

18731881

18741882
btf_verifier_log(env, "\t%s val=%d\n",
1875-
btf_name_by_offset(btf, enums[i].name_off),
1883+
__btf_name_by_offset(btf, enums[i].name_off),
18761884
enums[i].val);
18771885
}
18781886

@@ -1896,7 +1904,8 @@ static void btf_enum_seq_show(const struct btf *btf, const struct btf_type *t,
18961904
for (i = 0; i < nr_enums; i++) {
18971905
if (v == enums[i].val) {
18981906
seq_printf(m, "%s",
1899-
btf_name_by_offset(btf, enums[i].name_off));
1907+
__btf_name_by_offset(btf,
1908+
enums[i].name_off));
19001909
return;
19011910
}
19021911
}
@@ -1954,20 +1963,20 @@ static void btf_func_proto_log(struct btf_verifier_env *env,
19541963
}
19551964

19561965
btf_verifier_log(env, "%u %s", args[0].type,
1957-
btf_name_by_offset(env->btf,
1958-
args[0].name_off));
1966+
__btf_name_by_offset(env->btf,
1967+
args[0].name_off));
19591968
for (i = 1; i < nr_args - 1; i++)
19601969
btf_verifier_log(env, ", %u %s", args[i].type,
1961-
btf_name_by_offset(env->btf,
1962-
args[i].name_off));
1970+
__btf_name_by_offset(env->btf,
1971+
args[i].name_off));
19631972

19641973
if (nr_args > 1) {
19651974
const struct btf_param *last_arg = &args[nr_args - 1];
19661975

19671976
if (last_arg->type)
19681977
btf_verifier_log(env, ", %u %s", last_arg->type,
1969-
btf_name_by_offset(env->btf,
1970-
last_arg->name_off));
1978+
__btf_name_by_offset(env->btf,
1979+
last_arg->name_off));
19711980
else
19721981
btf_verifier_log(env, ", vararg");
19731982
}

kernel/bpf/verifier.c

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/bsearch.h>
2727
#include <linux/sort.h>
2828
#include <linux/perf_event.h>
29+
#include <linux/ctype.h>
2930

3031
#include "disasm.h"
3132

@@ -216,6 +217,27 @@ struct bpf_call_arg_meta {
216217

217218
static DEFINE_MUTEX(bpf_verifier_lock);
218219

220+
static const struct bpf_line_info *
221+
find_linfo(const struct bpf_verifier_env *env, u32 insn_off)
222+
{
223+
const struct bpf_line_info *linfo;
224+
const struct bpf_prog *prog;
225+
u32 i, nr_linfo;
226+
227+
prog = env->prog;
228+
nr_linfo = prog->aux->nr_linfo;
229+
230+
if (!nr_linfo || insn_off >= prog->len)
231+
return NULL;
232+
233+
linfo = prog->aux->linfo;
234+
for (i = 1; i < nr_linfo; i++)
235+
if (insn_off < linfo[i].insn_off)
236+
break;
237+
238+
return &linfo[i - 1];
239+
}
240+
219241
void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt,
220242
va_list args)
221243
{
@@ -266,6 +288,42 @@ __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...)
266288
va_end(args);
267289
}
268290

291+
static const char *ltrim(const char *s)
292+
{
293+
while (isspace(*s))
294+
s++;
295+
296+
return s;
297+
}
298+
299+
__printf(3, 4) static void verbose_linfo(struct bpf_verifier_env *env,
300+
u32 insn_off,
301+
const char *prefix_fmt, ...)
302+
{
303+
const struct bpf_line_info *linfo;
304+
305+
if (!bpf_verifier_log_needed(&env->log))
306+
return;
307+
308+
linfo = find_linfo(env, insn_off);
309+
if (!linfo || linfo == env->prev_linfo)
310+
return;
311+
312+
if (prefix_fmt) {
313+
va_list args;
314+
315+
va_start(args, prefix_fmt);
316+
bpf_verifier_vlog(&env->log, prefix_fmt, args);
317+
va_end(args);
318+
}
319+
320+
verbose(env, "%s\n",
321+
ltrim(btf_name_by_offset(env->prog->aux->btf,
322+
linfo->line_off)));
323+
324+
env->prev_linfo = linfo;
325+
}
326+
269327
static bool type_is_pkt_pointer(enum bpf_reg_type type)
270328
{
271329
return type == PTR_TO_PACKET ||
@@ -4561,6 +4619,7 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env)
45614619
return 0;
45624620

45634621
if (w < 0 || w >= env->prog->len) {
4622+
verbose_linfo(env, t, "%d: ", t);
45644623
verbose(env, "jump out of range from insn %d to %d\n", t, w);
45654624
return -EINVAL;
45664625
}
@@ -4578,6 +4637,8 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env)
45784637
insn_stack[cur_stack++] = w;
45794638
return 1;
45804639
} else if ((insn_state[w] & 0xF0) == DISCOVERED) {
4640+
verbose_linfo(env, t, "%d: ", t);
4641+
verbose_linfo(env, w, "%d: ", w);
45814642
verbose(env, "back-edge from insn %d to %d\n", t, w);
45824643
return -EINVAL;
45834644
} else if (insn_state[w] == EXPLORED) {
@@ -4600,10 +4661,6 @@ static int check_cfg(struct bpf_verifier_env *env)
46004661
int ret = 0;
46014662
int i, t;
46024663

4603-
ret = check_subprogs(env);
4604-
if (ret < 0)
4605-
return ret;
4606-
46074664
insn_state = kcalloc(insn_cnt, sizeof(int), GFP_KERNEL);
46084665
if (!insn_state)
46094666
return -ENOMEM;
@@ -4910,8 +4967,8 @@ static int check_btf_line(struct bpf_verifier_env *env,
49104967
goto err_free;
49114968
}
49124969

4913-
if (!btf_name_offset_valid(btf, linfo[i].line_off) ||
4914-
!btf_name_offset_valid(btf, linfo[i].file_name_off)) {
4970+
if (!btf_name_by_offset(btf, linfo[i].line_off) ||
4971+
!btf_name_by_offset(btf, linfo[i].file_name_off)) {
49154972
verbose(env, "Invalid line_info[%u].line_off or .file_name_off\n", i);
49164973
err = -EINVAL;
49174974
goto err_free;
@@ -5448,6 +5505,8 @@ static int do_check(struct bpf_verifier_env *env)
54485505
int insn_processed = 0;
54495506
bool do_print_state = false;
54505507

5508+
env->prev_linfo = NULL;
5509+
54515510
state = kzalloc(sizeof(struct bpf_verifier_state), GFP_KERNEL);
54525511
if (!state)
54535512
return -ENOMEM;
@@ -5521,6 +5580,7 @@ static int do_check(struct bpf_verifier_env *env)
55215580
.private_data = env,
55225581
};
55235582

5583+
verbose_linfo(env, insn_idx, "; ");
55245584
verbose(env, "%d: ", insn_idx);
55255585
print_bpf_insn(&cbs, insn, env->allow_ptr_leaks);
55265586
}
@@ -6755,14 +6815,18 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
67556815

67566816
env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);
67576817

6758-
ret = check_cfg(env);
6818+
ret = check_subprogs(env);
67596819
if (ret < 0)
67606820
goto skip_full_check;
67616821

67626822
ret = check_btf_info(env, attr, uattr);
67636823
if (ret < 0)
67646824
goto skip_full_check;
67656825

6826+
ret = check_cfg(env);
6827+
if (ret < 0)
6828+
goto skip_full_check;
6829+
67666830
ret = do_check(env);
67676831
if (env->cur_state) {
67686832
free_verifier_state(env->cur_state, true);

0 commit comments

Comments
 (0)