bpf: check max_entries before allocating memory
authorFlorian Lehner <dev@der-flo.net>
Fri, 28 Oct 2022 18:34:05 +0000 (20:34 +0200)
committerMartin KaFai Lau <martin.lau@kernel.org>
Fri, 28 Oct 2022 22:45:58 +0000 (15:45 -0700)
For maps of type BPF_MAP_TYPE_CPUMAP memory is allocated first before
checking the max_entries argument. If then max_entries is greater than
NR_CPUS additional work needs to be done to free allocated memory before
an error is returned.
This changes moves the check on max_entries before the allocation
happens.

Signed-off-by: Florian Lehner <dev@der-flo.net>
Link: https://lore.kernel.org/r/20221028183405.59554-1-dev@der-flo.net
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
kernel/bpf/cpumap.c

index b5ba34d..bb03fdb 100644 (file)
@@ -85,7 +85,6 @@ static struct bpf_map *cpu_map_alloc(union bpf_attr *attr)
 {
        u32 value_size = attr->value_size;
        struct bpf_cpu_map *cmap;
-       int err = -ENOMEM;
 
        if (!bpf_capable())
                return ERR_PTR(-EPERM);
@@ -97,29 +96,26 @@ static struct bpf_map *cpu_map_alloc(union bpf_attr *attr)
            attr->map_flags & ~BPF_F_NUMA_NODE)
                return ERR_PTR(-EINVAL);
 
+       /* Pre-limit array size based on NR_CPUS, not final CPU check */
+       if (attr->max_entries > NR_CPUS)
+               return ERR_PTR(-E2BIG);
+
        cmap = bpf_map_area_alloc(sizeof(*cmap), NUMA_NO_NODE);
        if (!cmap)
                return ERR_PTR(-ENOMEM);
 
        bpf_map_init_from_attr(&cmap->map, attr);
 
-       /* Pre-limit array size based on NR_CPUS, not final CPU check */
-       if (cmap->map.max_entries > NR_CPUS) {
-               err = -E2BIG;
-               goto free_cmap;
-       }
-
        /* Alloc array for possible remote "destination" CPUs */
        cmap->cpu_map = bpf_map_area_alloc(cmap->map.max_entries *
                                           sizeof(struct bpf_cpu_map_entry *),
                                           cmap->map.numa_node);
-       if (!cmap->cpu_map)
-               goto free_cmap;
+       if (!cmap->cpu_map) {
+               bpf_map_area_free(cmap);
+               return ERR_PTR(-ENOMEM);
+       }
 
        return &cmap->map;
-free_cmap:
-       bpf_map_area_free(cmap);
-       return ERR_PTR(err);
 }
 
 static void get_cpu_map_entry(struct bpf_cpu_map_entry *rcpu)