xref: /linux/tools/testing/selftests/bpf/progs/cgroup_storage.c (revision c4dde411bc366f568dbe33366253bbfea049e8ea)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/bpf.h>
4 #include <bpf/bpf_helpers.h>
5 
6 struct {
7 	__uint(type, BPF_MAP_TYPE_CGROUP_STORAGE);
8 	__type(key, struct bpf_cgroup_storage_key);
9 	__type(value, __u64);
10 } cgroup_storage SEC(".maps");
11 
12 SEC("cgroup_skb/egress")
13 int bpf_prog(struct __sk_buff *skb)
14 {
15 	__u64 *counter;
16 
17 	counter = bpf_get_local_storage(&cgroup_storage, 0);
18 	__sync_fetch_and_add(counter, 1);
19 
20 	/* Drop one out of every two packets */
21 	return (*counter & 1);
22 }
23 
24 /* Maps for OOB test */
25 struct {
26 	__uint(type, BPF_MAP_TYPE_CGROUP_STORAGE);
27 	__type(key, struct bpf_cgroup_storage_key);
28 	__type(value, __u32);  /* 4-byte value - not 8-byte aligned */
29 } cgroup_storage_oob SEC(".maps");
30 
31 struct {
32 	__uint(type, BPF_MAP_TYPE_LRU_PERCPU_HASH);
33 	__uint(max_entries, 1);
34 	__type(key, __u32);
35 	__type(value, __u32);  /* 4-byte value - same as cgroup storage */
36 } lru_map SEC(".maps");
37 
38 SEC("cgroup/sock_create")
39 int trigger_oob(struct bpf_sock *sk)
40 {
41 	__u32 key = 0;
42 	__u32 *cgroup_val;
43 	__u32 value = 0x12345678;
44 
45 	/* Get cgroup storage value */
46 	cgroup_val = bpf_get_local_storage(&cgroup_storage_oob, 0);
47 	if (!cgroup_val)
48 		return 0;
49 
50 	/* Initialize cgroup storage */
51 	*cgroup_val = value;
52 
53 	/* This triggers the OOB read:
54 	 * bpf_map_update_elem() -> htab_map_update_elem() ->
55 	 * pcpu_init_value() -> copy_map_value_long() ->
56 	 * bpf_obj_memcpy(..., long_memcpy=true) ->
57 	 * bpf_long_memcpy(dst, src, round_up(4, 8))
58 	 *
59 	 * The copy size is rounded up to 8 bytes, but cgroup_val
60 	 * points to a 4-byte buffer, causing a 4-byte OOB read.
61 	 */
62 	bpf_map_update_elem(&lru_map, &key, cgroup_val, BPF_ANY);
63 
64 	return 1;
65 }
66 
67 char _license[] SEC("license") = "GPL";
68