1 // SPDX-License-Identifier: GPL-2.0 2 /* Converted from tools/testing/selftests/bpf/verifier/map_ptr.c */ 3 4 #include <linux/bpf.h> 5 #include <bpf/bpf_helpers.h> 6 #include "bpf_misc.h" 7 8 #define MAX_ENTRIES 11 9 10 struct test_val { 11 unsigned int index; 12 int foo[MAX_ENTRIES]; 13 }; 14 15 struct { 16 __uint(type, BPF_MAP_TYPE_ARRAY); 17 __uint(max_entries, 1); 18 __type(key, int); 19 __type(value, struct test_val); 20 } map_array_48b SEC(".maps"); 21 22 struct other_val { 23 long long foo; 24 long long bar; 25 }; 26 27 struct { 28 __uint(type, BPF_MAP_TYPE_HASH); 29 __uint(max_entries, 1); 30 __type(key, long long); 31 __type(value, struct other_val); 32 } map_hash_16b SEC(".maps"); 33 34 SEC("socket") 35 __description("bpf_map_ptr: read with negative offset rejected") 36 __failure __msg("R1 is bpf_array invalid negative access: off=-8") 37 __failure_unpriv 38 __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") 39 __naked void read_with_negative_offset_rejected(void) 40 { 41 asm volatile (" \ 42 r1 = r10; \ 43 r1 = %[map_array_48b] ll; \ 44 r6 = *(u64*)(r1 - 8); \ 45 r0 = 1; \ 46 exit; \ 47 " : 48 : __imm_addr(map_array_48b) 49 : __clobber_all); 50 } 51 52 SEC("socket") 53 __description("bpf_map_ptr: write rejected") 54 __failure __msg("only read from bpf_array is supported") 55 __failure_unpriv 56 __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") 57 __naked void bpf_map_ptr_write_rejected(void) 58 { 59 asm volatile (" \ 60 r0 = 0; \ 61 *(u64*)(r10 - 8) = r0; \ 62 r2 = r10; \ 63 r2 += -8; \ 64 r1 = %[map_array_48b] ll; \ 65 *(u64*)(r1 + 0) = r2; \ 66 r0 = 1; \ 67 exit; \ 68 " : 69 : __imm_addr(map_array_48b) 70 : __clobber_all); 71 } 72 73 /* 74 * struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable 75 * byte array), the u32 excl field at offset 32, and the ops pointer at offset 76 * 40. Reading a u32 at offset 41 reaches into the middle of the ops pointer, 77 * i.e. a partial pointer access, which is rejected. 78 */ 79 SEC("socket") 80 __description("bpf_map_ptr: read non-existent field rejected") 81 __failure 82 __msg("cannot access ptr member ops with moff 40 in struct bpf_map with off 41 size 4") 83 __failure_unpriv 84 __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") 85 __flag(BPF_F_ANY_ALIGNMENT) 86 __naked void read_non_existent_field_rejected(void) 87 { 88 asm volatile (" \ 89 r6 = 0; \ 90 r1 = %[map_array_48b] ll; \ 91 r6 = *(u32*)(r1 + 41); \ 92 r0 = 1; \ 93 exit; \ 94 " : 95 : __imm_addr(map_array_48b) 96 : __clobber_all); 97 } 98 99 /* 100 * The u32 excl field spans offsets 32..35 (mend 36). Reading a u32 at offset 101 * 33 starts inside excl but extends past its end, which the verifier rejects 102 * as an out-of-bounds scalar access. 103 */ 104 SEC("socket") 105 __description("bpf_map_ptr: read beyond excl field rejected") 106 __failure 107 __msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4") 108 __failure_unpriv 109 __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") 110 __flag(BPF_F_ANY_ALIGNMENT) 111 __naked void read_beyond_excl_field_rejected(void) 112 { 113 asm volatile (" \ 114 r6 = 0; \ 115 r1 = %[map_array_48b] ll; \ 116 r6 = *(u32*)(r1 + 33); \ 117 r0 = 1; \ 118 exit; \ 119 " : 120 : __imm_addr(map_array_48b) 121 : __clobber_all); 122 } 123 124 SEC("socket") 125 __description("bpf_map_ptr: read ops field accepted") 126 __success __failure_unpriv 127 __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") 128 __retval(1) 129 __naked void ptr_read_ops_field_accepted(void) 130 { 131 asm volatile (" \ 132 r6 = 0; \ 133 r1 = %[map_array_48b] ll; \ 134 r6 = *(u64*)(r1 + 40); \ 135 r0 = 1; \ 136 exit; \ 137 " : 138 : __imm_addr(map_array_48b) 139 : __clobber_all); 140 } 141 142 SEC("socket") 143 __description("bpf_map_ptr: r = 0, map_ptr = map_ptr + r") 144 __success __failure_unpriv 145 __msg_unpriv("R1 has pointer with unsupported alu operation") 146 __retval(0) 147 __naked void map_ptr_map_ptr_r(void) 148 { 149 asm volatile (" \ 150 r0 = 0; \ 151 *(u64*)(r10 - 8) = r0; \ 152 r2 = r10; \ 153 r2 += -8; \ 154 r0 = 0; \ 155 r1 = %[map_hash_16b] ll; \ 156 r1 += r0; \ 157 call %[bpf_map_lookup_elem]; \ 158 r0 = 0; \ 159 exit; \ 160 " : 161 : __imm(bpf_map_lookup_elem), 162 __imm_addr(map_hash_16b) 163 : __clobber_all); 164 } 165 166 SEC("socket") 167 __description("bpf_map_ptr: r = 0, r = r + map_ptr") 168 __success __failure_unpriv 169 __msg_unpriv("R0 has pointer with unsupported alu operation") 170 __retval(0) 171 __naked void _0_r_r_map_ptr(void) 172 { 173 asm volatile (" \ 174 r0 = 0; \ 175 *(u64*)(r10 - 8) = r0; \ 176 r2 = r10; \ 177 r2 += -8; \ 178 r1 = 0; \ 179 r0 = %[map_hash_16b] ll; \ 180 r1 += r0; \ 181 call %[bpf_map_lookup_elem]; \ 182 r0 = 0; \ 183 exit; \ 184 " : 185 : __imm(bpf_map_lookup_elem), 186 __imm_addr(map_hash_16b) 187 : __clobber_all); 188 } 189 190 char _license[] SEC("license") = "GPL"; 191