1 /* 2 * Check bpf syscall decoding. 3 * 4 * Copyright (c) 2015-2017 Dmitry V. Levin <ldv (at) altlinux.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "tests.h" 31 #include <asm/unistd.h> 32 33 #if defined __NR_bpf \ 34 && (defined HAVE_UNION_BPF_ATTR_ATTACH_FLAGS \ 35 || defined HAVE_UNION_BPF_ATTR_BPF_FD \ 36 || defined HAVE_UNION_BPF_ATTR_FLAGS \ 37 || defined HAVE_UNION_BPF_ATTR_INFO_INFO \ 38 || defined HAVE_UNION_BPF_ATTR_NEXT_ID \ 39 || defined HAVE_UNION_BPF_ATTR_NUMA_NODE \ 40 || defined HAVE_UNION_BPF_ATTR_PROG_FLAGS \ 41 || defined HAVE_UNION_BPF_ATTR_TEST_DURATION) 42 43 # include <stddef.h> 44 # include <stdio.h> 45 # include <stdint.h> 46 # include <string.h> 47 # include <unistd.h> 48 # include <linux/bpf.h> 49 # include "print_fields.h" 50 51 static const kernel_ulong_t long_bits = (kernel_ulong_t) 0xfacefeed00000000ULL; 52 static const char *errstr; 53 static unsigned int sizeof_attr = sizeof(union bpf_attr); 54 static unsigned int page_size; 55 static unsigned long end_of_page; 56 57 static long 58 sys_bpf(kernel_ulong_t cmd, kernel_ulong_t attr, kernel_ulong_t size) 59 { 60 long rc = syscall(__NR_bpf, cmd, attr, size); 61 errstr = sprintrc(rc); 62 return rc; 63 } 64 65 # if VERBOSE 66 # define print_extra_data(addr_, size_) print_quoted_hex((addr_), (size_)) 67 # else 68 # define print_extra_data(addr_, size_) printf("...") 69 #endif 70 71 # define TEST_BPF_(cmd_, cmd_str_, \ 72 init_first_, print_first_, \ 73 init_attr_, print_attr_) \ 74 do { \ 75 /* zero addr */ \ 76 sys_bpf(cmd_, 0, long_bits | sizeof(union bpf_attr)); \ 77 printf("bpf(%s, NULL, %u) = %s\n", \ 78 cmd_str_, sizeof_attr, errstr); \ 79 \ 80 /* zero size */ \ 81 unsigned long addr = end_of_page - sizeof_attr; \ 82 sys_bpf(cmd_, addr, long_bits); \ 83 printf("bpf(%s, %#lx, 0) = %s\n", \ 84 cmd_str_, addr, errstr); \ 85 \ 86 /* the first field only */ \ 87 unsigned int offset = init_first_(end_of_page); \ 88 addr = end_of_page - offset; \ 89 sys_bpf(cmd_, addr, offset); \ 90 printf("bpf(%s, {", cmd_str_); \ 91 print_first_(addr); \ 92 printf("}, %u) = %s\n", offset, errstr); \ 93 \ 94 /* efault after the first field */ \ 95 sys_bpf(cmd_, addr, offset + 1); \ 96 printf("bpf(%s, %#lx, %u) = %s\n", \ 97 cmd_str_, addr, offset + 1, errstr); \ 98 \ 99 /* the relevant part of union bpf_attr */ \ 100 offset = init_attr_(end_of_page); \ 101 addr = end_of_page - offset; \ 102 sys_bpf(cmd_, addr, offset); \ 103 printf("bpf(%s, {", cmd_str_); \ 104 print_attr_(addr); \ 105 printf("}, %u) = %s\n", offset, errstr); \ 106 \ 107 /* short read of the relevant part of union bpf_attr */ \ 108 sys_bpf(cmd_, addr + 1, offset); \ 109 printf("bpf(%s, %#lx, %u) = %s\n", \ 110 cmd_str_, addr + 1, offset, errstr); \ 111 \ 112 if (offset < sizeof_attr) { \ 113 /* short read of the whole union bpf_attr */ \ 114 memmove((void *) end_of_page - sizeof_attr + 1, \ 115 (void *) addr, offset); \ 116 addr = end_of_page - sizeof_attr + 1; \ 117 memset((void *) addr + offset, 0, \ 118 sizeof_attr - offset - 1); \ 119 sys_bpf(cmd_, addr, sizeof_attr); \ 120 printf("bpf(%s, %#lx, %u) = %s\n", \ 121 cmd_str_, addr, sizeof_attr, errstr); \ 122 \ 123 /* the whole union bpf_attr */ \ 124 memmove((void *) end_of_page - sizeof_attr, \ 125 (void *) addr, offset); \ 126 addr = end_of_page - sizeof_attr; \ 127 memset((void *) addr + offset, 0, \ 128 sizeof_attr - offset); \ 129 sys_bpf(cmd_, addr, sizeof_attr); \ 130 printf("bpf(%s, {", cmd_str_); \ 131 print_attr_(addr); \ 132 printf("}, %u) = %s\n", sizeof_attr, errstr); \ 133 \ 134 /* non-zero bytes after the relevant part */ \ 135 fill_memory_ex((void *) addr + offset, \ 136 sizeof_attr - offset, '0', 10); \ 137 sys_bpf(cmd_, addr, sizeof_attr); \ 138 printf("bpf(%s, {", cmd_str_); \ 139 print_attr_(addr); \ 140 printf(", "); \ 141 print_extra_data((void *) addr + offset, \ 142 sizeof_attr - offset); \ 143 printf("}, %u) = %s\n", sizeof_attr, errstr); \ 144 } \ 145 \ 146 /* short read of the whole page */ \ 147 memmove((void *) end_of_page - page_size + 1, \ 148 (void *) addr, offset); \ 149 addr = end_of_page - page_size + 1; \ 150 memset((void *) addr + offset, 0, \ 151 page_size - offset - 1); \ 152 sys_bpf(cmd_, addr, page_size); \ 153 printf("bpf(%s, %#lx, %u) = %s\n", \ 154 cmd_str_, addr, page_size, errstr); \ 155 \ 156 /* the whole page */ \ 157 memmove((void *) end_of_page - page_size, \ 158 (void *) addr, offset); \ 159 addr = end_of_page - page_size; \ 160 memset((void *) addr + offset, 0, page_size - offset); \ 161 sys_bpf(cmd_, addr, page_size); \ 162 printf("bpf(%s, {", cmd_str_); \ 163 print_attr_(addr); \ 164 printf("}, %u) = %s\n", page_size, errstr); \ 165 \ 166 /* non-zero bytes after the whole union bpf_attr */ \ 167 fill_memory_ex((void *) addr + offset, \ 168 page_size - offset, '0', 10); \ 169 sys_bpf(cmd_, addr, page_size); \ 170 printf("bpf(%s, {", cmd_str_); \ 171 print_attr_(addr); \ 172 printf(", "); \ 173 print_extra_data((void *) addr + offset, \ 174 page_size - offset); \ 175 printf("}, %u) = %s\n", page_size, errstr); \ 176 \ 177 /* more than a page */ \ 178 sys_bpf(cmd_, addr, page_size + 1); \ 179 printf("bpf(%s, %#lx, %u) = %s\n", \ 180 cmd_str_, addr, page_size + 1, errstr); \ 181 } while (0) \ 182 /* End of TEST_BPF_ definition. */ 183 184 # define TEST_BPF(cmd_) \ 185 TEST_BPF_((cmd_), #cmd_, \ 186 init_ ## cmd_ ## _first, print_ ## cmd_ ## _first, \ 187 init_ ## cmd_ ## _attr, print_ ## cmd_ ## _attr) \ 188 /* End of TEST_BPF definition. */ 189 190 #define DEF_BPF_INIT_FIRST(cmd_, field_, value_) \ 191 static unsigned int \ 192 init_ ## cmd_ ## _first(const unsigned long eop) \ 193 { \ 194 static const union bpf_attr attr = { .field_ = value_ };\ 195 static const unsigned int offset = sizeof(attr.field_); \ 196 const unsigned long addr = eop - offset; \ 197 \ 198 memcpy((void *) addr, &attr.field_, offset); \ 199 return offset; \ 200 } \ 201 /* End of DEF_INIT_FIRST definition. */ 202 203 # ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE 204 205 DEF_BPF_INIT_FIRST(BPF_MAP_CREATE, map_type, 2) 206 207 static void 208 print_BPF_MAP_CREATE_first(const unsigned long addr) 209 { 210 printf("map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0" 211 ", max_entries=0, map_flags=0, inner_map_fd=0"); 212 } 213 214 static unsigned int 215 init_BPF_MAP_CREATE_attr(const unsigned long eop) 216 { 217 static const union bpf_attr attr = { 218 .map_type = 1, 219 .key_size = 4, 220 .value_size = 8, 221 .max_entries = 256, 222 .map_flags = 7, 223 .inner_map_fd = -1, 224 .numa_node = 42 225 }; 226 static const unsigned int offset = 227 offsetofend(union bpf_attr, numa_node); 228 const unsigned long addr = eop - offset; 229 230 memcpy((void *) addr, &attr, offset); 231 return offset; 232 } 233 234 static void 235 print_BPF_MAP_CREATE_attr(const unsigned long addr) 236 { 237 printf("map_type=BPF_MAP_TYPE_HASH, key_size=4" 238 ", value_size=8, max_entries=256" 239 ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU" 240 "|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42"); 241 } 242 243 # endif /* HAVE_UNION_BPF_ATTR_NUMA_NODE */ 244 245 # ifdef HAVE_UNION_BPF_ATTR_FLAGS 246 247 DEF_BPF_INIT_FIRST(BPF_MAP_LOOKUP_ELEM, map_fd, -1) 248 249 static void 250 print_BPF_MAP_LOOKUP_ELEM_first(const unsigned long addr) 251 { 252 printf("map_fd=-1, key=0, value=0"); 253 } 254 255 static unsigned int 256 init_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long eop) 257 { 258 static const union bpf_attr attr = { 259 .map_fd = -1, 260 .key = 0xdeadbeef, 261 .value = 0xbadc0ded 262 }; 263 static const unsigned int offset = 264 offsetofend(union bpf_attr, value); 265 const unsigned long addr = eop - offset; 266 267 memcpy((void *) addr, &attr, offset); 268 return offset; 269 } 270 271 static void 272 print_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long addr) 273 { 274 printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded"); 275 } 276 277 # define init_BPF_MAP_UPDATE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first 278 279 static void 280 print_BPF_MAP_UPDATE_ELEM_first(const unsigned long addr) 281 { 282 printf("map_fd=-1, key=0, value=0, flags=BPF_ANY"); 283 } 284 285 static unsigned int 286 init_BPF_MAP_UPDATE_ELEM_attr(const unsigned long eop) 287 { 288 static const union bpf_attr attr = { 289 .map_fd = -1, 290 .key = 0xdeadbeef, 291 .value = 0xbadc0ded, 292 .flags = 2 293 }; 294 static const unsigned int offset = 295 offsetofend(union bpf_attr, flags); 296 const unsigned long addr = eop - offset; 297 298 memcpy((void *) addr, &attr, offset); 299 return offset; 300 } 301 302 static void 303 print_BPF_MAP_UPDATE_ELEM_attr(const unsigned long addr) 304 { 305 printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded, flags=BPF_EXIST"); 306 } 307 308 # define init_BPF_MAP_DELETE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first 309 310 static void 311 print_BPF_MAP_DELETE_ELEM_first(const unsigned long addr) 312 { 313 printf("map_fd=-1, key=0"); 314 } 315 316 static unsigned int 317 init_BPF_MAP_DELETE_ELEM_attr(const unsigned long eop) 318 { 319 static const union bpf_attr attr = { 320 .map_fd = -1, 321 .key = 0xdeadbeef 322 }; 323 static const unsigned int offset = 324 offsetofend(union bpf_attr, key); 325 const unsigned long addr = eop - offset; 326 327 memcpy((void *) addr, &attr, offset); 328 return offset; 329 } 330 331 static void 332 print_BPF_MAP_DELETE_ELEM_attr(const unsigned long addr) 333 { 334 printf("map_fd=-1, key=0xdeadbeef"); 335 } 336 337 # define init_BPF_MAP_GET_NEXT_KEY_first init_BPF_MAP_LOOKUP_ELEM_first 338 339 static void 340 print_BPF_MAP_GET_NEXT_KEY_first(const unsigned long addr) 341 { 342 printf("map_fd=-1, key=0, next_key=0"); 343 } 344 345 static unsigned int 346 init_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long eop) 347 { 348 static const union bpf_attr attr = { 349 .map_fd = -1, 350 .key = 0xdeadbeef, 351 .next_key = 0xbadc0ded 352 }; 353 static const unsigned int offset = 354 offsetofend(union bpf_attr, next_key); 355 const unsigned long addr = eop - offset; 356 357 memcpy((void *) addr, &attr, offset); 358 return offset; 359 } 360 361 static void 362 print_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long addr) 363 { 364 printf("map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded"); 365 } 366 367 # endif /* HAVE_UNION_BPF_ATTR_FLAGS */ 368 369 # ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS 370 371 DEF_BPF_INIT_FIRST(BPF_PROG_LOAD, prog_type, 1) 372 373 static void 374 print_BPF_PROG_LOAD_first(const unsigned long addr) 375 { 376 377 printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=0, insns=0" 378 ", license=NULL, log_level=0, log_size=0, log_buf=0" 379 ", kern_version=0, prog_flags=0"); 380 } 381 382 static const struct bpf_insn insns[] = { 383 { .code = BPF_JMP | BPF_EXIT } 384 }; 385 static char log_buf[4096]; 386 387 static unsigned int 388 init_BPF_PROG_LOAD_attr(const unsigned long eop) 389 { 390 const union bpf_attr attr = { 391 .prog_type = 1, 392 .insn_cnt = ARRAY_SIZE(insns), 393 .insns = (uintptr_t) insns, 394 .license = (uintptr_t) "GPL", 395 .log_level = 42, 396 .log_size = sizeof(log_buf), 397 .log_buf = (uintptr_t) log_buf, 398 .kern_version = 0xcafef00d, 399 .prog_flags = 1 400 }; 401 static const unsigned int offset = 402 offsetofend(union bpf_attr, prog_flags); 403 const unsigned long addr = eop - offset; 404 405 memcpy((void *) addr, &attr, offset); 406 return offset; 407 } 408 409 static void 410 print_BPF_PROG_LOAD_attr(const unsigned long addr) 411 { 412 printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=%u, insns=%p" 413 ", license=\"GPL\", log_level=42, log_size=4096, log_buf=%p" 414 ", kern_version=%u, prog_flags=BPF_F_STRICT_ALIGNMENT", 415 (unsigned int) ARRAY_SIZE(insns), insns, 416 log_buf, 0xcafef00d); 417 } 418 419 # endif /* HAVE_UNION_BPF_ATTR_PROG_FLAGS */ 420 421 /* 422 * bpf() syscall and its first six commands were introduced in Linux kernel 423 * 3.18. Some additional commands were added afterwards, so we need to take 424 * precautions to make sure the tests compile. 425 * 426 * BPF_OBJ_PIN and BPF_OBJ_GET commands appear in kernel 4.4. 427 */ 428 # ifdef HAVE_UNION_BPF_ATTR_BPF_FD 429 430 DEF_BPF_INIT_FIRST(BPF_OBJ_PIN, pathname, 0) 431 432 static void 433 print_BPF_OBJ_PIN_first(const unsigned long addr) 434 { 435 436 printf("pathname=NULL, bpf_fd=0"); 437 } 438 439 static unsigned int 440 init_BPF_OBJ_PIN_attr(const unsigned long eop) 441 { 442 const union bpf_attr attr = { 443 .pathname = (uintptr_t) "/sys/fs/bpf/foo/bar", 444 .bpf_fd = -1 445 }; 446 static const unsigned int offset = 447 offsetofend(union bpf_attr, bpf_fd); 448 const unsigned long addr = eop - offset; 449 450 memcpy((void *) addr, &attr, offset); 451 return offset; 452 } 453 454 static void 455 print_BPF_OBJ_PIN_attr(const unsigned long addr) 456 { 457 printf("pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1"); 458 } 459 460 # define init_BPF_OBJ_GET_first init_BPF_OBJ_PIN_first 461 # define print_BPF_OBJ_GET_first print_BPF_OBJ_PIN_first 462 # define init_BPF_OBJ_GET_attr init_BPF_OBJ_PIN_attr 463 # define print_BPF_OBJ_GET_attr print_BPF_OBJ_PIN_attr 464 465 # endif /* HAVE_UNION_BPF_ATTR_BPF_FD */ 466 467 /* BPF_PROG_ATTACH and BPF_PROG_DETACH commands appear in kernel 4.10. */ 468 # ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS 469 470 DEF_BPF_INIT_FIRST(BPF_PROG_ATTACH, target_fd, -1) 471 472 static void 473 print_BPF_PROG_ATTACH_first(const unsigned long addr) 474 { 475 printf("target_fd=-1, attach_bpf_fd=0" 476 ", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0"); 477 } 478 479 static unsigned int 480 init_BPF_PROG_ATTACH_attr(const unsigned long eop) 481 { 482 static const union bpf_attr attr = { 483 .target_fd = -1, 484 .attach_bpf_fd = -2, 485 .attach_type = 2, 486 .attach_flags = 1 487 }; 488 static const unsigned int offset = 489 offsetofend(union bpf_attr, attach_flags); 490 const unsigned long addr = eop - offset; 491 492 memcpy((void *) addr, &attr, offset); 493 return offset; 494 } 495 496 static void 497 print_BPF_PROG_ATTACH_attr(const unsigned long addr) 498 { 499 printf("target_fd=-1, attach_bpf_fd=-2" 500 ", attach_type=BPF_CGROUP_INET_SOCK_CREATE" 501 ", attach_flags=BPF_F_ALLOW_OVERRIDE"); 502 } 503 504 # define init_BPF_PROG_DETACH_first init_BPF_PROG_ATTACH_first 505 506 static unsigned int 507 init_BPF_PROG_DETACH_attr(const unsigned long eop) 508 { 509 static const union bpf_attr attr = { 510 .target_fd = -1, 511 .attach_type = 2 512 }; 513 static const unsigned int offset = 514 offsetofend(union bpf_attr, attach_type); 515 const unsigned long addr = eop - offset; 516 517 memcpy((void *) addr, &attr, offset); 518 return offset; 519 } 520 521 522 static void 523 print_BPF_PROG_DETACH_first(const unsigned long addr) 524 { 525 printf("target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS"); 526 } 527 528 static void 529 print_BPF_PROG_DETACH_attr(const unsigned long addr) 530 { 531 printf("target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE"); 532 } 533 534 # endif /* HAVE_UNION_BPF_ATTR_ATTACH_FLAGS */ 535 536 /* BPF_PROG_TEST_RUN command appears in kernel 4.12. */ 537 # ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION 538 539 DEF_BPF_INIT_FIRST(BPF_PROG_TEST_RUN, test.prog_fd, -1) 540 541 static void 542 print_BPF_PROG_TEST_RUN_first(const unsigned long addr) 543 { 544 printf("test={prog_fd=-1, retval=0, data_size_in=0, data_size_out=0" 545 ", data_in=0, data_out=0, repeat=0, duration=0}"); 546 } 547 548 static const union bpf_attr sample_BPF_PROG_TEST_RUN_attr = { 549 .test = { 550 .prog_fd = -1, 551 .retval = 0xfac1fed2, 552 .data_size_in = 0xfac3fed4, 553 .data_size_out = 0xfac5fed6, 554 .data_in = (uint64_t) 0xfacef11dbadc2ded, 555 .data_out = (uint64_t) 0xfacef33dbadc4ded, 556 .repeat = 0xfac7fed8, 557 .duration = 0xfac9feda 558 } 559 }; 560 static unsigned int 561 init_BPF_PROG_TEST_RUN_attr(const unsigned long eop) 562 { 563 static const unsigned int offset = 564 offsetofend(union bpf_attr, test); 565 const unsigned long addr = eop - offset; 566 567 memcpy((void *) addr, &sample_BPF_PROG_TEST_RUN_attr, offset); 568 return offset; 569 } 570 571 static void 572 print_BPF_PROG_TEST_RUN_attr(const unsigned long addr) 573 { 574 PRINT_FIELD_D("test={", sample_BPF_PROG_TEST_RUN_attr.test, prog_fd); 575 PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, retval); 576 PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_in); 577 PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_out); 578 PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_in); 579 PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_out); 580 PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, repeat); 581 PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, duration); 582 printf("}"); 583 } 584 585 # endif /* HAVE_UNION_BPF_ATTR_TEST_DURATION */ 586 587 # ifdef HAVE_UNION_BPF_ATTR_NEXT_ID 588 589 DEF_BPF_INIT_FIRST(BPF_PROG_GET_NEXT_ID, start_id, 0xdeadbeef) 590 591 static void 592 print_BPF_PROG_GET_NEXT_ID_first(const unsigned long addr) 593 { 594 printf("start_id=%u, next_id=0", 0xdeadbeef); 595 } 596 597 static unsigned int 598 init_BPF_PROG_GET_NEXT_ID_attr(const unsigned long eop) 599 { 600 static const union bpf_attr attr = { 601 .start_id = 0xbadc0ded, 602 .next_id = 0xcafef00d 603 }; 604 static const unsigned int offset = 605 offsetofend(union bpf_attr, next_id); 606 const unsigned long addr = eop - offset; 607 608 memcpy((void *) addr, &attr, offset); 609 return offset; 610 } 611 612 static void 613 print_BPF_PROG_GET_NEXT_ID_attr(const unsigned long addr) 614 { 615 printf("start_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d); 616 } 617 618 # define init_BPF_MAP_GET_NEXT_ID_first init_BPF_PROG_GET_NEXT_ID_first 619 # define print_BPF_MAP_GET_NEXT_ID_first print_BPF_PROG_GET_NEXT_ID_first 620 # define init_BPF_MAP_GET_NEXT_ID_attr init_BPF_PROG_GET_NEXT_ID_attr 621 # define print_BPF_MAP_GET_NEXT_ID_attr print_BPF_PROG_GET_NEXT_ID_attr 622 623 # define init_BPF_PROG_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first 624 # define init_BPF_PROG_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr 625 626 static void 627 print_BPF_PROG_GET_FD_BY_ID_first(const unsigned long addr) 628 { 629 printf("prog_id=%u, next_id=0", 0xdeadbeef); 630 } 631 632 static void 633 print_BPF_PROG_GET_FD_BY_ID_attr(const unsigned long addr) 634 { 635 printf("prog_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d); 636 } 637 638 # define init_BPF_MAP_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first 639 # define init_BPF_MAP_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr 640 641 static void 642 print_BPF_MAP_GET_FD_BY_ID_first(const unsigned long addr) 643 { 644 printf("map_id=%u, next_id=0", 0xdeadbeef); 645 } 646 647 static void 648 print_BPF_MAP_GET_FD_BY_ID_attr(const unsigned long addr) 649 { 650 printf("map_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d); 651 } 652 653 # endif /* HAVE_UNION_BPF_ATTR_NEXT_ID */ 654 655 # ifdef HAVE_UNION_BPF_ATTR_INFO_INFO 656 657 DEF_BPF_INIT_FIRST(BPF_OBJ_GET_INFO_BY_FD, info.bpf_fd, -1) 658 659 static void 660 print_BPF_OBJ_GET_INFO_BY_FD_first(const unsigned long addr) 661 { 662 printf("info={bpf_fd=-1, info_len=0, info=0}"); 663 } 664 665 static const union bpf_attr sample_BPF_OBJ_GET_INFO_BY_FD_attr = { 666 .info = { 667 .bpf_fd = -1, 668 .info_len = 0xdeadbeef, 669 .info = (uint64_t) 0xfacefeedbadc0ded 670 } 671 }; 672 static unsigned int 673 init_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long eop) 674 { 675 static const unsigned int offset = 676 offsetofend(union bpf_attr, info); 677 const unsigned long addr = eop - offset; 678 679 memcpy((void *) addr, &sample_BPF_OBJ_GET_INFO_BY_FD_attr, offset); 680 return offset; 681 } 682 683 static void 684 print_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long addr) 685 { 686 PRINT_FIELD_D("info={", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, bpf_fd); 687 PRINT_FIELD_U(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, info_len); 688 PRINT_FIELD_X(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, info); 689 printf("}"); 690 } 691 692 # endif /* HAVE_UNION_BPF_ATTR_INFO_INFO */ 693 694 int 695 main(void) 696 { 697 page_size = get_page_size(); 698 end_of_page = (unsigned long) tail_alloc(1) + 1; 699 700 # ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE 701 TEST_BPF(BPF_MAP_CREATE); 702 # endif 703 704 # ifdef HAVE_UNION_BPF_ATTR_FLAGS 705 TEST_BPF(BPF_MAP_LOOKUP_ELEM); 706 TEST_BPF(BPF_MAP_UPDATE_ELEM); 707 TEST_BPF(BPF_MAP_DELETE_ELEM); 708 TEST_BPF(BPF_MAP_GET_NEXT_KEY); 709 # endif 710 711 # ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS 712 TEST_BPF(BPF_PROG_LOAD); 713 # endif 714 715 # ifdef HAVE_UNION_BPF_ATTR_BPF_FD 716 TEST_BPF(BPF_OBJ_PIN); 717 TEST_BPF(BPF_OBJ_GET); 718 # endif 719 720 # ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS 721 TEST_BPF(BPF_PROG_ATTACH); 722 TEST_BPF(BPF_PROG_DETACH); 723 # endif 724 725 # ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION 726 TEST_BPF(BPF_PROG_TEST_RUN); 727 # endif 728 729 # ifdef HAVE_UNION_BPF_ATTR_NEXT_ID 730 TEST_BPF(BPF_PROG_GET_NEXT_ID); 731 TEST_BPF(BPF_MAP_GET_NEXT_ID); 732 TEST_BPF(BPF_PROG_GET_FD_BY_ID); 733 TEST_BPF(BPF_MAP_GET_FD_BY_ID); 734 # endif 735 736 # ifdef HAVE_UNION_BPF_ATTR_INFO_INFO 737 TEST_BPF(BPF_OBJ_GET_INFO_BY_FD); 738 # endif 739 740 sys_bpf(0xfacefeed, end_of_page, 40); 741 printf("bpf(0xfacefeed /* BPF_??? */, %#lx, 40) = %s\n", 742 end_of_page, errstr); 743 744 puts("+++ exited with 0 +++"); 745 return 0; 746 } 747 748 #else 749 750 SKIP_MAIN_UNDEFINED("__NR_bpf && HAVE_UNION_BPF_ATTR_*") 751 752 #endif 753