diff options
author | David S. Miller <davem@davemloft.net> | 2018-02-21 15:37:37 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-02-21 15:37:37 -0500 |
commit | bf006d18b74172c3562486b5e354b42cb5bcb261 (patch) | |
tree | a7437cb2d9b04240d29325c384ad198c74406563 | |
parent | 6c4df17c7a529d460448cc8284b95a4ada37e3a3 (diff) | |
parent | b1a2ce825737b0165cc08e6f98f8c0ea1affdd60 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Daniel Borkmann says:
====================
pull-request: bpf 2018-02-20
The following pull-request contains BPF updates for your *net* tree.
The main changes are:
1) Fix a memory leak in LPM trie's map_free() callback function, where
the trie structure itself was not freed since initial implementation.
Also a synchronize_rcu() was needed in order to wait for outstanding
programs accessing the trie to complete, from Yonghong.
2) Fix sock_map_alloc()'s error path in order to correctly propagate
the -EINVAL error in case of too large allocation requests. This
was just recently introduced when fixing close hooks via ULP layer,
fix from Eric.
3) Do not use GFP_ATOMIC in __cpu_map_entry_alloc(). Reason is that this
will not work with the recent __ptr_ring_init_queue_alloc() conversion
to kvmalloc_array(), where in case of fallback to vmalloc() that GFP
flag is invalid, from Jason.
4) Fix two recent syzkaller warnings: i) fix bpf_prog_array_copy_to_user()
when a prog query with a big number of ids was performed where we'd
otherwise trigger a warning from allocator side, ii) fix a missing
mlock precharge on arraymaps, from Daniel.
5) Two fixes for bpftool in order to avoid breaking JSON output when used
in batch mode, from Quentin.
6) Move a pr_debug() in libbpf in order to avoid having an otherwise
uninitialized variable in bpf_program__reloc_text(), from Jeremy.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | kernel/bpf/arraymap.c | 28 | ||||
-rw-r--r-- | kernel/bpf/core.c | 2 | ||||
-rw-r--r-- | kernel/bpf/cpumap.c | 2 | ||||
-rw-r--r-- | kernel/bpf/lpm_trie.c | 11 | ||||
-rw-r--r-- | kernel/bpf/sockmap.c | 3 | ||||
-rw-r--r-- | kernel/trace/bpf_trace.c | 2 | ||||
-rw-r--r-- | tools/bpf/bpftool/main.c | 2 | ||||
-rw-r--r-- | tools/bpf/bpftool/prog.c | 3 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.c | 5 |
9 files changed, 36 insertions, 22 deletions
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index b1f66480135b..a364c408f25a 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c | |||
@@ -73,11 +73,11 @@ static int array_map_alloc_check(union bpf_attr *attr) | |||
73 | static struct bpf_map *array_map_alloc(union bpf_attr *attr) | 73 | static struct bpf_map *array_map_alloc(union bpf_attr *attr) |
74 | { | 74 | { |
75 | bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY; | 75 | bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY; |
76 | int numa_node = bpf_map_attr_numa_node(attr); | 76 | int ret, numa_node = bpf_map_attr_numa_node(attr); |
77 | u32 elem_size, index_mask, max_entries; | 77 | u32 elem_size, index_mask, max_entries; |
78 | bool unpriv = !capable(CAP_SYS_ADMIN); | 78 | bool unpriv = !capable(CAP_SYS_ADMIN); |
79 | u64 cost, array_size, mask64; | ||
79 | struct bpf_array *array; | 80 | struct bpf_array *array; |
80 | u64 array_size, mask64; | ||
81 | 81 | ||
82 | elem_size = round_up(attr->value_size, 8); | 82 | elem_size = round_up(attr->value_size, 8); |
83 | 83 | ||
@@ -109,8 +109,19 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) | |||
109 | array_size += (u64) max_entries * elem_size; | 109 | array_size += (u64) max_entries * elem_size; |
110 | 110 | ||
111 | /* make sure there is no u32 overflow later in round_up() */ | 111 | /* make sure there is no u32 overflow later in round_up() */ |
112 | if (array_size >= U32_MAX - PAGE_SIZE) | 112 | cost = array_size; |
113 | if (cost >= U32_MAX - PAGE_SIZE) | ||
113 | return ERR_PTR(-ENOMEM); | 114 | return ERR_PTR(-ENOMEM); |
115 | if (percpu) { | ||
116 | cost += (u64)attr->max_entries * elem_size * num_possible_cpus(); | ||
117 | if (cost >= U32_MAX - PAGE_SIZE) | ||
118 | return ERR_PTR(-ENOMEM); | ||
119 | } | ||
120 | cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT; | ||
121 | |||
122 | ret = bpf_map_precharge_memlock(cost); | ||
123 | if (ret < 0) | ||
124 | return ERR_PTR(ret); | ||
114 | 125 | ||
115 | /* allocate all map elements and zero-initialize them */ | 126 | /* allocate all map elements and zero-initialize them */ |
116 | array = bpf_map_area_alloc(array_size, numa_node); | 127 | array = bpf_map_area_alloc(array_size, numa_node); |
@@ -121,20 +132,13 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) | |||
121 | 132 | ||
122 | /* copy mandatory map attributes */ | 133 | /* copy mandatory map attributes */ |
123 | bpf_map_init_from_attr(&array->map, attr); | 134 | bpf_map_init_from_attr(&array->map, attr); |
135 | array->map.pages = cost; | ||
124 | array->elem_size = elem_size; | 136 | array->elem_size = elem_size; |
125 | 137 | ||
126 | if (!percpu) | 138 | if (percpu && bpf_array_alloc_percpu(array)) { |
127 | goto out; | ||
128 | |||
129 | array_size += (u64) attr->max_entries * elem_size * num_possible_cpus(); | ||
130 | |||
131 | if (array_size >= U32_MAX - PAGE_SIZE || | ||
132 | bpf_array_alloc_percpu(array)) { | ||
133 | bpf_map_area_free(array); | 139 | bpf_map_area_free(array); |
134 | return ERR_PTR(-ENOMEM); | 140 | return ERR_PTR(-ENOMEM); |
135 | } | 141 | } |
136 | out: | ||
137 | array->map.pages = round_up(array_size, PAGE_SIZE) >> PAGE_SHIFT; | ||
138 | 142 | ||
139 | return &array->map; | 143 | return &array->map; |
140 | } | 144 | } |
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 29ca9208dcfa..d315b393abdd 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c | |||
@@ -1590,7 +1590,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, | |||
1590 | * so always copy 'cnt' prog_ids to the user. | 1590 | * so always copy 'cnt' prog_ids to the user. |
1591 | * In a rare race the user will see zero prog_ids | 1591 | * In a rare race the user will see zero prog_ids |
1592 | */ | 1592 | */ |
1593 | ids = kcalloc(cnt, sizeof(u32), GFP_USER); | 1593 | ids = kcalloc(cnt, sizeof(u32), GFP_USER | __GFP_NOWARN); |
1594 | if (!ids) | 1594 | if (!ids) |
1595 | return -ENOMEM; | 1595 | return -ENOMEM; |
1596 | rcu_read_lock(); | 1596 | rcu_read_lock(); |
diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c index fbfdada6caee..a4bb0b34375a 100644 --- a/kernel/bpf/cpumap.c +++ b/kernel/bpf/cpumap.c | |||
@@ -334,7 +334,7 @@ static int cpu_map_kthread_run(void *data) | |||
334 | static struct bpf_cpu_map_entry *__cpu_map_entry_alloc(u32 qsize, u32 cpu, | 334 | static struct bpf_cpu_map_entry *__cpu_map_entry_alloc(u32 qsize, u32 cpu, |
335 | int map_id) | 335 | int map_id) |
336 | { | 336 | { |
337 | gfp_t gfp = GFP_ATOMIC|__GFP_NOWARN; | 337 | gfp_t gfp = GFP_KERNEL | __GFP_NOWARN; |
338 | struct bpf_cpu_map_entry *rcpu; | 338 | struct bpf_cpu_map_entry *rcpu; |
339 | int numa, err; | 339 | int numa, err; |
340 | 340 | ||
diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c index 7b469d10d0e9..a75e02c961b5 100644 --- a/kernel/bpf/lpm_trie.c +++ b/kernel/bpf/lpm_trie.c | |||
@@ -555,7 +555,10 @@ static void trie_free(struct bpf_map *map) | |||
555 | struct lpm_trie_node __rcu **slot; | 555 | struct lpm_trie_node __rcu **slot; |
556 | struct lpm_trie_node *node; | 556 | struct lpm_trie_node *node; |
557 | 557 | ||
558 | raw_spin_lock(&trie->lock); | 558 | /* Wait for outstanding programs to complete |
559 | * update/lookup/delete/get_next_key and free the trie. | ||
560 | */ | ||
561 | synchronize_rcu(); | ||
559 | 562 | ||
560 | /* Always start at the root and walk down to a node that has no | 563 | /* Always start at the root and walk down to a node that has no |
561 | * children. Then free that node, nullify its reference in the parent | 564 | * children. Then free that node, nullify its reference in the parent |
@@ -569,7 +572,7 @@ static void trie_free(struct bpf_map *map) | |||
569 | node = rcu_dereference_protected(*slot, | 572 | node = rcu_dereference_protected(*slot, |
570 | lockdep_is_held(&trie->lock)); | 573 | lockdep_is_held(&trie->lock)); |
571 | if (!node) | 574 | if (!node) |
572 | goto unlock; | 575 | goto out; |
573 | 576 | ||
574 | if (rcu_access_pointer(node->child[0])) { | 577 | if (rcu_access_pointer(node->child[0])) { |
575 | slot = &node->child[0]; | 578 | slot = &node->child[0]; |
@@ -587,8 +590,8 @@ static void trie_free(struct bpf_map *map) | |||
587 | } | 590 | } |
588 | } | 591 | } |
589 | 592 | ||
590 | unlock: | 593 | out: |
591 | raw_spin_unlock(&trie->lock); | 594 | kfree(trie); |
592 | } | 595 | } |
593 | 596 | ||
594 | static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key) | 597 | static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key) |
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 48c33417d13c..a927e89dad6e 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c | |||
@@ -521,8 +521,8 @@ static struct smap_psock *smap_init_psock(struct sock *sock, | |||
521 | static struct bpf_map *sock_map_alloc(union bpf_attr *attr) | 521 | static struct bpf_map *sock_map_alloc(union bpf_attr *attr) |
522 | { | 522 | { |
523 | struct bpf_stab *stab; | 523 | struct bpf_stab *stab; |
524 | int err = -EINVAL; | ||
525 | u64 cost; | 524 | u64 cost; |
525 | int err; | ||
526 | 526 | ||
527 | if (!capable(CAP_NET_ADMIN)) | 527 | if (!capable(CAP_NET_ADMIN)) |
528 | return ERR_PTR(-EPERM); | 528 | return ERR_PTR(-EPERM); |
@@ -547,6 +547,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr) | |||
547 | 547 | ||
548 | /* make sure page count doesn't overflow */ | 548 | /* make sure page count doesn't overflow */ |
549 | cost = (u64) stab->map.max_entries * sizeof(struct sock *); | 549 | cost = (u64) stab->map.max_entries * sizeof(struct sock *); |
550 | err = -EINVAL; | ||
550 | if (cost >= U32_MAX - PAGE_SIZE) | 551 | if (cost >= U32_MAX - PAGE_SIZE) |
551 | goto free_stab; | 552 | goto free_stab; |
552 | 553 | ||
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index fc2838ac8b78..c0a9e310d715 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c | |||
@@ -872,6 +872,8 @@ int perf_event_query_prog_array(struct perf_event *event, void __user *info) | |||
872 | return -EINVAL; | 872 | return -EINVAL; |
873 | if (copy_from_user(&query, uquery, sizeof(query))) | 873 | if (copy_from_user(&query, uquery, sizeof(query))) |
874 | return -EFAULT; | 874 | return -EFAULT; |
875 | if (query.ids_len > BPF_TRACE_MAX_PROGS) | ||
876 | return -E2BIG; | ||
875 | 877 | ||
876 | mutex_lock(&bpf_event_mutex); | 878 | mutex_lock(&bpf_event_mutex); |
877 | ret = bpf_prog_array_copy_info(event->tp_event->prog_array, | 879 | ret = bpf_prog_array_copy_info(event->tp_event->prog_array, |
diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 3a0396d87c42..185acfa229b5 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c | |||
@@ -244,7 +244,7 @@ static int do_batch(int argc, char **argv) | |||
244 | } | 244 | } |
245 | 245 | ||
246 | if (errno && errno != ENOENT) { | 246 | if (errno && errno != ENOENT) { |
247 | perror("reading batch file failed"); | 247 | p_err("reading batch file failed: %s", strerror(errno)); |
248 | err = -1; | 248 | err = -1; |
249 | } else { | 249 | } else { |
250 | p_info("processed %d lines", lines); | 250 | p_info("processed %d lines", lines); |
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index e8e2baaf93c2..e549e329be82 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c | |||
@@ -774,6 +774,9 @@ static int do_dump(int argc, char **argv) | |||
774 | n < 0 ? strerror(errno) : "short write"); | 774 | n < 0 ? strerror(errno) : "short write"); |
775 | goto err_free; | 775 | goto err_free; |
776 | } | 776 | } |
777 | |||
778 | if (json_output) | ||
779 | jsonw_null(json_wtr); | ||
777 | } else { | 780 | } else { |
778 | if (member_len == &info.jited_prog_len) { | 781 | if (member_len == &info.jited_prog_len) { |
779 | const char *name = NULL; | 782 | const char *name = NULL; |
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 97073d649c1a..5bbbf285af74 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c | |||
@@ -1060,11 +1060,12 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, | |||
1060 | prog->insns = new_insn; | 1060 | prog->insns = new_insn; |
1061 | prog->main_prog_cnt = prog->insns_cnt; | 1061 | prog->main_prog_cnt = prog->insns_cnt; |
1062 | prog->insns_cnt = new_cnt; | 1062 | prog->insns_cnt = new_cnt; |
1063 | pr_debug("added %zd insn from %s to prog %s\n", | ||
1064 | text->insns_cnt, text->section_name, | ||
1065 | prog->section_name); | ||
1063 | } | 1066 | } |
1064 | insn = &prog->insns[relo->insn_idx]; | 1067 | insn = &prog->insns[relo->insn_idx]; |
1065 | insn->imm += prog->main_prog_cnt - relo->insn_idx; | 1068 | insn->imm += prog->main_prog_cnt - relo->insn_idx; |
1066 | pr_debug("added %zd insn from %s to prog %s\n", | ||
1067 | text->insns_cnt, text->section_name, prog->section_name); | ||
1068 | return 0; | 1069 | return 0; |
1069 | } | 1070 | } |
1070 | 1071 | ||