aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf/libbpf.c
diff options
context:
space:
mode:
authorCraig Gallek <kraig@google.com>2017-10-05 10:41:57 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-06 00:42:28 -0400
commitb13c5c14dbfd5923d773de9661404ed9600c53ef (patch)
treecfb266d6bb37d00da439d028930d34691ae8e1c0 /tools/lib/bpf/libbpf.c
parentd009313c99ba575b65a944fe2c683c6346ea1721 (diff)
libbpf: parse maps sections of varying size
This library previously assumed a fixed-size map options structure. Any new options were ignored. In order to allow the options structure to grow and to support parsing older programs, this patch updates the maps section parsing to handle varying sizes. Object files with maps sections smaller than expected will have the new fields initialized to zero. Object files which have larger than expected maps sections will be rejected unless all of the unrecognized data is zero. This change still assumes that each map definition in the maps section is the same size. Signed-off-by: Craig Gallek <kraig@google.com> Acked-by: Jesper Dangaard Brouer <brouer@redhat.com> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'tools/lib/bpf/libbpf.c')
-rw-r--r--tools/lib/bpf/libbpf.c70
1 files changed, 41 insertions, 29 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 4f402dcdf372..23152890ec60 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -579,31 +579,6 @@ bpf_object__init_kversion(struct bpf_object *obj,
579 return 0; 579 return 0;
580} 580}
581 581
582static int
583bpf_object__validate_maps(struct bpf_object *obj)
584{
585 int i;
586
587 /*
588 * If there's only 1 map, the only error case should have been
589 * catched in bpf_object__init_maps().
590 */
591 if (!obj->maps || !obj->nr_maps || (obj->nr_maps == 1))
592 return 0;
593
594 for (i = 1; i < obj->nr_maps; i++) {
595 const struct bpf_map *a = &obj->maps[i - 1];
596 const struct bpf_map *b = &obj->maps[i];
597
598 if (b->offset - a->offset < sizeof(struct bpf_map_def)) {
599 pr_warning("corrupted map section in %s: map \"%s\" too small\n",
600 obj->path, a->name);
601 return -EINVAL;
602 }
603 }
604 return 0;
605}
606
607static int compare_bpf_map(const void *_a, const void *_b) 582static int compare_bpf_map(const void *_a, const void *_b)
608{ 583{
609 const struct bpf_map *a = _a; 584 const struct bpf_map *a = _a;
@@ -615,7 +590,7 @@ static int compare_bpf_map(const void *_a, const void *_b)
615static int 590static int
616bpf_object__init_maps(struct bpf_object *obj) 591bpf_object__init_maps(struct bpf_object *obj)
617{ 592{
618 int i, map_idx, nr_maps = 0; 593 int i, map_idx, map_def_sz, nr_maps = 0;
619 Elf_Scn *scn; 594 Elf_Scn *scn;
620 Elf_Data *data; 595 Elf_Data *data;
621 Elf_Data *symbols = obj->efile.symbols; 596 Elf_Data *symbols = obj->efile.symbols;
@@ -658,6 +633,15 @@ bpf_object__init_maps(struct bpf_object *obj)
658 if (!nr_maps) 633 if (!nr_maps)
659 return 0; 634 return 0;
660 635
636 /* Assume equally sized map definitions */
637 map_def_sz = data->d_size / nr_maps;
638 if (!data->d_size || (data->d_size % nr_maps) != 0) {
639 pr_warning("unable to determine map definition size "
640 "section %s, %d maps in %zd bytes\n",
641 obj->path, nr_maps, data->d_size);
642 return -EINVAL;
643 }
644
661 obj->maps = calloc(nr_maps, sizeof(obj->maps[0])); 645 obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
662 if (!obj->maps) { 646 if (!obj->maps) {
663 pr_warning("alloc maps for object failed\n"); 647 pr_warning("alloc maps for object failed\n");
@@ -690,7 +674,7 @@ bpf_object__init_maps(struct bpf_object *obj)
690 obj->efile.strtabidx, 674 obj->efile.strtabidx,
691 sym.st_name); 675 sym.st_name);
692 obj->maps[map_idx].offset = sym.st_value; 676 obj->maps[map_idx].offset = sym.st_value;
693 if (sym.st_value + sizeof(struct bpf_map_def) > data->d_size) { 677 if (sym.st_value + map_def_sz > data->d_size) {
694 pr_warning("corrupted maps section in %s: last map \"%s\" too small\n", 678 pr_warning("corrupted maps section in %s: last map \"%s\" too small\n",
695 obj->path, map_name); 679 obj->path, map_name);
696 return -EINVAL; 680 return -EINVAL;
@@ -704,12 +688,40 @@ bpf_object__init_maps(struct bpf_object *obj)
704 pr_debug("map %d is \"%s\"\n", map_idx, 688 pr_debug("map %d is \"%s\"\n", map_idx,
705 obj->maps[map_idx].name); 689 obj->maps[map_idx].name);
706 def = (struct bpf_map_def *)(data->d_buf + sym.st_value); 690 def = (struct bpf_map_def *)(data->d_buf + sym.st_value);
707 obj->maps[map_idx].def = *def; 691 /*
692 * If the definition of the map in the object file fits in
693 * bpf_map_def, copy it. Any extra fields in our version
694 * of bpf_map_def will default to zero as a result of the
695 * calloc above.
696 */
697 if (map_def_sz <= sizeof(struct bpf_map_def)) {
698 memcpy(&obj->maps[map_idx].def, def, map_def_sz);
699 } else {
700 /*
701 * Here the map structure being read is bigger than what
702 * we expect, truncate if the excess bits are all zero.
703 * If they are not zero, reject this map as
704 * incompatible.
705 */
706 char *b;
707 for (b = ((char *)def) + sizeof(struct bpf_map_def);
708 b < ((char *)def) + map_def_sz; b++) {
709 if (*b != 0) {
710 pr_warning("maps section in %s: \"%s\" "
711 "has unrecognized, non-zero "
712 "options\n",
713 obj->path, map_name);
714 return -EINVAL;
715 }
716 }
717 memcpy(&obj->maps[map_idx].def, def,
718 sizeof(struct bpf_map_def));
719 }
708 map_idx++; 720 map_idx++;
709 } 721 }
710 722
711 qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map); 723 qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map);
712 return bpf_object__validate_maps(obj); 724 return 0;
713} 725}
714 726
715static int bpf_object__elf_collect(struct bpf_object *obj) 727static int bpf_object__elf_collect(struct bpf_object *obj)