|
@@ -185,6 +185,7 @@ struct bpf_program {
|
|
|
struct bpf_map {
|
|
|
int fd;
|
|
|
char *name;
|
|
|
+ size_t offset;
|
|
|
struct bpf_map_def def;
|
|
|
void *priv;
|
|
|
bpf_map_clear_priv_t clear_priv;
|
|
@@ -513,57 +514,106 @@ bpf_object__init_kversion(struct bpf_object *obj,
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-bpf_object__init_maps(struct bpf_object *obj, void *data,
|
|
|
- size_t size)
|
|
|
+bpf_object__validate_maps(struct bpf_object *obj)
|
|
|
{
|
|
|
- size_t nr_maps;
|
|
|
int i;
|
|
|
|
|
|
- nr_maps = size / sizeof(struct bpf_map_def);
|
|
|
- if (!data || !nr_maps) {
|
|
|
- pr_debug("%s doesn't need map definition\n",
|
|
|
- obj->path);
|
|
|
+ /*
|
|
|
+ * If there's only 1 map, the only error case should have been
|
|
|
+ * catched in bpf_object__init_maps().
|
|
|
+ */
|
|
|
+ if (!obj->maps || !obj->nr_maps || (obj->nr_maps == 1))
|
|
|
return 0;
|
|
|
- }
|
|
|
|
|
|
- pr_debug("maps in %s: %zd bytes\n", obj->path, size);
|
|
|
+ for (i = 1; i < obj->nr_maps; i++) {
|
|
|
+ const struct bpf_map *a = &obj->maps[i - 1];
|
|
|
+ const struct bpf_map *b = &obj->maps[i];
|
|
|
|
|
|
- obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
|
|
|
- if (!obj->maps) {
|
|
|
- pr_warning("alloc maps for object failed\n");
|
|
|
- return -ENOMEM;
|
|
|
+ if (b->offset - a->offset < sizeof(struct bpf_map_def)) {
|
|
|
+ pr_warning("corrupted map section in %s: map \"%s\" too small\n",
|
|
|
+ obj->path, a->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
}
|
|
|
- obj->nr_maps = nr_maps;
|
|
|
-
|
|
|
- for (i = 0; i < nr_maps; i++) {
|
|
|
- struct bpf_map_def *def = &obj->maps[i].def;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- * fill all fd with -1 so won't close incorrect
|
|
|
- * fd (fd=0 is stdin) when failure (zclose won't close
|
|
|
- * negative fd)).
|
|
|
- */
|
|
|
- obj->maps[i].fd = -1;
|
|
|
+static int compare_bpf_map(const void *_a, const void *_b)
|
|
|
+{
|
|
|
+ const struct bpf_map *a = _a;
|
|
|
+ const struct bpf_map *b = _b;
|
|
|
|
|
|
- /* Save map definition into obj->maps */
|
|
|
- *def = ((struct bpf_map_def *)data)[i];
|
|
|
- }
|
|
|
- return 0;
|
|
|
+ return a->offset - b->offset;
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-bpf_object__init_maps_name(struct bpf_object *obj)
|
|
|
+bpf_object__init_maps(struct bpf_object *obj)
|
|
|
{
|
|
|
- int i;
|
|
|
+ int i, map_idx, nr_maps = 0;
|
|
|
+ Elf_Scn *scn;
|
|
|
+ Elf_Data *data;
|
|
|
Elf_Data *symbols = obj->efile.symbols;
|
|
|
|
|
|
- if (!symbols || obj->efile.maps_shndx < 0)
|
|
|
+ if (obj->efile.maps_shndx < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ if (!symbols)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ scn = elf_getscn(obj->efile.elf, obj->efile.maps_shndx);
|
|
|
+ if (scn)
|
|
|
+ data = elf_getdata(scn, NULL);
|
|
|
+ if (!scn || !data) {
|
|
|
+ pr_warning("failed to get Elf_Data from map section %d\n",
|
|
|
+ obj->efile.maps_shndx);
|
|
|
return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
+ /*
|
|
|
+ * Count number of maps. Each map has a name.
|
|
|
+ * Array of maps is not supported: only the first element is
|
|
|
+ * considered.
|
|
|
+ *
|
|
|
+ * TODO: Detect array of map and report error.
|
|
|
+ */
|
|
|
for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
|
|
|
GElf_Sym sym;
|
|
|
- size_t map_idx;
|
|
|
+
|
|
|
+ if (!gelf_getsym(symbols, i, &sym))
|
|
|
+ continue;
|
|
|
+ if (sym.st_shndx != obj->efile.maps_shndx)
|
|
|
+ continue;
|
|
|
+ nr_maps++;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Alloc obj->maps and fill nr_maps. */
|
|
|
+ pr_debug("maps in %s: %d maps in %zd bytes\n", obj->path,
|
|
|
+ nr_maps, data->d_size);
|
|
|
+
|
|
|
+ if (!nr_maps)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
|
|
|
+ if (!obj->maps) {
|
|
|
+ pr_warning("alloc maps for object failed\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ obj->nr_maps = nr_maps;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * fill all fd with -1 so won't close incorrect
|
|
|
+ * fd (fd=0 is stdin) when failure (zclose won't close
|
|
|
+ * negative fd)).
|
|
|
+ */
|
|
|
+ for (i = 0; i < nr_maps; i++)
|
|
|
+ obj->maps[i].fd = -1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Fill obj->maps using data in "maps" section.
|
|
|
+ */
|
|
|
+ for (i = 0, map_idx = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
|
|
|
+ GElf_Sym sym;
|
|
|
const char *map_name;
|
|
|
+ struct bpf_map_def *def;
|
|
|
|
|
|
if (!gelf_getsym(symbols, i, &sym))
|
|
|
continue;
|
|
@@ -573,21 +623,27 @@ bpf_object__init_maps_name(struct bpf_object *obj)
|
|
|
map_name = elf_strptr(obj->efile.elf,
|
|
|
obj->efile.strtabidx,
|
|
|
sym.st_name);
|
|
|
- map_idx = sym.st_value / sizeof(struct bpf_map_def);
|
|
|
- if (map_idx >= obj->nr_maps) {
|
|
|
- pr_warning("index of map \"%s\" is buggy: %zu > %zu\n",
|
|
|
- map_name, map_idx, obj->nr_maps);
|
|
|
- continue;
|
|
|
+ obj->maps[map_idx].offset = sym.st_value;
|
|
|
+ if (sym.st_value + sizeof(struct bpf_map_def) > data->d_size) {
|
|
|
+ pr_warning("corrupted maps section in %s: last map \"%s\" too small\n",
|
|
|
+ obj->path, map_name);
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
+
|
|
|
obj->maps[map_idx].name = strdup(map_name);
|
|
|
if (!obj->maps[map_idx].name) {
|
|
|
pr_warning("failed to alloc map name\n");
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
- pr_debug("map %zu is \"%s\"\n", map_idx,
|
|
|
+ pr_debug("map %d is \"%s\"\n", map_idx,
|
|
|
obj->maps[map_idx].name);
|
|
|
+ def = (struct bpf_map_def *)(data->d_buf + sym.st_value);
|
|
|
+ obj->maps[map_idx].def = *def;
|
|
|
+ map_idx++;
|
|
|
}
|
|
|
- return 0;
|
|
|
+
|
|
|
+ qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map);
|
|
|
+ return bpf_object__validate_maps(obj);
|
|
|
}
|
|
|
|
|
|
static int bpf_object__elf_collect(struct bpf_object *obj)
|
|
@@ -645,11 +701,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
|
|
|
err = bpf_object__init_kversion(obj,
|
|
|
data->d_buf,
|
|
|
data->d_size);
|
|
|
- else if (strcmp(name, "maps") == 0) {
|
|
|
- err = bpf_object__init_maps(obj, data->d_buf,
|
|
|
- data->d_size);
|
|
|
+ else if (strcmp(name, "maps") == 0)
|
|
|
obj->efile.maps_shndx = idx;
|
|
|
- } else if (sh.sh_type == SHT_SYMTAB) {
|
|
|
+ else if (sh.sh_type == SHT_SYMTAB) {
|
|
|
if (obj->efile.symbols) {
|
|
|
pr_warning("bpf: multiple SYMTAB in %s\n",
|
|
|
obj->path);
|
|
@@ -698,7 +752,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
|
|
|
return LIBBPF_ERRNO__FORMAT;
|
|
|
}
|
|
|
if (obj->efile.maps_shndx >= 0)
|
|
|
- err = bpf_object__init_maps_name(obj);
|
|
|
+ err = bpf_object__init_maps(obj);
|
|
|
out:
|
|
|
return err;
|
|
|
}
|
|
@@ -807,7 +861,7 @@ bpf_object__create_maps(struct bpf_object *obj)
|
|
|
zclose(obj->maps[j].fd);
|
|
|
return err;
|
|
|
}
|
|
|
- pr_debug("create map: fd=%d\n", *pfd);
|
|
|
+ pr_debug("create map %s: fd=%d\n", obj->maps[i].name, *pfd);
|
|
|
}
|
|
|
|
|
|
return 0;
|