Skip to content

Commit b13c5c1

Browse files
kraigatgoogdavem330
authored andcommitted
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>
1 parent d009313 commit b13c5c1

File tree

1 file changed

+41
-29
lines changed

1 file changed

+41
-29
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -579,31 +579,6 @@ bpf_object__init_kversion(struct bpf_object *obj,
579579
return 0;
580580
}
581581

582-
static int
583-
bpf_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-
607582
static int compare_bpf_map(const void *_a, const void *_b)
608583
{
609584
const struct bpf_map *a = _a;
@@ -615,7 +590,7 @@ static int compare_bpf_map(const void *_a, const void *_b)
615590
static int
616591
bpf_object__init_maps(struct bpf_object *obj)
617592
{
618-
int i, map_idx, nr_maps = 0;
593+
int i, map_idx, map_def_sz, nr_maps = 0;
619594
Elf_Scn *scn;
620595
Elf_Data *data;
621596
Elf_Data *symbols = obj->efile.symbols;
@@ -658,6 +633,15 @@ bpf_object__init_maps(struct bpf_object *obj)
658633
if (!nr_maps)
659634
return 0;
660635

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+
661645
obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
662646
if (!obj->maps) {
663647
pr_warning("alloc maps for object failed\n");
@@ -690,7 +674,7 @@ bpf_object__init_maps(struct bpf_object *obj)
690674
obj->efile.strtabidx,
691675
sym.st_name);
692676
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) {
694678
pr_warning("corrupted maps section in %s: last map \"%s\" too small\n",
695679
obj->path, map_name);
696680
return -EINVAL;
@@ -704,12 +688,40 @@ bpf_object__init_maps(struct bpf_object *obj)
704688
pr_debug("map %d is \"%s\"\n", map_idx,
705689
obj->maps[map_idx].name);
706690
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+
}
708720
map_idx++;
709721
}
710722

711723
qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map);
712-
return bpf_object__validate_maps(obj);
724+
return 0;
713725
}
714726

715727
static int bpf_object__elf_collect(struct bpf_object *obj)

0 commit comments

Comments
 (0)