bpf: Avoid ABI change in 4.9.77
authorYves-Alexis Perez <corsac@debian.org>
Sat, 20 Jan 2018 13:52:32 +0000 (14:52 +0100)
committerYves-Alexis Perez <corsac@debian.org>
Fri, 9 Feb 2018 12:58:52 +0000 (12:58 +0000)
Commit a9bfac14cde2 "bpf: prevent out-of-bounds speculation" added one
member each to struct bpf_map and struct bpf_array (which is
effectively a sub-type of bpf_map).  Changing the size of struct
bpf_array is an ABI change, since the array contents immediately
follows the structure.  However, bpf_map::work is not used (or even
initialised) until after the map's refcount drops to zero.  We can
therefore move the new members into a union with it.

Based on the patch against 4.14.14 by Ben Hutchings <ben@decadent.org.uk>

Gbp-Pq: Topic debian
Gbp-Pq: Name bpf-avoid-abi-change-in-4.9.77.patch

include/linux/bpf.h
kernel/bpf/arraymap.c
kernel/bpf/verifier.c

index 75ffd3b2149e9531392c1681f7776c034b79b90e..e28c535d0a5398f31e0305f1ae13f9d7c5bd9bfe 100644 (file)
@@ -43,10 +43,20 @@ struct bpf_map {
        u32 max_entries;
        u32 map_flags;
        u32 pages;
-       bool unpriv_array;
+
        struct user_struct *user;
        const struct bpf_map_ops *ops;
+#ifdef __GENKSYMS__
        struct work_struct work;
+#else
+       union {
+               struct work_struct work;
+               struct {
+                       bool unpriv_array;
+                       u32 index_mask;
+               };
+       };
+#endif
        atomic_t usercnt;
 };
 
@@ -190,7 +200,6 @@ struct bpf_prog_aux {
 struct bpf_array {
        struct bpf_map map;
        u32 elem_size;
-       u32 index_mask;
        /* 'ownership' of prog_array is claimed by the first program that
         * is going to use this map or by the first program which FD is stored
         * in the map to make sure that all callers and callees have the same
index 9a1e6ed7babce6a9fbaf4126b6fd2f04d95eee9d..e949abb8bdd453c97294a9fa210190d1d1aadfe5 100644 (file)
@@ -99,7 +99,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
        array = bpf_map_area_alloc(array_size);
        if (!array)
                return ERR_PTR(-ENOMEM);
-       array->index_mask = index_mask;
+       array->map.index_mask = index_mask;
        array->map.unpriv_array = unpriv;
 
        /* copy mandatory map attributes */
@@ -134,7 +134,7 @@ static void *array_map_lookup_elem(struct bpf_map *map, void *key)
        if (unlikely(index >= array->map.max_entries))
                return NULL;
 
-       return array->value + array->elem_size * (index & array->index_mask);
+       return array->value + array->elem_size * (index & array->map.index_mask);
 }
 
 /* Called from eBPF program */
@@ -146,7 +146,7 @@ static void *percpu_array_map_lookup_elem(struct bpf_map *map, void *key)
        if (unlikely(index >= array->map.max_entries))
                return NULL;
 
-       return this_cpu_ptr(array->pptrs[index & array->index_mask]);
+       return this_cpu_ptr(array->pptrs[index & array->map.index_mask]);
 }
 
 int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value)
@@ -166,7 +166,7 @@ int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value)
         */
        size = round_up(map->value_size, 8);
        rcu_read_lock();
-       pptr = array->pptrs[index & array->index_mask];
+       pptr = array->pptrs[index & array->map.index_mask];
        for_each_possible_cpu(cpu) {
                bpf_long_memcpy(value + off, per_cpu_ptr(pptr, cpu), size);
                off += size;
@@ -214,11 +214,11 @@ static int array_map_update_elem(struct bpf_map *map, void *key, void *value,
                return -EEXIST;
 
        if (array->map.map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
-               memcpy(this_cpu_ptr(array->pptrs[index & array->index_mask]),
+               memcpy(this_cpu_ptr(array->pptrs[index & array->map.index_mask]),
                       value, map->value_size);
        else
                memcpy(array->value +
-                      array->elem_size * (index & array->index_mask),
+                      array->elem_size * (index & array->map.index_mask),
                       value, map->value_size);
        return 0;
 }
@@ -252,7 +252,7 @@ int bpf_percpu_array_update(struct bpf_map *map, void *key, void *value,
         */
        size = round_up(map->value_size, 8);
        rcu_read_lock();
-       pptr = array->pptrs[index & array->index_mask];
+       pptr = array->pptrs[index & array->map.index_mask];
        for_each_possible_cpu(cpu) {
                bpf_long_memcpy(per_cpu_ptr(pptr, cpu), value + off, size);
                off += size;
index 076e4a0ff95e7b4d3b41a2e9f040da8e20b6feaf..f23dfac066b83b0dbf3bc970a0e315626ef02afc 100644 (file)
@@ -3456,9 +3456,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
                        insn_buf[0] = BPF_JMP_IMM(BPF_JGE, BPF_REG_3,
                                                  map_ptr->max_entries, 2);
                        insn_buf[1] = BPF_ALU32_IMM(BPF_AND, BPF_REG_3,
-                                                   container_of(map_ptr,
-                                                                struct bpf_array,
-                                                                map)->index_mask);
+                                                   map_ptr->index_mask);
                        insn_buf[2] = *insn;
                        cnt = 3;
                        new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);