1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3 4 #include <vmlinux.h> 5 #include <bpf/bpf_helpers.h> 6 #include <bpf/bpf_tracing.h> 7 #include <bpf/bpf_core_read.h> 8 #include "bpf_misc.h" 9 #include "xdp_metadata.h" 10 #include "bpf_kfuncs.h" 11 12 extern struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym __weak; 13 extern void bpf_task_release(struct task_struct *p) __ksym __weak; 14 15 __weak int subprog_trusted_task_nullable(struct task_struct *task __arg_trusted __arg_nullable) 16 { 17 if (!task) 18 return 0; 19 return task->pid + task->tgid; 20 } 21 22 __weak int subprog_trusted_task_nullable_extra_layer(struct task_struct *task __arg_trusted __arg_nullable) 23 { 24 return subprog_trusted_task_nullable(task) + subprog_trusted_task_nullable(NULL); 25 } 26 27 SEC("?tp_btf/task_newtask") 28 __success __log_level(2) 29 __msg("Validating subprog_trusted_task_nullable() func#1...") 30 __msg(": R1=trusted_ptr_or_null_task_struct(") 31 int trusted_task_arg_nullable(void *ctx) 32 { 33 struct task_struct *t1 = bpf_get_current_task_btf(); 34 struct task_struct *t2 = bpf_task_acquire(t1); 35 int res = 0; 36 37 /* known NULL */ 38 res += subprog_trusted_task_nullable(NULL); 39 40 /* known non-NULL */ 41 res += subprog_trusted_task_nullable(t1); 42 res += subprog_trusted_task_nullable_extra_layer(t1); 43 44 /* unknown if NULL or not */ 45 res += subprog_trusted_task_nullable(t2); 46 res += subprog_trusted_task_nullable_extra_layer(t2); 47 48 if (t2) { 49 /* known non-NULL after explicit NULL check, just in case */ 50 res += subprog_trusted_task_nullable(t2); 51 res += subprog_trusted_task_nullable_extra_layer(t2); 52 53 bpf_task_release(t2); 54 } 55 56 return res; 57 } 58 59 /* 60 * Check that the verifier does not use checkpoints created 61 * on path with r1 == 0 to prune path with r1 != 0. 62 */ 63 SEC("?tp_btf/task_newtask") 64 __failure 65 __flag(BPF_F_TEST_STATE_FREQ) 66 __msg("R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_") 67 __naked int null_btf_id_arg_global_subprog(void) 68 { 69 asm volatile ( 70 "call %[bpf_get_prandom_u32];" 71 "r1 = 42;" 72 "if r0 > 42 goto 1f;" 73 "r1 = 0;" 74 "1:" 75 "call subprog_trusted_task_nullable;" 76 "r0 = 0;" 77 "exit;" 78 : 79 : __imm(bpf_get_prandom_u32) 80 : __clobber_all); 81 } 82 83 __weak int subprog_trusted_task_nonnull(struct task_struct *task __arg_trusted) 84 { 85 return task->pid + task->tgid; 86 } 87 88 SEC("?kprobe") 89 __failure __log_level(2) 90 __msg("R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_") 91 __msg("Caller passes invalid args into func#1 ('subprog_trusted_task_nonnull')") 92 int trusted_task_arg_nonnull_fail1(void *ctx) 93 { 94 return subprog_trusted_task_nonnull(NULL); 95 } 96 97 SEC("?tp_btf/task_newtask") 98 __failure __log_level(2) 99 __msg("R1 type=trusted_ptr_or_null_ expected=ptr_, trusted_ptr_, rcu_ptr_") 100 __msg("Caller passes invalid args into func#1 ('subprog_trusted_task_nonnull')") 101 int trusted_task_arg_nonnull_fail2(void *ctx) 102 { 103 struct task_struct *t = bpf_get_current_task_btf(); 104 struct task_struct *nullable; 105 int res; 106 107 nullable = bpf_task_acquire(t); 108 109 /* should fail, PTR_TO_BTF_ID_OR_NULL */ 110 res = subprog_trusted_task_nonnull(nullable); 111 112 if (nullable) 113 bpf_task_release(nullable); 114 115 return res; 116 } 117 118 SEC("?kprobe") 119 __success __log_level(2) 120 __msg("Validating subprog_trusted_task_nonnull() func#1...") 121 __msg(": R1=trusted_ptr_task_struct(") 122 int trusted_task_arg_nonnull(void *ctx) 123 { 124 struct task_struct *t = bpf_get_current_task_btf(); 125 126 return subprog_trusted_task_nonnull(t); 127 } 128 129 struct task_struct___local {} __attribute__((preserve_access_index)); 130 131 __weak int subprog_nullable_task_flavor( 132 struct task_struct___local *task __arg_trusted __arg_nullable) 133 { 134 char buf[16]; 135 136 if (!task) 137 return 0; 138 139 return bpf_copy_from_user_task(&buf, sizeof(buf), NULL, (void *)task, 0); 140 } 141 142 SEC("?uprobe.s") 143 __success __log_level(2) 144 __msg("Validating subprog_nullable_task_flavor() func#1...") 145 __msg(": R1=trusted_ptr_or_null_task_struct(") 146 int flavor_ptr_nullable(void *ctx) 147 { 148 struct task_struct___local *t = (void *)bpf_get_current_task_btf(); 149 150 return subprog_nullable_task_flavor(t); 151 } 152 153 __weak int subprog_nonnull_task_flavor(struct task_struct___local *task __arg_trusted) 154 { 155 char buf[16]; 156 157 return bpf_copy_from_user_task(&buf, sizeof(buf), NULL, (void *)task, 0); 158 } 159 160 SEC("?uprobe.s") 161 __success __log_level(2) 162 __msg("Validating subprog_nonnull_task_flavor() func#1...") 163 __msg(": R1=trusted_ptr_task_struct(") 164 int flavor_ptr_nonnull(void *ctx) 165 { 166 struct task_struct *t = bpf_get_current_task_btf(); 167 168 return subprog_nonnull_task_flavor((void *)t); 169 } 170 171 __weak int subprog_trusted_destroy(struct task_struct *task __arg_trusted) 172 { 173 bpf_task_release(task); /* should be rejected */ 174 175 return 0; 176 } 177 178 SEC("?tp_btf/task_newtask") 179 __failure __log_level(2) 180 __msg("release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1") 181 int BPF_PROG(trusted_destroy_fail, struct task_struct *task, u64 clone_flags) 182 { 183 return subprog_trusted_destroy(task); 184 } 185 186 __weak int subprog_trusted_acq_rel(struct task_struct *task __arg_trusted) 187 { 188 struct task_struct *owned; 189 190 owned = bpf_task_acquire(task); 191 if (!owned) 192 return 0; 193 194 bpf_task_release(owned); /* this one is OK, we acquired it locally */ 195 196 return 0; 197 } 198 199 SEC("?tp_btf/task_newtask") 200 __success __log_level(2) 201 int BPF_PROG(trusted_acq_rel, struct task_struct *task, u64 clone_flags) 202 { 203 return subprog_trusted_acq_rel(task); 204 } 205 206 __weak int subprog_untrusted_bad_tags(struct task_struct *task __arg_untrusted __arg_nullable) 207 { 208 return task->pid; 209 } 210 211 SEC("tp_btf/sys_enter") 212 __failure 213 __msg("arg#0 untrusted cannot be combined with any other tags") 214 int untrusted_bad_tags(void *ctx) 215 { 216 return subprog_untrusted_bad_tags(0); 217 } 218 219 struct local_type_wont_be_accepted {}; 220 221 __weak int subprog_untrusted_bad_type(struct local_type_wont_be_accepted *p __arg_untrusted) 222 { 223 return 0; 224 } 225 226 SEC("tp_btf/sys_enter") 227 __failure 228 __msg("arg#0 reference type('STRUCT local_type_wont_be_accepted') has no matches") 229 int untrusted_bad_type(void *ctx) 230 { 231 return subprog_untrusted_bad_type(bpf_rdonly_cast(0, 0)); 232 } 233 234 __weak int subprog_untrusted(const volatile struct task_struct *restrict task __arg_untrusted) 235 { 236 return task->pid; 237 } 238 239 SEC("tp_btf/sys_enter") 240 __success 241 __log_level(2) 242 __msg("r1 = {{.*}}; {{.*}}R1=trusted_ptr_task_struct()") 243 __msg("Func#1 ('subprog_untrusted') is global and assumed valid.") 244 __msg("Validating subprog_untrusted() func#1...") 245 __msg(": R1=untrusted_ptr_task_struct") 246 int trusted_to_untrusted(void *ctx) 247 { 248 return subprog_untrusted(bpf_get_current_task_btf()); 249 } 250 251 char mem[16]; 252 u32 offset; 253 254 SEC("tp_btf/sys_enter") 255 __success 256 int anything_to_untrusted(void *ctx) 257 { 258 /* untrusted to untrusted */ 259 subprog_untrusted(bpf_core_cast(0, struct task_struct)); 260 /* wrong type to untrusted */ 261 subprog_untrusted((void *)bpf_core_cast(0, struct bpf_verifier_env)); 262 /* map value to untrusted */ 263 subprog_untrusted((void *)mem); 264 /* scalar to untrusted */ 265 subprog_untrusted(0); 266 /* variable offset to untrusted (map) */ 267 subprog_untrusted((void *)mem + offset); 268 /* variable offset to untrusted (trusted) */ 269 subprog_untrusted((void *)bpf_get_current_task_btf() + offset); 270 return 0; 271 } 272 273 __weak int subprog_untrusted2(struct task_struct *task __arg_untrusted) 274 { 275 return subprog_trusted_task_nullable(task); 276 } 277 278 SEC("tp_btf/sys_enter") 279 __failure 280 __msg("R1 type=untrusted_ptr_ expected=ptr_, trusted_ptr_, rcu_ptr_") 281 __msg("Caller passes invalid args into func#{{.*}} ('subprog_trusted_task_nullable')") 282 int untrusted_to_trusted(void *ctx) 283 { 284 return subprog_untrusted2(bpf_get_current_task_btf()); 285 } 286 287 __weak int subprog_void_untrusted(void *p __arg_untrusted) 288 { 289 return *(int *)p; 290 } 291 292 __weak int subprog_char_untrusted(char *p __arg_untrusted) 293 { 294 return *(int *)p; 295 } 296 297 __weak int subprog_enum_untrusted(enum bpf_attach_type *p __arg_untrusted) 298 { 299 return *(int *)p; 300 } 301 302 SEC("tp_btf/sys_enter") 303 __success 304 __log_level(2) 305 __msg("r1 = {{.*}}; {{.*}}R1=trusted_ptr_task_struct()") 306 __msg("Func#1 ('subprog_void_untrusted') is global and assumed valid.") 307 __msg("Validating subprog_void_untrusted() func#1...") 308 __msg(": R1=rdonly_untrusted_mem(sz=0)") 309 int trusted_to_untrusted_mem(void *ctx) 310 { 311 return subprog_void_untrusted(bpf_get_current_task_btf()); 312 } 313 314 __weak int subprog_write_mem_arg(int *p) 315 { 316 if (!p) 317 return 0; 318 319 *p = 42; 320 return 0; 321 } 322 323 SEC("?tp_btf/task_newtask") 324 __failure 325 __msg("only read is supported") 326 int trusted_btf_field_to_writable_mem(void *ctx) 327 { 328 struct task_struct *task = bpf_get_current_task_btf(); 329 330 return subprog_write_mem_arg(&task->prio); 331 } 332 333 SEC("tp_btf/sys_enter") 334 __success 335 int anything_to_untrusted_mem(void *ctx) 336 { 337 /* untrusted to untrusted mem */ 338 subprog_void_untrusted(bpf_core_cast(0, struct task_struct)); 339 /* map value to untrusted mem */ 340 subprog_void_untrusted(mem); 341 /* scalar to untrusted mem */ 342 subprog_void_untrusted(0); 343 /* variable offset to untrusted mem (map) */ 344 subprog_void_untrusted((void *)mem + offset); 345 /* variable offset to untrusted mem (trusted) */ 346 subprog_void_untrusted(bpf_get_current_task_btf() + offset); 347 /* variable offset to untrusted char/enum (map) */ 348 subprog_char_untrusted(mem + offset); 349 subprog_enum_untrusted((void *)mem + offset); 350 return 0; 351 } 352 353 struct pkt_arg { 354 __u64 x; 355 __u8 pad[56]; 356 }; 357 358 __weak int subprog_pkt_ptr_no_change(struct pkt_arg *p) 359 { 360 if (!p) 361 return 0; 362 363 return p->x; 364 } 365 366 SEC("?tc") 367 __success 368 int pkt_ptr_to_global_mem_arg_no_change(struct __sk_buff *skb) 369 { 370 void *data = (void *)(long)skb->data; 371 void *data_end = (void *)(long)skb->data_end; 372 struct pkt_arg *p = data; 373 374 if ((void *)(p + 1) > data_end) 375 return 0; 376 377 return subprog_pkt_ptr_no_change(p); 378 } 379 380 __weak int subprog_pkt_ptr_changes_data(struct __sk_buff *skb __arg_ctx, 381 struct pkt_arg *p) 382 { 383 if (!p) 384 return 0; 385 386 bpf_skb_pull_data(skb, 0); 387 return p->x; 388 } 389 390 SEC("?tc") 391 __failure __log_level(2) 392 __msg("R2 is a packet pointer, but func#{{[0-9]+}} may change packet data") 393 __msg("Caller passes invalid args into func#{{[0-9]+}} ('subprog_pkt_ptr_changes_data')") 394 int pkt_ptr_to_global_mem_arg_changes_data(struct __sk_buff *skb) 395 { 396 void *data = (void *)(long)skb->data; 397 void *data_end = (void *)(long)skb->data_end; 398 struct pkt_arg *p = data; 399 400 if ((void *)(p + 1) > data_end) 401 return 0; 402 403 return subprog_pkt_ptr_changes_data(skb, p); 404 } 405 406 char _license[] SEC("license") = "GPL"; 407