diff options
Diffstat (limited to 'kernel/bpf')
| -rw-r--r-- | kernel/bpf/btf.c | 31 | ||||
| -rw-r--r-- | kernel/bpf/verifier.c | 78 |
2 files changed, 91 insertions, 18 deletions
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 1545ddfb6fa5..8fa0bf1c33fd 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c | |||
| @@ -474,7 +474,7 @@ static bool btf_name_valid_identifier(const struct btf *btf, u32 offset) | |||
| 474 | return !*src; | 474 | return !*src; |
| 475 | } | 475 | } |
| 476 | 476 | ||
| 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) |
| 478 | { | 478 | { |
| 479 | if (!offset) | 479 | if (!offset) |
| 480 | return "(anon)"; | 480 | return "(anon)"; |
| @@ -484,6 +484,14 @@ const char *btf_name_by_offset(const struct btf *btf, u32 offset) | |||
| 484 | return "(invalid-name-offset)"; | 484 | return "(invalid-name-offset)"; |
| 485 | } | 485 | } |
| 486 | 486 | ||
| 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 | |||
| 487 | const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id) | 495 | const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id) |
| 488 | { | 496 | { |
| 489 | if (type_id > btf->nr_types) | 497 | if (type_id > btf->nr_types) |
| @@ -576,7 +584,7 @@ __printf(4, 5) static void __btf_verifier_log_type(struct btf_verifier_env *env, | |||
| 576 | __btf_verifier_log(log, "[%u] %s %s%s", | 584 | __btf_verifier_log(log, "[%u] %s %s%s", |
| 577 | env->log_type_id, | 585 | env->log_type_id, |
| 578 | btf_kind_str[kind], | 586 | btf_kind_str[kind], |
| 579 | btf_name_by_offset(btf, t->name_off), | 587 | __btf_name_by_offset(btf, t->name_off), |
| 580 | log_details ? " " : ""); | 588 | log_details ? " " : ""); |
| 581 | 589 | ||
| 582 | if (log_details) | 590 | if (log_details) |
| @@ -620,7 +628,7 @@ static void btf_verifier_log_member(struct btf_verifier_env *env, | |||
| 620 | btf_verifier_log_type(env, struct_type, NULL); | 628 | btf_verifier_log_type(env, struct_type, NULL); |
| 621 | 629 | ||
| 622 | __btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u", | 630 | __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), |
| 624 | member->type, member->offset); | 632 | member->type, member->offset); |
| 625 | 633 | ||
| 626 | if (fmt && *fmt) { | 634 | if (fmt && *fmt) { |
| @@ -1872,7 +1880,7 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env, | |||
| 1872 | 1880 | ||
| 1873 | 1881 | ||
| 1874 | btf_verifier_log(env, "\t%s val=%d\n", | 1882 | 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), |
| 1876 | enums[i].val); | 1884 | enums[i].val); |
| 1877 | } | 1885 | } |
| 1878 | 1886 | ||
| @@ -1896,7 +1904,8 @@ static void btf_enum_seq_show(const struct btf *btf, const struct btf_type *t, | |||
| 1896 | for (i = 0; i < nr_enums; i++) { | 1904 | for (i = 0; i < nr_enums; i++) { |
| 1897 | if (v == enums[i].val) { | 1905 | if (v == enums[i].val) { |
| 1898 | seq_printf(m, "%s", | 1906 | 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)); | ||
| 1900 | return; | 1909 | return; |
| 1901 | } | 1910 | } |
| 1902 | } | 1911 | } |
| @@ -1954,20 +1963,20 @@ static void btf_func_proto_log(struct btf_verifier_env *env, | |||
| 1954 | } | 1963 | } |
| 1955 | 1964 | ||
| 1956 | btf_verifier_log(env, "%u %s", args[0].type, | 1965 | btf_verifier_log(env, "%u %s", args[0].type, |
| 1957 | btf_name_by_offset(env->btf, | 1966 | __btf_name_by_offset(env->btf, |
| 1958 | args[0].name_off)); | 1967 | args[0].name_off)); |
| 1959 | for (i = 1; i < nr_args - 1; i++) | 1968 | for (i = 1; i < nr_args - 1; i++) |
| 1960 | btf_verifier_log(env, ", %u %s", args[i].type, | 1969 | btf_verifier_log(env, ", %u %s", args[i].type, |
| 1961 | btf_name_by_offset(env->btf, | 1970 | __btf_name_by_offset(env->btf, |
| 1962 | args[i].name_off)); | 1971 | args[i].name_off)); |
| 1963 | 1972 | ||
| 1964 | if (nr_args > 1) { | 1973 | if (nr_args > 1) { |
| 1965 | const struct btf_param *last_arg = &args[nr_args - 1]; | 1974 | const struct btf_param *last_arg = &args[nr_args - 1]; |
| 1966 | 1975 | ||
| 1967 | if (last_arg->type) | 1976 | if (last_arg->type) |
| 1968 | btf_verifier_log(env, ", %u %s", last_arg->type, | 1977 | btf_verifier_log(env, ", %u %s", last_arg->type, |
| 1969 | btf_name_by_offset(env->btf, | 1978 | __btf_name_by_offset(env->btf, |
| 1970 | last_arg->name_off)); | 1979 | last_arg->name_off)); |
| 1971 | else | 1980 | else |
| 1972 | btf_verifier_log(env, ", vararg"); | 1981 | btf_verifier_log(env, ", vararg"); |
| 1973 | } | 1982 | } |
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 8b511a4fe84a..ba8e3134bbc2 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/bsearch.h> | 26 | #include <linux/bsearch.h> |
| 27 | #include <linux/sort.h> | 27 | #include <linux/sort.h> |
| 28 | #include <linux/perf_event.h> | 28 | #include <linux/perf_event.h> |
| 29 | #include <linux/ctype.h> | ||
| 29 | 30 | ||
| 30 | #include "disasm.h" | 31 | #include "disasm.h" |
| 31 | 32 | ||
| @@ -216,6 +217,27 @@ struct bpf_call_arg_meta { | |||
| 216 | 217 | ||
| 217 | static DEFINE_MUTEX(bpf_verifier_lock); | 218 | static DEFINE_MUTEX(bpf_verifier_lock); |
| 218 | 219 | ||
| 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 | |||
| 219 | void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt, | 241 | void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt, |
| 220 | va_list args) | 242 | va_list args) |
| 221 | { | 243 | { |
| @@ -266,6 +288,42 @@ __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...) | |||
| 266 | va_end(args); | 288 | va_end(args); |
| 267 | } | 289 | } |
| 268 | 290 | ||
| 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 | |||
| 269 | static bool type_is_pkt_pointer(enum bpf_reg_type type) | 327 | static bool type_is_pkt_pointer(enum bpf_reg_type type) |
| 270 | { | 328 | { |
| 271 | return type == PTR_TO_PACKET || | 329 | return type == PTR_TO_PACKET || |
| @@ -4561,6 +4619,7 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env) | |||
| 4561 | return 0; | 4619 | return 0; |
| 4562 | 4620 | ||
| 4563 | if (w < 0 || w >= env->prog->len) { | 4621 | if (w < 0 || w >= env->prog->len) { |
| 4622 | verbose_linfo(env, t, "%d: ", t); | ||
| 4564 | verbose(env, "jump out of range from insn %d to %d\n", t, w); | 4623 | verbose(env, "jump out of range from insn %d to %d\n", t, w); |
| 4565 | return -EINVAL; | 4624 | return -EINVAL; |
| 4566 | } | 4625 | } |
| @@ -4578,6 +4637,8 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env) | |||
| 4578 | insn_stack[cur_stack++] = w; | 4637 | insn_stack[cur_stack++] = w; |
| 4579 | return 1; | 4638 | return 1; |
| 4580 | } else if ((insn_state[w] & 0xF0) == DISCOVERED) { | 4639 | } else if ((insn_state[w] & 0xF0) == DISCOVERED) { |
| 4640 | verbose_linfo(env, t, "%d: ", t); | ||
| 4641 | verbose_linfo(env, w, "%d: ", w); | ||
| 4581 | verbose(env, "back-edge from insn %d to %d\n", t, w); | 4642 | verbose(env, "back-edge from insn %d to %d\n", t, w); |
| 4582 | return -EINVAL; | 4643 | return -EINVAL; |
| 4583 | } else if (insn_state[w] == EXPLORED) { | 4644 | } else if (insn_state[w] == EXPLORED) { |
| @@ -4600,10 +4661,6 @@ static int check_cfg(struct bpf_verifier_env *env) | |||
| 4600 | int ret = 0; | 4661 | int ret = 0; |
| 4601 | int i, t; | 4662 | int i, t; |
| 4602 | 4663 | ||
| 4603 | ret = check_subprogs(env); | ||
| 4604 | if (ret < 0) | ||
| 4605 | return ret; | ||
| 4606 | |||
| 4607 | insn_state = kcalloc(insn_cnt, sizeof(int), GFP_KERNEL); | 4664 | insn_state = kcalloc(insn_cnt, sizeof(int), GFP_KERNEL); |
| 4608 | if (!insn_state) | 4665 | if (!insn_state) |
| 4609 | return -ENOMEM; | 4666 | return -ENOMEM; |
| @@ -4910,8 +4967,8 @@ static int check_btf_line(struct bpf_verifier_env *env, | |||
| 4910 | goto err_free; | 4967 | goto err_free; |
| 4911 | } | 4968 | } |
| 4912 | 4969 | ||
| 4913 | if (!btf_name_offset_valid(btf, linfo[i].line_off) || | 4970 | if (!btf_name_by_offset(btf, linfo[i].line_off) || |
| 4914 | !btf_name_offset_valid(btf, linfo[i].file_name_off)) { | 4971 | !btf_name_by_offset(btf, linfo[i].file_name_off)) { |
| 4915 | verbose(env, "Invalid line_info[%u].line_off or .file_name_off\n", i); | 4972 | verbose(env, "Invalid line_info[%u].line_off or .file_name_off\n", i); |
| 4916 | err = -EINVAL; | 4973 | err = -EINVAL; |
| 4917 | goto err_free; | 4974 | goto err_free; |
| @@ -5448,6 +5505,8 @@ static int do_check(struct bpf_verifier_env *env) | |||
| 5448 | int insn_processed = 0; | 5505 | int insn_processed = 0; |
| 5449 | bool do_print_state = false; | 5506 | bool do_print_state = false; |
| 5450 | 5507 | ||
| 5508 | env->prev_linfo = NULL; | ||
| 5509 | |||
| 5451 | state = kzalloc(sizeof(struct bpf_verifier_state), GFP_KERNEL); | 5510 | state = kzalloc(sizeof(struct bpf_verifier_state), GFP_KERNEL); |
| 5452 | if (!state) | 5511 | if (!state) |
| 5453 | return -ENOMEM; | 5512 | return -ENOMEM; |
| @@ -5521,6 +5580,7 @@ static int do_check(struct bpf_verifier_env *env) | |||
| 5521 | .private_data = env, | 5580 | .private_data = env, |
| 5522 | }; | 5581 | }; |
| 5523 | 5582 | ||
| 5583 | verbose_linfo(env, insn_idx, "; "); | ||
| 5524 | verbose(env, "%d: ", insn_idx); | 5584 | verbose(env, "%d: ", insn_idx); |
| 5525 | print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); | 5585 | print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); |
| 5526 | } | 5586 | } |
| @@ -6755,7 +6815,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, | |||
| 6755 | 6815 | ||
| 6756 | env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); | 6816 | env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); |
| 6757 | 6817 | ||
| 6758 | ret = check_cfg(env); | 6818 | ret = check_subprogs(env); |
| 6759 | if (ret < 0) | 6819 | if (ret < 0) |
| 6760 | goto skip_full_check; | 6820 | goto skip_full_check; |
| 6761 | 6821 | ||
| @@ -6763,6 +6823,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, | |||
| 6763 | if (ret < 0) | 6823 | if (ret < 0) |
| 6764 | goto skip_full_check; | 6824 | goto skip_full_check; |
| 6765 | 6825 | ||
| 6826 | ret = check_cfg(env); | ||
| 6827 | if (ret < 0) | ||
| 6828 | goto skip_full_check; | ||
| 6829 | |||
| 6766 | ret = do_check(env); | 6830 | ret = do_check(env); |
| 6767 | if (env->cur_state) { | 6831 | if (env->cur_state) { |
| 6768 | free_verifier_state(env->cur_state, true); | 6832 | free_verifier_state(env->cur_state, true); |
