aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2019-04-09 17:20:10 -0400
committerAlexei Starovoitov <ast@kernel.org>2019-04-09 20:05:46 -0400
commit2824ecb7010f6a20e9a4140512b798469ab066cc (patch)
treebb72402c12f3dd2f34be1d12e460442e7ed79b54
parent1dc92851849cc2235a1efef8f8d5a9255efc5f13 (diff)
bpf: allow for key-less BTF in array map
Given we'll be reusing BPF array maps for global data/bss/rodata sections, we need a way to associate BTF DataSec type as its map value type. In usual cases we have this ugly BPF_ANNOTATE_KV_PAIR() macro hack e.g. via 38d5d3b3d5db ("bpf: Introduce BPF_ANNOTATE_KV_PAIR") to get initial map to type association going. While more use cases for it are discouraged, this also won't work for global data since the use of array map is a BPF loader detail and therefore unknown at compilation time. For array maps with just a single entry we make an exception in terms of BTF in that key type is declared optional if value type is of DataSec type. The latter LLVM is guaranteed to emit and it also aligns with how we regard global data maps as just a plain buffer area reusing existing map facilities for allowing things like introspection with existing tools. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--include/linux/btf.h1
-rw-r--r--kernel/bpf/arraymap.c15
-rw-r--r--kernel/bpf/btf.c2
-rw-r--r--kernel/bpf/syscall.c15
4 files changed, 27 insertions, 6 deletions
diff --git a/include/linux/btf.h b/include/linux/btf.h
index 455d31b55828..64cdf2a23d42 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -51,6 +51,7 @@ bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
51 const struct btf_member *m, 51 const struct btf_member *m,
52 u32 expected_offset, u32 expected_size); 52 u32 expected_offset, u32 expected_size);
53int btf_find_spin_lock(const struct btf *btf, const struct btf_type *t); 53int btf_find_spin_lock(const struct btf *btf, const struct btf_type *t);
54bool btf_type_is_void(const struct btf_type *t);
54 55
55#ifdef CONFIG_BPF_SYSCALL 56#ifdef CONFIG_BPF_SYSCALL
56const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); 57const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id);
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 217b10bd9f48..584636c9e2eb 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -391,7 +391,8 @@ static void array_map_seq_show_elem(struct bpf_map *map, void *key,
391 return; 391 return;
392 } 392 }
393 393
394 seq_printf(m, "%u: ", *(u32 *)key); 394 if (map->btf_key_type_id)
395 seq_printf(m, "%u: ", *(u32 *)key);
395 btf_type_seq_show(map->btf, map->btf_value_type_id, value, m); 396 btf_type_seq_show(map->btf, map->btf_value_type_id, value, m);
396 seq_puts(m, "\n"); 397 seq_puts(m, "\n");
397 398
@@ -428,6 +429,18 @@ static int array_map_check_btf(const struct bpf_map *map,
428{ 429{
429 u32 int_data; 430 u32 int_data;
430 431
432 /* One exception for keyless BTF: .bss/.data/.rodata map */
433 if (btf_type_is_void(key_type)) {
434 if (map->map_type != BPF_MAP_TYPE_ARRAY ||
435 map->max_entries != 1)
436 return -EINVAL;
437
438 if (BTF_INFO_KIND(value_type->info) != BTF_KIND_DATASEC)
439 return -EINVAL;
440
441 return 0;
442 }
443
431 if (BTF_INFO_KIND(key_type->info) != BTF_KIND_INT) 444 if (BTF_INFO_KIND(key_type->info) != BTF_KIND_INT)
432 return -EINVAL; 445 return -EINVAL;
433 446
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 0cecf6bab61b..cad09858a5f2 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -326,7 +326,7 @@ static bool btf_type_is_modifier(const struct btf_type *t)
326 return false; 326 return false;
327} 327}
328 328
329static bool btf_type_is_void(const struct btf_type *t) 329bool btf_type_is_void(const struct btf_type *t)
330{ 330{
331 return t == &btf_void; 331 return t == &btf_void;
332} 332}
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 198c9680bf0d..438199e2eca4 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -504,9 +504,16 @@ static int map_check_btf(struct bpf_map *map, const struct btf *btf,
504 u32 key_size, value_size; 504 u32 key_size, value_size;
505 int ret = 0; 505 int ret = 0;
506 506
507 key_type = btf_type_id_size(btf, &btf_key_id, &key_size); 507 /* Some maps allow key to be unspecified. */
508 if (!key_type || key_size != map->key_size) 508 if (btf_key_id) {
509 return -EINVAL; 509 key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
510 if (!key_type || key_size != map->key_size)
511 return -EINVAL;
512 } else {
513 key_type = btf_type_by_id(btf, 0);
514 if (!map->ops->map_check_btf)
515 return -EINVAL;
516 }
510 517
511 value_type = btf_type_id_size(btf, &btf_value_id, &value_size); 518 value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
512 if (!value_type || value_size != map->value_size) 519 if (!value_type || value_size != map->value_size)
@@ -573,7 +580,7 @@ static int map_create(union bpf_attr *attr)
573 if (attr->btf_key_type_id || attr->btf_value_type_id) { 580 if (attr->btf_key_type_id || attr->btf_value_type_id) {
574 struct btf *btf; 581 struct btf *btf;
575 582
576 if (!attr->btf_key_type_id || !attr->btf_value_type_id) { 583 if (!attr->btf_value_type_id) {
577 err = -EINVAL; 584 err = -EINVAL;
578 goto free_map_nouncharge; 585 goto free_map_nouncharge;
579 } 586 }