1 // SPDX-License-Identifier: GPL-2.0 2 /* Converted from tools/testing/selftests/bpf/verifier/ctx.c */ 3 4 #include "vmlinux.h" 5 #include <bpf/bpf_helpers.h> 6 #include "bpf_misc.h" 7 8 #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) 9 10 SEC("tc") 11 __description("context stores via BPF_ATOMIC") 12 __failure __msg("BPF_ATOMIC stores into R1 ctx is not allowed") 13 __naked void context_stores_via_bpf_atomic(void) 14 { 15 asm volatile (" \ 16 r0 = 0; \ 17 lock *(u32 *)(r1 + %[__sk_buff_mark]) += w0; \ 18 exit; \ 19 " : 20 : __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) 21 : __clobber_all); 22 } 23 24 SEC("tc") 25 __description("arithmetic ops make PTR_TO_CTX unusable") 26 __failure __msg("dereference of modified ctx ptr") 27 __naked void make_ptr_to_ctx_unusable(void) 28 { 29 asm volatile (" \ 30 r1 += %[__imm_0]; \ 31 r0 = *(u32*)(r1 + %[__sk_buff_mark]); \ 32 exit; \ 33 " : 34 : __imm_const(__imm_0, 35 offsetof(struct __sk_buff, data) - offsetof(struct __sk_buff, mark)), 36 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) 37 : __clobber_all); 38 } 39 40 SEC("tc") 41 __description("pass unmodified ctx pointer to helper") 42 __success __retval(0) 43 __naked void unmodified_ctx_pointer_to_helper(void) 44 { 45 asm volatile (" \ 46 r2 = 0; \ 47 call %[bpf_csum_update]; \ 48 r0 = 0; \ 49 exit; \ 50 " : 51 : __imm(bpf_csum_update) 52 : __clobber_all); 53 } 54 55 SEC("tc") 56 __description("pass modified ctx pointer to helper, 1") 57 __failure __msg("negative offset ctx ptr R1 off=-612 disallowed") 58 __naked void ctx_pointer_to_helper_1(void) 59 { 60 asm volatile (" \ 61 r1 += -612; \ 62 r2 = 0; \ 63 call %[bpf_csum_update]; \ 64 r0 = 0; \ 65 exit; \ 66 " : 67 : __imm(bpf_csum_update) 68 : __clobber_all); 69 } 70 71 SEC("socket") 72 __description("pass modified ctx pointer to helper, 2") 73 __failure __msg("negative offset ctx ptr R1 off=-612 disallowed") 74 __failure_unpriv __msg_unpriv("negative offset ctx ptr R1 off=-612 disallowed") 75 __naked void ctx_pointer_to_helper_2(void) 76 { 77 asm volatile (" \ 78 r1 += -612; \ 79 call %[bpf_get_socket_cookie]; \ 80 r0 = 0; \ 81 exit; \ 82 " : 83 : __imm(bpf_get_socket_cookie) 84 : __clobber_all); 85 } 86 87 SEC("tc") 88 __description("pass modified ctx pointer to helper, 3") 89 __failure __msg("variable ctx access var_off=(0x0; 0x4)") 90 __naked void ctx_pointer_to_helper_3(void) 91 { 92 asm volatile (" \ 93 r3 = *(u32*)(r1 + 0); \ 94 r3 &= 4; \ 95 r1 += r3; \ 96 r2 = 0; \ 97 call %[bpf_csum_update]; \ 98 r0 = 0; \ 99 exit; \ 100 " : 101 : __imm(bpf_csum_update) 102 : __clobber_all); 103 } 104 105 SEC("cgroup/sendmsg6") 106 __description("pass ctx or null check, 1: ctx") 107 __success 108 __naked void or_null_check_1_ctx(void) 109 { 110 asm volatile (" \ 111 call %[bpf_get_netns_cookie]; \ 112 r0 = 0; \ 113 exit; \ 114 " : 115 : __imm(bpf_get_netns_cookie) 116 : __clobber_all); 117 } 118 119 SEC("cgroup/sendmsg6") 120 __description("pass ctx or null check, 2: null") 121 __success 122 __naked void or_null_check_2_null(void) 123 { 124 asm volatile (" \ 125 r1 = 0; \ 126 call %[bpf_get_netns_cookie]; \ 127 r0 = 0; \ 128 exit; \ 129 " : 130 : __imm(bpf_get_netns_cookie) 131 : __clobber_all); 132 } 133 134 SEC("cgroup/sendmsg6") 135 __description("pass ctx or null check, 3: 1") 136 __failure __msg("R1 type=scalar expected=ctx") 137 __naked void or_null_check_3_1(void) 138 { 139 asm volatile (" \ 140 r1 = 1; \ 141 call %[bpf_get_netns_cookie]; \ 142 r0 = 0; \ 143 exit; \ 144 " : 145 : __imm(bpf_get_netns_cookie) 146 : __clobber_all); 147 } 148 149 SEC("cgroup/sendmsg6") 150 __description("pass ctx or null check, 4: ctx - const") 151 __failure __msg("negative offset ctx ptr R1 off=-612 disallowed") 152 __naked void null_check_4_ctx_const(void) 153 { 154 asm volatile (" \ 155 r1 += -612; \ 156 call %[bpf_get_netns_cookie]; \ 157 r0 = 0; \ 158 exit; \ 159 " : 160 : __imm(bpf_get_netns_cookie) 161 : __clobber_all); 162 } 163 164 SEC("cgroup/connect4") 165 __description("pass ctx or null check, 5: null (connect)") 166 __success 167 __naked void null_check_5_null_connect(void) 168 { 169 asm volatile (" \ 170 r1 = 0; \ 171 call %[bpf_get_netns_cookie]; \ 172 r0 = 0; \ 173 exit; \ 174 " : 175 : __imm(bpf_get_netns_cookie) 176 : __clobber_all); 177 } 178 179 SEC("cgroup/post_bind4") 180 __description("pass ctx or null check, 6: null (bind)") 181 __success 182 __naked void null_check_6_null_bind(void) 183 { 184 asm volatile (" \ 185 r1 = 0; \ 186 call %[bpf_get_netns_cookie]; \ 187 r0 = 0; \ 188 exit; \ 189 " : 190 : __imm(bpf_get_netns_cookie) 191 : __clobber_all); 192 } 193 194 SEC("cgroup/post_bind4") 195 __description("pass ctx or null check, 7: ctx (bind)") 196 __success 197 __naked void null_check_7_ctx_bind(void) 198 { 199 asm volatile (" \ 200 call %[bpf_get_socket_cookie]; \ 201 r0 = 0; \ 202 exit; \ 203 " : 204 : __imm(bpf_get_socket_cookie) 205 : __clobber_all); 206 } 207 208 SEC("cgroup/post_bind4") 209 __description("pass ctx or null check, 8: null (bind)") 210 __failure __msg("R1 type=scalar expected=ctx") 211 __naked void null_check_8_null_bind(void) 212 { 213 asm volatile (" \ 214 r1 = 0; \ 215 call %[bpf_get_socket_cookie]; \ 216 r0 = 0; \ 217 exit; \ 218 " : 219 : __imm(bpf_get_socket_cookie) 220 : __clobber_all); 221 } 222 223 #define narrow_load(type, ctx, field) \ 224 SEC(type) \ 225 __description("narrow load on field " #field " of " #ctx) \ 226 __failure __msg("invalid bpf_context access") \ 227 __naked void invalid_narrow_load##ctx##field(void) \ 228 { \ 229 asm volatile (" \ 230 r1 = *(u32 *)(r1 + %[off]); \ 231 r0 = 0; \ 232 exit;" \ 233 : \ 234 : __imm_const(off, offsetof(struct ctx, field) + 4) \ 235 : __clobber_all); \ 236 } 237 238 narrow_load("cgroup/getsockopt", bpf_sockopt, sk); 239 narrow_load("cgroup/getsockopt", bpf_sockopt, optval); 240 narrow_load("cgroup/getsockopt", bpf_sockopt, optval_end); 241 narrow_load("tc", __sk_buff, sk); 242 narrow_load("cgroup/bind4", bpf_sock_addr, sk); 243 narrow_load("sockops", bpf_sock_ops, sk); 244 narrow_load("sockops", bpf_sock_ops, skb_data); 245 narrow_load("sockops", bpf_sock_ops, skb_data_end); 246 narrow_load("sockops", bpf_sock_ops, skb_hwtstamp); 247 248 #define unaligned_access(type, ctx, field) \ 249 SEC(type) \ 250 __description("unaligned access on field " #field " of " #ctx) \ 251 __failure __msg("invalid bpf_context access") \ 252 __naked void unaligned_ctx_access_##ctx##field(void) \ 253 { \ 254 asm volatile (" \ 255 r1 = *(u%[size] *)(r1 + %[off]); \ 256 r0 = 0; \ 257 exit;" \ 258 : \ 259 : __imm_const(size, sizeof_field(struct ctx, field) * 8), \ 260 __imm_const(off, offsetof(struct ctx, field) + 1) \ 261 : __clobber_all); \ 262 } 263 264 unaligned_access("flow_dissector", __sk_buff, data); 265 unaligned_access("netfilter", bpf_nf_ctx, skb); 266 267 char _license[] SEC("license") = "GPL"; 268