diff options
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r-- | kernel/bpf/syscall.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 4ca46df19c9a..fe23dc5a3ec4 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -11,6 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | #include <linux/bpf.h> | 12 | #include <linux/bpf.h> |
13 | #include <linux/bpf_trace.h> | 13 | #include <linux/bpf_trace.h> |
14 | #include <linux/btf.h> | ||
14 | #include <linux/syscalls.h> | 15 | #include <linux/syscalls.h> |
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
16 | #include <linux/sched/signal.h> | 17 | #include <linux/sched/signal.h> |
@@ -26,6 +27,7 @@ | |||
26 | #include <linux/cred.h> | 27 | #include <linux/cred.h> |
27 | #include <linux/timekeeping.h> | 28 | #include <linux/timekeeping.h> |
28 | #include <linux/ctype.h> | 29 | #include <linux/ctype.h> |
30 | #include <linux/btf.h> | ||
29 | 31 | ||
30 | #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \ | 32 | #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \ |
31 | (map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ | 33 | (map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ |
@@ -250,6 +252,7 @@ static void bpf_map_free_deferred(struct work_struct *work) | |||
250 | 252 | ||
251 | bpf_map_uncharge_memlock(map); | 253 | bpf_map_uncharge_memlock(map); |
252 | security_bpf_map_free(map); | 254 | security_bpf_map_free(map); |
255 | btf_put(map->btf); | ||
253 | /* implementation dependent freeing */ | 256 | /* implementation dependent freeing */ |
254 | map->ops->map_free(map); | 257 | map->ops->map_free(map); |
255 | } | 258 | } |
@@ -415,7 +418,7 @@ static int bpf_obj_name_cpy(char *dst, const char *src) | |||
415 | return 0; | 418 | return 0; |
416 | } | 419 | } |
417 | 420 | ||
418 | #define BPF_MAP_CREATE_LAST_FIELD map_ifindex | 421 | #define BPF_MAP_CREATE_LAST_FIELD btf_value_id |
419 | /* called via syscall */ | 422 | /* called via syscall */ |
420 | static int map_create(union bpf_attr *attr) | 423 | static int map_create(union bpf_attr *attr) |
421 | { | 424 | { |
@@ -449,6 +452,33 @@ static int map_create(union bpf_attr *attr) | |||
449 | atomic_set(&map->refcnt, 1); | 452 | atomic_set(&map->refcnt, 1); |
450 | atomic_set(&map->usercnt, 1); | 453 | atomic_set(&map->usercnt, 1); |
451 | 454 | ||
455 | if (bpf_map_support_seq_show(map) && | ||
456 | (attr->btf_key_id || attr->btf_value_id)) { | ||
457 | struct btf *btf; | ||
458 | |||
459 | if (!attr->btf_key_id || !attr->btf_value_id) { | ||
460 | err = -EINVAL; | ||
461 | goto free_map_nouncharge; | ||
462 | } | ||
463 | |||
464 | btf = btf_get_by_fd(attr->btf_fd); | ||
465 | if (IS_ERR(btf)) { | ||
466 | err = PTR_ERR(btf); | ||
467 | goto free_map_nouncharge; | ||
468 | } | ||
469 | |||
470 | err = map->ops->map_check_btf(map, btf, attr->btf_key_id, | ||
471 | attr->btf_value_id); | ||
472 | if (err) { | ||
473 | btf_put(btf); | ||
474 | goto free_map_nouncharge; | ||
475 | } | ||
476 | |||
477 | map->btf = btf; | ||
478 | map->btf_key_id = attr->btf_key_id; | ||
479 | map->btf_value_id = attr->btf_value_id; | ||
480 | } | ||
481 | |||
452 | err = security_bpf_map_alloc(map); | 482 | err = security_bpf_map_alloc(map); |
453 | if (err) | 483 | if (err) |
454 | goto free_map_nouncharge; | 484 | goto free_map_nouncharge; |
@@ -481,6 +511,7 @@ free_map: | |||
481 | free_map_sec: | 511 | free_map_sec: |
482 | security_bpf_map_free(map); | 512 | security_bpf_map_free(map); |
483 | free_map_nouncharge: | 513 | free_map_nouncharge: |
514 | btf_put(map->btf); | ||
484 | map->ops->map_free(map); | 515 | map->ops->map_free(map); |
485 | return err; | 516 | return err; |
486 | } | 517 | } |
@@ -2016,6 +2047,8 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, | |||
2016 | else if (f.file->f_op == &bpf_map_fops) | 2047 | else if (f.file->f_op == &bpf_map_fops) |
2017 | err = bpf_map_get_info_by_fd(f.file->private_data, attr, | 2048 | err = bpf_map_get_info_by_fd(f.file->private_data, attr, |
2018 | uattr); | 2049 | uattr); |
2050 | else if (f.file->f_op == &btf_fops) | ||
2051 | err = btf_get_info_by_fd(f.file->private_data, attr, uattr); | ||
2019 | else | 2052 | else |
2020 | err = -EINVAL; | 2053 | err = -EINVAL; |
2021 | 2054 | ||
@@ -2023,6 +2056,19 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, | |||
2023 | return err; | 2056 | return err; |
2024 | } | 2057 | } |
2025 | 2058 | ||
2059 | #define BPF_BTF_LOAD_LAST_FIELD btf_log_level | ||
2060 | |||
2061 | static int bpf_btf_load(const union bpf_attr *attr) | ||
2062 | { | ||
2063 | if (CHECK_ATTR(BPF_BTF_LOAD)) | ||
2064 | return -EINVAL; | ||
2065 | |||
2066 | if (!capable(CAP_SYS_ADMIN)) | ||
2067 | return -EPERM; | ||
2068 | |||
2069 | return btf_new_fd(attr); | ||
2070 | } | ||
2071 | |||
2026 | SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) | 2072 | SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) |
2027 | { | 2073 | { |
2028 | union bpf_attr attr = {}; | 2074 | union bpf_attr attr = {}; |
@@ -2103,6 +2149,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz | |||
2103 | case BPF_RAW_TRACEPOINT_OPEN: | 2149 | case BPF_RAW_TRACEPOINT_OPEN: |
2104 | err = bpf_raw_tracepoint_open(&attr); | 2150 | err = bpf_raw_tracepoint_open(&attr); |
2105 | break; | 2151 | break; |
2152 | case BPF_BTF_LOAD: | ||
2153 | err = bpf_btf_load(&attr); | ||
2154 | break; | ||
2106 | default: | 2155 | default: |
2107 | err = -EINVAL; | 2156 | err = -EINVAL; |
2108 | break; | 2157 | break; |