Commit bf006d18 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 6c4df17c b1a2ce82
...@@ -73,11 +73,11 @@ static int array_map_alloc_check(union bpf_attr *attr) ...@@ -73,11 +73,11 @@ static int array_map_alloc_check(union bpf_attr *attr)
static struct bpf_map *array_map_alloc(union bpf_attr *attr) static struct bpf_map *array_map_alloc(union bpf_attr *attr)
{ {
bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY; bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
int numa_node = bpf_map_attr_numa_node(attr); int ret, numa_node = bpf_map_attr_numa_node(attr);
u32 elem_size, index_mask, max_entries; u32 elem_size, index_mask, max_entries;
bool unpriv = !capable(CAP_SYS_ADMIN); bool unpriv = !capable(CAP_SYS_ADMIN);
u64 cost, array_size, mask64;
struct bpf_array *array; struct bpf_array *array;
u64 array_size, mask64;
elem_size = round_up(attr->value_size, 8); elem_size = round_up(attr->value_size, 8);
...@@ -109,8 +109,19 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) ...@@ -109,8 +109,19 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
array_size += (u64) max_entries * elem_size; array_size += (u64) max_entries * elem_size;
/* make sure there is no u32 overflow later in round_up() */ /* make sure there is no u32 overflow later in round_up() */
if (array_size >= U32_MAX - PAGE_SIZE) cost = array_size;
if (cost >= U32_MAX - PAGE_SIZE)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (percpu) {
cost += (u64)attr->max_entries * elem_size * num_possible_cpus();
if (cost >= U32_MAX - PAGE_SIZE)
return ERR_PTR(-ENOMEM);
}
cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
ret = bpf_map_precharge_memlock(cost);
if (ret < 0)
return ERR_PTR(ret);
/* allocate all map elements and zero-initialize them */ /* allocate all map elements and zero-initialize them */
array = bpf_map_area_alloc(array_size, numa_node); 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,20 +132,13 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
/* copy mandatory map attributes */ /* copy mandatory map attributes */
bpf_map_init_from_attr(&array->map, attr); bpf_map_init_from_attr(&array->map, attr);
array->map.pages = cost;
array->elem_size = elem_size; array->elem_size = elem_size;
if (!percpu) if (percpu && bpf_array_alloc_percpu(array)) {
goto out;
array_size += (u64) attr->max_entries * elem_size * num_possible_cpus();
if (array_size >= U32_MAX - PAGE_SIZE ||
bpf_array_alloc_percpu(array)) {
bpf_map_area_free(array); bpf_map_area_free(array);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
out:
array->map.pages = round_up(array_size, PAGE_SIZE) >> PAGE_SHIFT;
return &array->map; return &array->map;
} }
......
...@@ -1590,7 +1590,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, ...@@ -1590,7 +1590,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
* so always copy 'cnt' prog_ids to the user. * so always copy 'cnt' prog_ids to the user.
* In a rare race the user will see zero prog_ids * In a rare race the user will see zero prog_ids
*/ */
ids = kcalloc(cnt, sizeof(u32), GFP_USER); ids = kcalloc(cnt, sizeof(u32), GFP_USER | __GFP_NOWARN);
if (!ids) if (!ids)
return -ENOMEM; return -ENOMEM;
rcu_read_lock(); rcu_read_lock();
......
...@@ -334,7 +334,7 @@ static int cpu_map_kthread_run(void *data) ...@@ -334,7 +334,7 @@ static int cpu_map_kthread_run(void *data)
static struct bpf_cpu_map_entry *__cpu_map_entry_alloc(u32 qsize, u32 cpu, static struct bpf_cpu_map_entry *__cpu_map_entry_alloc(u32 qsize, u32 cpu,
int map_id) int map_id)
{ {
gfp_t gfp = GFP_ATOMIC|__GFP_NOWARN; gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;
struct bpf_cpu_map_entry *rcpu; struct bpf_cpu_map_entry *rcpu;
int numa, err; int numa, err;
......
...@@ -555,7 +555,10 @@ static void trie_free(struct bpf_map *map) ...@@ -555,7 +555,10 @@ static void trie_free(struct bpf_map *map)
struct lpm_trie_node __rcu **slot; struct lpm_trie_node __rcu **slot;
struct lpm_trie_node *node; struct lpm_trie_node *node;
raw_spin_lock(&trie->lock); /* Wait for outstanding programs to complete
* update/lookup/delete/get_next_key and free the trie.
*/
synchronize_rcu();
/* Always start at the root and walk down to a node that has no /* Always start at the root and walk down to a node that has no
* children. Then free that node, nullify its reference in the parent * children. Then free that node, nullify its reference in the parent
...@@ -569,7 +572,7 @@ static void trie_free(struct bpf_map *map) ...@@ -569,7 +572,7 @@ static void trie_free(struct bpf_map *map)
node = rcu_dereference_protected(*slot, node = rcu_dereference_protected(*slot,
lockdep_is_held(&trie->lock)); lockdep_is_held(&trie->lock));
if (!node) if (!node)
goto unlock; goto out;
if (rcu_access_pointer(node->child[0])) { if (rcu_access_pointer(node->child[0])) {
slot = &node->child[0]; slot = &node->child[0];
...@@ -587,8 +590,8 @@ static void trie_free(struct bpf_map *map) ...@@ -587,8 +590,8 @@ static void trie_free(struct bpf_map *map)
} }
} }
unlock: out:
raw_spin_unlock(&trie->lock); kfree(trie);
} }
static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key) static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key)
......
...@@ -521,8 +521,8 @@ static struct smap_psock *smap_init_psock(struct sock *sock, ...@@ -521,8 +521,8 @@ static struct smap_psock *smap_init_psock(struct sock *sock,
static struct bpf_map *sock_map_alloc(union bpf_attr *attr) static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
{ {
struct bpf_stab *stab; struct bpf_stab *stab;
int err = -EINVAL;
u64 cost; u64 cost;
int err;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return ERR_PTR(-EPERM); return ERR_PTR(-EPERM);
...@@ -547,6 +547,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr) ...@@ -547,6 +547,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
/* make sure page count doesn't overflow */ /* make sure page count doesn't overflow */
cost = (u64) stab->map.max_entries * sizeof(struct sock *); cost = (u64) stab->map.max_entries * sizeof(struct sock *);
err = -EINVAL;
if (cost >= U32_MAX - PAGE_SIZE) if (cost >= U32_MAX - PAGE_SIZE)
goto free_stab; goto free_stab;
......
...@@ -872,6 +872,8 @@ int perf_event_query_prog_array(struct perf_event *event, void __user *info) ...@@ -872,6 +872,8 @@ int perf_event_query_prog_array(struct perf_event *event, void __user *info)
return -EINVAL; return -EINVAL;
if (copy_from_user(&query, uquery, sizeof(query))) if (copy_from_user(&query, uquery, sizeof(query)))
return -EFAULT; return -EFAULT;
if (query.ids_len > BPF_TRACE_MAX_PROGS)
return -E2BIG;
mutex_lock(&bpf_event_mutex); mutex_lock(&bpf_event_mutex);
ret = bpf_prog_array_copy_info(event->tp_event->prog_array, ret = bpf_prog_array_copy_info(event->tp_event->prog_array,
......
...@@ -244,7 +244,7 @@ static int do_batch(int argc, char **argv) ...@@ -244,7 +244,7 @@ static int do_batch(int argc, char **argv)
} }
if (errno && errno != ENOENT) { if (errno && errno != ENOENT) {
perror("reading batch file failed"); p_err("reading batch file failed: %s", strerror(errno));
err = -1; err = -1;
} else { } else {
p_info("processed %d lines", lines); p_info("processed %d lines", lines);
......
...@@ -774,6 +774,9 @@ static int do_dump(int argc, char **argv) ...@@ -774,6 +774,9 @@ static int do_dump(int argc, char **argv)
n < 0 ? strerror(errno) : "short write"); n < 0 ? strerror(errno) : "short write");
goto err_free; goto err_free;
} }
if (json_output)
jsonw_null(json_wtr);
} else { } else {
if (member_len == &info.jited_prog_len) { if (member_len == &info.jited_prog_len) {
const char *name = NULL; const char *name = NULL;
......
...@@ -1060,11 +1060,12 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, ...@@ -1060,11 +1060,12 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
prog->insns = new_insn; prog->insns = new_insn;
prog->main_prog_cnt = prog->insns_cnt; prog->main_prog_cnt = prog->insns_cnt;
prog->insns_cnt = new_cnt; prog->insns_cnt = new_cnt;
pr_debug("added %zd insn from %s to prog %s\n",
text->insns_cnt, text->section_name,
prog->section_name);
} }
insn = &prog->insns[relo->insn_idx]; insn = &prog->insns[relo->insn_idx];
insn->imm += prog->main_prog_cnt - relo->insn_idx; insn->imm += prog->main_prog_cnt - relo->insn_idx;
pr_debug("added %zd insn from %s to prog %s\n",
text->insns_cnt, text->section_name, prog->section_name);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment