bpf: Fix out of bounds memory access in bpf_sk_storage
authorArthur Fabre <afabre@cloudflare.com>
Sat, 15 Jun 2019 21:36:27 +0000 (14:36 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 15 Jun 2019 21:37:56 +0000 (14:37 -0700)
bpf_sk_storage maps use multiple spin locks to reduce contention.
The number of locks to use is determined by the number of possible CPUs.
With only 1 possible CPU, bucket_log == 0, and 2^0 = 1 locks are used.

When updating elements, the correct lock is determined with hash_ptr().
Calling hash_ptr() with 0 bits is undefined behavior, as it does:

x >> (64 - bits)

Using the value results in an out of bounds memory access.
In my case, this manifested itself as a page fault when raw_spin_lock_bh()
is called later, when running the self tests:

./tools/testing/selftests/bpf/test_verifier 773 775
[   16.366342] BUG: unable to handle page fault for address: ffff8fe7a66f93f8

Force the minimum number of locks to two.

Signed-off-by: Arthur Fabre <afabre@cloudflare.com>
Fixes: 6ac99e8f23d4 ("bpf: Introduce bpf sk local storage")
Acked-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
net/core/bpf_sk_storage.c

index cc9597a877707f3de6e7bbfdec3d3c7ae9f56fbc..d1c4e1f3be2c71385e5c4414b8c831e4b2e4a91d 100644 (file)
@@ -633,7 +633,8 @@ static struct bpf_map *bpf_sk_storage_map_alloc(union bpf_attr *attr)
                return ERR_PTR(-ENOMEM);
        bpf_map_init_from_attr(&smap->map, attr);
 
-       smap->bucket_log = ilog2(roundup_pow_of_two(num_possible_cpus()));
+       /* Use at least 2 buckets, select_bucket() is undefined behavior with 1 bucket */
+       smap->bucket_log = max_t(u32, 1, ilog2(roundup_pow_of_two(num_possible_cpus())));
        nbuckets = 1U << smap->bucket_log;
        smap->buckets = kvcalloc(sizeof(*smap->buckets), nbuckets,
                                 GFP_USER | __GFP_NOWARN);