1 // SPDX-License-Identifier: GPL-2.0 2 /* Converted from tools/testing/selftests/bpf/verifier/bounds_mix_sign_unsign.c */ 3 4 #include <linux/bpf.h> 5 #include <bpf/bpf_helpers.h> 6 #include "bpf_misc.h" 7 8 struct { 9 __uint(type, BPF_MAP_TYPE_HASH); 10 __uint(max_entries, 1); 11 __type(key, long long); 12 __type(value, long long); 13 } map_hash_8b SEC(".maps"); 14 15 SEC("socket") 16 __description("bounds checks mixing signed and unsigned, positive bounds") 17 __failure __msg("unbounded min value") 18 __failure_unpriv 19 __naked void signed_and_unsigned_positive_bounds(void) 20 { 21 asm volatile (" \ 22 call %[bpf_ktime_get_ns]; \ 23 *(u64*)(r10 - 16) = r0; \ 24 r1 = 0; \ 25 *(u64*)(r10 - 8) = r1; \ 26 r2 = r10; \ 27 r2 += -8; \ 28 r1 = %[map_hash_8b] ll; \ 29 call %[bpf_map_lookup_elem]; \ 30 if r0 == 0 goto l0_%=; \ 31 r1 = *(u64*)(r10 - 16); \ 32 r2 = 2; \ 33 if r2 >= r1 goto l0_%=; \ 34 if r1 s> 4 goto l0_%=; \ 35 r0 += r1; \ 36 r1 = 0; \ 37 *(u8*)(r0 + 0) = r1; \ 38 l0_%=: r0 = 0; \ 39 exit; \ 40 " : 41 : __imm(bpf_ktime_get_ns), 42 __imm(bpf_map_lookup_elem), 43 __imm_addr(map_hash_8b) 44 : __clobber_all); 45 } 46 47 SEC("socket") 48 __description("bounds checks mixing signed and unsigned") 49 __failure __msg("unbounded min value") 50 __failure_unpriv 51 __naked void checks_mixing_signed_and_unsigned(void) 52 { 53 asm volatile (" \ 54 call %[bpf_ktime_get_ns]; \ 55 *(u64*)(r10 - 16) = r0; \ 56 r1 = 0; \ 57 *(u64*)(r10 - 8) = r1; \ 58 r2 = r10; \ 59 r2 += -8; \ 60 r1 = %[map_hash_8b] ll; \ 61 call %[bpf_map_lookup_elem]; \ 62 if r0 == 0 goto l0_%=; \ 63 r1 = *(u64*)(r10 - 16); \ 64 r2 = -1; \ 65 if r1 > r2 goto l0_%=; \ 66 if r1 s> 1 goto l0_%=; \ 67 r0 += r1; \ 68 r1 = 0; \ 69 *(u8*)(r0 + 0) = r1; \ 70 l0_%=: r0 = 0; \ 71 exit; \ 72 " : 73 : __imm(bpf_ktime_get_ns), 74 __imm(bpf_map_lookup_elem), 75 __imm_addr(map_hash_8b) 76 : __clobber_all); 77 } 78 79 SEC("socket") 80 __description("bounds checks mixing signed and unsigned, variant 2") 81 __failure __msg("unbounded min value") 82 __failure_unpriv 83 __naked void signed_and_unsigned_variant_2(void) 84 { 85 asm volatile (" \ 86 call %[bpf_ktime_get_ns]; \ 87 *(u64*)(r10 - 16) = r0; \ 88 r1 = 0; \ 89 *(u64*)(r10 - 8) = r1; \ 90 r2 = r10; \ 91 r2 += -8; \ 92 r1 = %[map_hash_8b] ll; \ 93 call %[bpf_map_lookup_elem]; \ 94 if r0 == 0 goto l0_%=; \ 95 r1 = *(u64*)(r10 - 16); \ 96 r2 = -1; \ 97 if r1 > r2 goto l0_%=; \ 98 r8 = 0; \ 99 r8 += r1; \ 100 if r8 s> 1 goto l0_%=; \ 101 r0 += r8; \ 102 r0 = 0; \ 103 *(u8*)(r8 + 0) = r0; \ 104 l0_%=: r0 = 0; \ 105 exit; \ 106 " : 107 : __imm(bpf_ktime_get_ns), 108 __imm(bpf_map_lookup_elem), 109 __imm_addr(map_hash_8b) 110 : __clobber_all); 111 } 112 113 SEC("socket") 114 __description("bounds checks mixing signed and unsigned, variant 3") 115 __failure __msg("unbounded min value") 116 __failure_unpriv 117 __naked void signed_and_unsigned_variant_3(void) 118 { 119 asm volatile (" \ 120 call %[bpf_ktime_get_ns]; \ 121 *(u64*)(r10 - 16) = r0; \ 122 r1 = 0; \ 123 *(u64*)(r10 - 8) = r1; \ 124 r2 = r10; \ 125 r2 += -8; \ 126 r1 = %[map_hash_8b] ll; \ 127 call %[bpf_map_lookup_elem]; \ 128 if r0 == 0 goto l0_%=; \ 129 r1 = *(u64*)(r10 - 16); \ 130 r2 = -1; \ 131 if r1 > r2 goto l0_%=; \ 132 r8 = r1; \ 133 if r8 s> 1 goto l0_%=; \ 134 r0 += r8; \ 135 r0 = 0; \ 136 *(u8*)(r8 + 0) = r0; \ 137 l0_%=: r0 = 0; \ 138 exit; \ 139 " : 140 : __imm(bpf_ktime_get_ns), 141 __imm(bpf_map_lookup_elem), 142 __imm_addr(map_hash_8b) 143 : __clobber_all); 144 } 145 146 SEC("socket") 147 __description("bounds checks mixing signed and unsigned, variant 4") 148 __success __success_unpriv __retval(0) 149 __naked void signed_and_unsigned_variant_4(void) 150 { 151 asm volatile (" \ 152 call %[bpf_ktime_get_ns]; \ 153 *(u64*)(r10 - 16) = r0; \ 154 r1 = 0; \ 155 *(u64*)(r10 - 8) = r1; \ 156 r2 = r10; \ 157 r2 += -8; \ 158 r1 = %[map_hash_8b] ll; \ 159 call %[bpf_map_lookup_elem]; \ 160 if r0 == 0 goto l0_%=; \ 161 r1 = *(u64*)(r10 - 16); \ 162 r2 = 1; \ 163 r1 &= r2; \ 164 if r1 s> 1 goto l0_%=; \ 165 r0 += r1; \ 166 r1 = 0; \ 167 *(u8*)(r0 + 0) = r1; \ 168 l0_%=: r0 = 0; \ 169 exit; \ 170 " : 171 : __imm(bpf_ktime_get_ns), 172 __imm(bpf_map_lookup_elem), 173 __imm_addr(map_hash_8b) 174 : __clobber_all); 175 } 176 177 SEC("socket") 178 __description("bounds checks mixing signed and unsigned, variant 5") 179 __failure __msg("unbounded min value") 180 __failure_unpriv 181 __naked void signed_and_unsigned_variant_5(void) 182 { 183 asm volatile (" \ 184 call %[bpf_ktime_get_ns]; \ 185 *(u64*)(r10 - 16) = r0; \ 186 r1 = 0; \ 187 *(u64*)(r10 - 8) = r1; \ 188 r2 = r10; \ 189 r2 += -8; \ 190 r1 = %[map_hash_8b] ll; \ 191 call %[bpf_map_lookup_elem]; \ 192 if r0 == 0 goto l0_%=; \ 193 r1 = *(u64*)(r10 - 16); \ 194 r2 = -1; \ 195 if r1 > r2 goto l0_%=; \ 196 if r1 s> 1 goto l0_%=; \ 197 r0 += 4; \ 198 r0 -= r1; \ 199 r1 = 0; \ 200 *(u8*)(r0 + 0) = r1; \ 201 r0 = 0; \ 202 l0_%=: exit; \ 203 " : 204 : __imm(bpf_ktime_get_ns), 205 __imm(bpf_map_lookup_elem), 206 __imm_addr(map_hash_8b) 207 : __clobber_all); 208 } 209 210 SEC("socket") 211 __description("bounds checks mixing signed and unsigned, variant 6") 212 __failure __msg("R4 min value is negative, either use unsigned") 213 __failure_unpriv 214 __naked void signed_and_unsigned_variant_6(void) 215 { 216 asm volatile (" \ 217 r9 = r1; \ 218 call %[bpf_ktime_get_ns]; \ 219 *(u64*)(r10 - 16) = r0; \ 220 r1 = r9; \ 221 r2 = 0; \ 222 r3 = r10; \ 223 r3 += -512; \ 224 r4 = *(u64*)(r10 - 16); \ 225 r6 = -1; \ 226 if r4 > r6 goto l0_%=; \ 227 if r4 s> 1 goto l0_%=; \ 228 r4 += 1; \ 229 r5 = 0; \ 230 r6 = 0; \ 231 *(u16*)(r10 - 512) = r6; \ 232 call %[bpf_skb_load_bytes]; \ 233 l0_%=: r0 = 0; \ 234 exit; \ 235 " : 236 : __imm(bpf_ktime_get_ns), 237 __imm(bpf_skb_load_bytes) 238 : __clobber_all); 239 } 240 241 SEC("socket") 242 __description("bounds checks mixing signed and unsigned, variant 7") 243 __success __success_unpriv __retval(0) 244 __naked void signed_and_unsigned_variant_7(void) 245 { 246 asm volatile (" \ 247 call %[bpf_ktime_get_ns]; \ 248 *(u64*)(r10 - 16) = r0; \ 249 r1 = 0; \ 250 *(u64*)(r10 - 8) = r1; \ 251 r2 = r10; \ 252 r2 += -8; \ 253 r1 = %[map_hash_8b] ll; \ 254 call %[bpf_map_lookup_elem]; \ 255 if r0 == 0 goto l0_%=; \ 256 r1 = *(u64*)(r10 - 16); \ 257 r2 = %[__imm_0]; \ 258 if r1 > r2 goto l0_%=; \ 259 if r1 s> 1 goto l0_%=; \ 260 r0 += r1; \ 261 r1 = 0; \ 262 *(u8*)(r0 + 0) = r1; \ 263 l0_%=: r0 = 0; \ 264 exit; \ 265 " : 266 : __imm(bpf_ktime_get_ns), 267 __imm(bpf_map_lookup_elem), 268 __imm_addr(map_hash_8b), 269 __imm_const(__imm_0, 1024 * 1024 * 1024) 270 : __clobber_all); 271 } 272 273 SEC("socket") 274 __description("bounds checks mixing signed and unsigned, variant 8") 275 __failure __msg("unbounded min value") 276 __failure_unpriv 277 __naked void signed_and_unsigned_variant_8(void) 278 { 279 asm volatile (" \ 280 call %[bpf_ktime_get_ns]; \ 281 *(u64*)(r10 - 16) = r0; \ 282 r1 = 0; \ 283 *(u64*)(r10 - 8) = r1; \ 284 r2 = r10; \ 285 r2 += -8; \ 286 r1 = %[map_hash_8b] ll; \ 287 call %[bpf_map_lookup_elem]; \ 288 if r0 == 0 goto l0_%=; \ 289 r1 = *(u64*)(r10 - 16); \ 290 r2 = -1; \ 291 if r2 > r1 goto l1_%=; \ 292 r0 = 0; \ 293 exit; \ 294 l1_%=: if r1 s> 1 goto l0_%=; \ 295 r0 += r1; \ 296 r1 = 0; \ 297 *(u8*)(r0 + 0) = r1; \ 298 l0_%=: r0 = 0; \ 299 exit; \ 300 " : 301 : __imm(bpf_ktime_get_ns), 302 __imm(bpf_map_lookup_elem), 303 __imm_addr(map_hash_8b) 304 : __clobber_all); 305 } 306 307 SEC("socket") 308 __description("bounds checks mixing signed and unsigned, variant 9") 309 __success __success_unpriv __retval(0) 310 __naked void signed_and_unsigned_variant_9(void) 311 { 312 asm volatile (" \ 313 call %[bpf_ktime_get_ns]; \ 314 *(u64*)(r10 - 16) = r0; \ 315 r1 = 0; \ 316 *(u64*)(r10 - 8) = r1; \ 317 r2 = r10; \ 318 r2 += -8; \ 319 r1 = %[map_hash_8b] ll; \ 320 call %[bpf_map_lookup_elem]; \ 321 if r0 == 0 goto l0_%=; \ 322 r1 = *(u64*)(r10 - 16); \ 323 r2 = -9223372036854775808ULL ll; \ 324 if r2 > r1 goto l1_%=; \ 325 r0 = 0; \ 326 exit; \ 327 l1_%=: if r1 s> 1 goto l0_%=; \ 328 r0 += r1; \ 329 r1 = 0; \ 330 *(u8*)(r0 + 0) = r1; \ 331 l0_%=: r0 = 0; \ 332 exit; \ 333 " : 334 : __imm(bpf_ktime_get_ns), 335 __imm(bpf_map_lookup_elem), 336 __imm_addr(map_hash_8b) 337 : __clobber_all); 338 } 339 340 SEC("socket") 341 __description("bounds checks mixing signed and unsigned, variant 10") 342 __failure __msg("unbounded min value") 343 __failure_unpriv 344 __naked void signed_and_unsigned_variant_10(void) 345 { 346 asm volatile (" \ 347 call %[bpf_ktime_get_ns]; \ 348 *(u64*)(r10 - 16) = r0; \ 349 r1 = 0; \ 350 *(u64*)(r10 - 8) = r1; \ 351 r2 = r10; \ 352 r2 += -8; \ 353 r1 = %[map_hash_8b] ll; \ 354 call %[bpf_map_lookup_elem]; \ 355 if r0 == 0 goto l0_%=; \ 356 r1 = *(u64*)(r10 - 16); \ 357 r2 = -1; \ 358 if r2 > r1 goto l1_%=; \ 359 r0 = 0; \ 360 exit; \ 361 l1_%=: if r1 s> 1 goto l0_%=; \ 362 r0 += r1; \ 363 r1 = 0; \ 364 *(u8*)(r0 + 0) = r1; \ 365 l0_%=: r0 = 0; \ 366 exit; \ 367 " : 368 : __imm(bpf_ktime_get_ns), 369 __imm(bpf_map_lookup_elem), 370 __imm_addr(map_hash_8b) 371 : __clobber_all); 372 } 373 374 SEC("socket") 375 __description("bounds checks mixing signed and unsigned, variant 11") 376 __failure __msg("unbounded min value") 377 __failure_unpriv 378 __naked void signed_and_unsigned_variant_11(void) 379 { 380 asm volatile (" \ 381 call %[bpf_ktime_get_ns]; \ 382 *(u64*)(r10 - 16) = r0; \ 383 r1 = 0; \ 384 *(u64*)(r10 - 8) = r1; \ 385 r2 = r10; \ 386 r2 += -8; \ 387 r1 = %[map_hash_8b] ll; \ 388 call %[bpf_map_lookup_elem]; \ 389 if r0 == 0 goto l0_%=; \ 390 r1 = *(u64*)(r10 - 16); \ 391 r2 = -1; \ 392 if r2 >= r1 goto l1_%=; \ 393 /* Dead branch. */ \ 394 r0 = 0; \ 395 exit; \ 396 l1_%=: if r1 s> 1 goto l0_%=; \ 397 r0 += r1; \ 398 r1 = 0; \ 399 *(u8*)(r0 + 0) = r1; \ 400 l0_%=: r0 = 0; \ 401 exit; \ 402 " : 403 : __imm(bpf_ktime_get_ns), 404 __imm(bpf_map_lookup_elem), 405 __imm_addr(map_hash_8b) 406 : __clobber_all); 407 } 408 409 SEC("socket") 410 __description("bounds checks mixing signed and unsigned, variant 12") 411 __failure __msg("unbounded min value") 412 __failure_unpriv 413 __naked void signed_and_unsigned_variant_12(void) 414 { 415 asm volatile (" \ 416 call %[bpf_ktime_get_ns]; \ 417 *(u64*)(r10 - 16) = r0; \ 418 r1 = 0; \ 419 *(u64*)(r10 - 8) = r1; \ 420 r2 = r10; \ 421 r2 += -8; \ 422 r1 = %[map_hash_8b] ll; \ 423 call %[bpf_map_lookup_elem]; \ 424 if r0 == 0 goto l0_%=; \ 425 r1 = *(u64*)(r10 - 16); \ 426 r2 = -6; \ 427 if r2 >= r1 goto l1_%=; \ 428 r0 = 0; \ 429 exit; \ 430 l1_%=: if r1 s> 1 goto l0_%=; \ 431 r0 += r1; \ 432 r1 = 0; \ 433 *(u8*)(r0 + 0) = r1; \ 434 l0_%=: r0 = 0; \ 435 exit; \ 436 " : 437 : __imm(bpf_ktime_get_ns), 438 __imm(bpf_map_lookup_elem), 439 __imm_addr(map_hash_8b) 440 : __clobber_all); 441 } 442 443 SEC("socket") 444 __description("bounds checks mixing signed and unsigned, variant 13") 445 __failure __msg("unbounded min value") 446 __failure_unpriv 447 __naked void signed_and_unsigned_variant_13(void) 448 { 449 asm volatile (" \ 450 call %[bpf_ktime_get_ns]; \ 451 *(u64*)(r10 - 16) = r0; \ 452 r1 = 0; \ 453 *(u64*)(r10 - 8) = r1; \ 454 r2 = r10; \ 455 r2 += -8; \ 456 r1 = %[map_hash_8b] ll; \ 457 call %[bpf_map_lookup_elem]; \ 458 if r0 == 0 goto l0_%=; \ 459 r1 = *(u64*)(r10 - 16); \ 460 r2 = 2; \ 461 if r2 >= r1 goto l0_%=; \ 462 r7 = 1; \ 463 if r7 s> 0 goto l1_%=; \ 464 l0_%=: r0 = 0; \ 465 exit; \ 466 l1_%=: r7 += r1; \ 467 if r7 s> 4 goto l2_%=; \ 468 r0 += r7; \ 469 r1 = 0; \ 470 *(u8*)(r0 + 0) = r1; \ 471 l2_%=: r0 = 0; \ 472 exit; \ 473 " : 474 : __imm(bpf_ktime_get_ns), 475 __imm(bpf_map_lookup_elem), 476 __imm_addr(map_hash_8b) 477 : __clobber_all); 478 } 479 480 SEC("socket") 481 __description("bounds checks mixing signed and unsigned, variant 14") 482 __failure __msg("unbounded min value") 483 __failure_unpriv 484 __naked void signed_and_unsigned_variant_14(void) 485 { 486 asm volatile (" \ 487 r9 = *(u32*)(r1 + %[__sk_buff_mark]); \ 488 call %[bpf_ktime_get_ns]; \ 489 *(u64*)(r10 - 16) = r0; \ 490 r1 = 0; \ 491 *(u64*)(r10 - 8) = r1; \ 492 r2 = r10; \ 493 r2 += -8; \ 494 r1 = %[map_hash_8b] ll; \ 495 call %[bpf_map_lookup_elem]; \ 496 if r0 == 0 goto l0_%=; \ 497 r1 = *(u64*)(r10 - 16); \ 498 r2 = -1; \ 499 r8 = 2; \ 500 if r9 == 42 goto l1_%=; \ 501 if r8 s> r1 goto l2_%=; \ 502 l3_%=: if r1 s> 1 goto l2_%=; \ 503 r0 += r1; \ 504 l0_%=: r1 = 0; \ 505 *(u8*)(r0 + 0) = r1; \ 506 l2_%=: r0 = 0; \ 507 exit; \ 508 l1_%=: if r1 > r2 goto l2_%=; \ 509 goto l3_%=; \ 510 " : 511 : __imm(bpf_ktime_get_ns), 512 __imm(bpf_map_lookup_elem), 513 __imm_addr(map_hash_8b), 514 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) 515 : __clobber_all); 516 } 517 518 SEC("socket") 519 __description("bounds checks mixing signed and unsigned, variant 15") 520 __failure __msg("unbounded min value") 521 __failure_unpriv 522 __naked void signed_and_unsigned_variant_15(void) 523 { 524 asm volatile (" \ 525 call %[bpf_ktime_get_ns]; \ 526 *(u64*)(r10 - 16) = r0; \ 527 r1 = 0; \ 528 *(u64*)(r10 - 8) = r1; \ 529 r2 = r10; \ 530 r2 += -8; \ 531 r1 = %[map_hash_8b] ll; \ 532 call %[bpf_map_lookup_elem]; \ 533 if r0 == 0 goto l0_%=; \ 534 r1 = *(u64*)(r10 - 16); \ 535 r2 = -6; \ 536 if r2 >= r1 goto l1_%=; \ 537 l0_%=: r0 = 0; \ 538 exit; \ 539 l1_%=: r0 += r1; \ 540 if r0 > 1 goto l2_%=; \ 541 r0 = 0; \ 542 exit; \ 543 l2_%=: r1 = 0; \ 544 *(u8*)(r0 + 0) = r1; \ 545 r0 = 0; \ 546 exit; \ 547 " : 548 : __imm(bpf_ktime_get_ns), 549 __imm(bpf_map_lookup_elem), 550 __imm_addr(map_hash_8b) 551 : __clobber_all); 552 } 553 554 char _license[] SEC("license") = "GPL"; 555