1 /* 2 * Copyright (C) 2017 Netronome Systems, Inc. 3 * 4 * This software is dual licensed under the GNU General License Version 2, 5 * June 1991 as shown in the file COPYING in the top-level directory of this 6 * source tree or the BSD 2-Clause License provided below. You have the 7 * option to license this software under the complete terms of either license. 8 * 9 * The BSD 2-Clause License: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 /* Author: Jakub Kicinski <kubakici@wp.pl> */ 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <stdarg.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <time.h> 43 #include <unistd.h> 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 47 #include <bpf.h> 48 #include <libbpf.h> 49 50 #include "cfg.h" 51 #include "main.h" 52 #include "xlated_dumper.h" 53 54 static const char * const prog_type_name[] = { 55 [BPF_PROG_TYPE_UNSPEC] = "unspec", 56 [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", 57 [BPF_PROG_TYPE_KPROBE] = "kprobe", 58 [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", 59 [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", 60 [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", 61 [BPF_PROG_TYPE_XDP] = "xdp", 62 [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", 63 [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", 64 [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", 65 [BPF_PROG_TYPE_LWT_IN] = "lwt_in", 66 [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", 67 [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", 68 [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", 69 [BPF_PROG_TYPE_SK_SKB] = "sk_skb", 70 [BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device", 71 [BPF_PROG_TYPE_SK_MSG] = "sk_msg", 72 [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", 73 [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr", 74 [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2", 75 }; 76 77 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 78 { 79 struct timespec real_time_ts, boot_time_ts; 80 time_t wallclock_secs; 81 struct tm load_tm; 82 83 buf[--size] = '\0'; 84 85 if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 86 clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 87 perror("Can't read clocks"); 88 snprintf(buf, size, "%llu", nsecs / 1000000000); 89 return; 90 } 91 92 wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 93 (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 94 1000000000; 95 96 97 if (!localtime_r(&wallclock_secs, &load_tm)) { 98 snprintf(buf, size, "%llu", nsecs / 1000000000); 99 return; 100 } 101 102 if (json_output) 103 strftime(buf, size, "%s", &load_tm); 104 else 105 strftime(buf, size, "%FT%T%z", &load_tm); 106 } 107 108 static int prog_fd_by_tag(unsigned char *tag) 109 { 110 struct bpf_prog_info info = {}; 111 __u32 len = sizeof(info); 112 unsigned int id = 0; 113 int err; 114 int fd; 115 116 while (true) { 117 err = bpf_prog_get_next_id(id, &id); 118 if (err) { 119 p_err("%s", strerror(errno)); 120 return -1; 121 } 122 123 fd = bpf_prog_get_fd_by_id(id); 124 if (fd < 0) { 125 p_err("can't get prog by id (%u): %s", 126 id, strerror(errno)); 127 return -1; 128 } 129 130 err = bpf_obj_get_info_by_fd(fd, &info, &len); 131 if (err) { 132 p_err("can't get prog info (%u): %s", 133 id, strerror(errno)); 134 close(fd); 135 return -1; 136 } 137 138 if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 139 return fd; 140 141 close(fd); 142 } 143 } 144 145 int prog_parse_fd(int *argc, char ***argv) 146 { 147 int fd; 148 149 if (is_prefix(**argv, "id")) { 150 unsigned int id; 151 char *endptr; 152 153 NEXT_ARGP(); 154 155 id = strtoul(**argv, &endptr, 0); 156 if (*endptr) { 157 p_err("can't parse %s as ID", **argv); 158 return -1; 159 } 160 NEXT_ARGP(); 161 162 fd = bpf_prog_get_fd_by_id(id); 163 if (fd < 0) 164 p_err("get by id (%u): %s", id, strerror(errno)); 165 return fd; 166 } else if (is_prefix(**argv, "tag")) { 167 unsigned char tag[BPF_TAG_SIZE]; 168 169 NEXT_ARGP(); 170 171 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 172 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 173 != BPF_TAG_SIZE) { 174 p_err("can't parse tag"); 175 return -1; 176 } 177 NEXT_ARGP(); 178 179 return prog_fd_by_tag(tag); 180 } else if (is_prefix(**argv, "pinned")) { 181 char *path; 182 183 NEXT_ARGP(); 184 185 path = **argv; 186 NEXT_ARGP(); 187 188 return open_obj_pinned_any(path, BPF_OBJ_PROG); 189 } 190 191 p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 192 return -1; 193 } 194 195 static void show_prog_maps(int fd, u32 num_maps) 196 { 197 struct bpf_prog_info info = {}; 198 __u32 len = sizeof(info); 199 __u32 map_ids[num_maps]; 200 unsigned int i; 201 int err; 202 203 info.nr_map_ids = num_maps; 204 info.map_ids = ptr_to_u64(map_ids); 205 206 err = bpf_obj_get_info_by_fd(fd, &info, &len); 207 if (err || !info.nr_map_ids) 208 return; 209 210 if (json_output) { 211 jsonw_name(json_wtr, "map_ids"); 212 jsonw_start_array(json_wtr); 213 for (i = 0; i < info.nr_map_ids; i++) 214 jsonw_uint(json_wtr, map_ids[i]); 215 jsonw_end_array(json_wtr); 216 } else { 217 printf(" map_ids "); 218 for (i = 0; i < info.nr_map_ids; i++) 219 printf("%u%s", map_ids[i], 220 i == info.nr_map_ids - 1 ? "" : ","); 221 } 222 } 223 224 static void print_prog_json(struct bpf_prog_info *info, int fd) 225 { 226 char *memlock; 227 228 jsonw_start_object(json_wtr); 229 jsonw_uint_field(json_wtr, "id", info->id); 230 if (info->type < ARRAY_SIZE(prog_type_name)) 231 jsonw_string_field(json_wtr, "type", 232 prog_type_name[info->type]); 233 else 234 jsonw_uint_field(json_wtr, "type", info->type); 235 236 if (*info->name) 237 jsonw_string_field(json_wtr, "name", info->name); 238 239 jsonw_name(json_wtr, "tag"); 240 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 241 info->tag[0], info->tag[1], info->tag[2], info->tag[3], 242 info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 243 244 jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 245 246 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 247 248 if (info->load_time) { 249 char buf[32]; 250 251 print_boot_time(info->load_time, buf, sizeof(buf)); 252 253 /* Piggy back on load_time, since 0 uid is a valid one */ 254 jsonw_name(json_wtr, "loaded_at"); 255 jsonw_printf(json_wtr, "%s", buf); 256 jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 257 } 258 259 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 260 261 if (info->jited_prog_len) { 262 jsonw_bool_field(json_wtr, "jited", true); 263 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 264 } else { 265 jsonw_bool_field(json_wtr, "jited", false); 266 } 267 268 memlock = get_fdinfo(fd, "memlock"); 269 if (memlock) 270 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 271 free(memlock); 272 273 if (info->nr_map_ids) 274 show_prog_maps(fd, info->nr_map_ids); 275 276 if (!hash_empty(prog_table.table)) { 277 struct pinned_obj *obj; 278 279 jsonw_name(json_wtr, "pinned"); 280 jsonw_start_array(json_wtr); 281 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 282 if (obj->id == info->id) 283 jsonw_string(json_wtr, obj->path); 284 } 285 jsonw_end_array(json_wtr); 286 } 287 288 jsonw_end_object(json_wtr); 289 } 290 291 static void print_prog_plain(struct bpf_prog_info *info, int fd) 292 { 293 char *memlock; 294 295 printf("%u: ", info->id); 296 if (info->type < ARRAY_SIZE(prog_type_name)) 297 printf("%s ", prog_type_name[info->type]); 298 else 299 printf("type %u ", info->type); 300 301 if (*info->name) 302 printf("name %s ", info->name); 303 304 printf("tag "); 305 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 306 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 307 printf("%s", info->gpl_compatible ? " gpl" : ""); 308 printf("\n"); 309 310 if (info->load_time) { 311 char buf[32]; 312 313 print_boot_time(info->load_time, buf, sizeof(buf)); 314 315 /* Piggy back on load_time, since 0 uid is a valid one */ 316 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 317 } 318 319 printf("\txlated %uB", info->xlated_prog_len); 320 321 if (info->jited_prog_len) 322 printf(" jited %uB", info->jited_prog_len); 323 else 324 printf(" not jited"); 325 326 memlock = get_fdinfo(fd, "memlock"); 327 if (memlock) 328 printf(" memlock %sB", memlock); 329 free(memlock); 330 331 if (info->nr_map_ids) 332 show_prog_maps(fd, info->nr_map_ids); 333 334 if (!hash_empty(prog_table.table)) { 335 struct pinned_obj *obj; 336 337 printf("\n"); 338 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 339 if (obj->id == info->id) 340 printf("\tpinned %s\n", obj->path); 341 } 342 } 343 344 printf("\n"); 345 } 346 347 static int show_prog(int fd) 348 { 349 struct bpf_prog_info info = {}; 350 __u32 len = sizeof(info); 351 int err; 352 353 err = bpf_obj_get_info_by_fd(fd, &info, &len); 354 if (err) { 355 p_err("can't get prog info: %s", strerror(errno)); 356 return -1; 357 } 358 359 if (json_output) 360 print_prog_json(&info, fd); 361 else 362 print_prog_plain(&info, fd); 363 364 return 0; 365 } 366 367 static int do_show(int argc, char **argv) 368 { 369 __u32 id = 0; 370 int err; 371 int fd; 372 373 if (show_pinned) 374 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 375 376 if (argc == 2) { 377 fd = prog_parse_fd(&argc, &argv); 378 if (fd < 0) 379 return -1; 380 381 return show_prog(fd); 382 } 383 384 if (argc) 385 return BAD_ARG(); 386 387 if (json_output) 388 jsonw_start_array(json_wtr); 389 while (true) { 390 err = bpf_prog_get_next_id(id, &id); 391 if (err) { 392 if (errno == ENOENT) { 393 err = 0; 394 break; 395 } 396 p_err("can't get next program: %s%s", strerror(errno), 397 errno == EINVAL ? " -- kernel too old?" : ""); 398 err = -1; 399 break; 400 } 401 402 fd = bpf_prog_get_fd_by_id(id); 403 if (fd < 0) { 404 if (errno == ENOENT) 405 continue; 406 p_err("can't get prog by id (%u): %s", 407 id, strerror(errno)); 408 err = -1; 409 break; 410 } 411 412 err = show_prog(fd); 413 close(fd); 414 if (err) 415 break; 416 } 417 418 if (json_output) 419 jsonw_end_array(json_wtr); 420 421 return err; 422 } 423 424 static int do_dump(int argc, char **argv) 425 { 426 unsigned long *func_ksyms = NULL; 427 struct bpf_prog_info info = {}; 428 unsigned int *func_lens = NULL; 429 unsigned int nr_func_ksyms; 430 unsigned int nr_func_lens; 431 struct dump_data dd = {}; 432 __u32 len = sizeof(info); 433 unsigned int buf_size; 434 char *filepath = NULL; 435 bool opcodes = false; 436 bool visual = false; 437 unsigned char *buf; 438 __u32 *member_len; 439 __u64 *member_ptr; 440 ssize_t n; 441 int err; 442 int fd; 443 444 if (is_prefix(*argv, "jited")) { 445 member_len = &info.jited_prog_len; 446 member_ptr = &info.jited_prog_insns; 447 } else if (is_prefix(*argv, "xlated")) { 448 member_len = &info.xlated_prog_len; 449 member_ptr = &info.xlated_prog_insns; 450 } else { 451 p_err("expected 'xlated' or 'jited', got: %s", *argv); 452 return -1; 453 } 454 NEXT_ARG(); 455 456 if (argc < 2) 457 usage(); 458 459 fd = prog_parse_fd(&argc, &argv); 460 if (fd < 0) 461 return -1; 462 463 if (is_prefix(*argv, "file")) { 464 NEXT_ARG(); 465 if (!argc) { 466 p_err("expected file path"); 467 return -1; 468 } 469 470 filepath = *argv; 471 NEXT_ARG(); 472 } else if (is_prefix(*argv, "opcodes")) { 473 opcodes = true; 474 NEXT_ARG(); 475 } else if (is_prefix(*argv, "visual")) { 476 visual = true; 477 NEXT_ARG(); 478 } 479 480 if (argc) { 481 usage(); 482 return -1; 483 } 484 485 err = bpf_obj_get_info_by_fd(fd, &info, &len); 486 if (err) { 487 p_err("can't get prog info: %s", strerror(errno)); 488 return -1; 489 } 490 491 if (!*member_len) { 492 p_info("no instructions returned"); 493 close(fd); 494 return 0; 495 } 496 497 buf_size = *member_len; 498 499 buf = malloc(buf_size); 500 if (!buf) { 501 p_err("mem alloc failed"); 502 close(fd); 503 return -1; 504 } 505 506 nr_func_ksyms = info.nr_jited_ksyms; 507 if (nr_func_ksyms) { 508 func_ksyms = malloc(nr_func_ksyms * sizeof(__u64)); 509 if (!func_ksyms) { 510 p_err("mem alloc failed"); 511 close(fd); 512 goto err_free; 513 } 514 } 515 516 nr_func_lens = info.nr_jited_func_lens; 517 if (nr_func_lens) { 518 func_lens = malloc(nr_func_lens * sizeof(__u32)); 519 if (!func_lens) { 520 p_err("mem alloc failed"); 521 close(fd); 522 goto err_free; 523 } 524 } 525 526 memset(&info, 0, sizeof(info)); 527 528 *member_ptr = ptr_to_u64(buf); 529 *member_len = buf_size; 530 info.jited_ksyms = ptr_to_u64(func_ksyms); 531 info.nr_jited_ksyms = nr_func_ksyms; 532 info.jited_func_lens = ptr_to_u64(func_lens); 533 info.nr_jited_func_lens = nr_func_lens; 534 535 err = bpf_obj_get_info_by_fd(fd, &info, &len); 536 close(fd); 537 if (err) { 538 p_err("can't get prog info: %s", strerror(errno)); 539 goto err_free; 540 } 541 542 if (*member_len > buf_size) { 543 p_err("too many instructions returned"); 544 goto err_free; 545 } 546 547 if (info.nr_jited_ksyms > nr_func_ksyms) { 548 p_err("too many addresses returned"); 549 goto err_free; 550 } 551 552 if (info.nr_jited_func_lens > nr_func_lens) { 553 p_err("too many values returned"); 554 goto err_free; 555 } 556 557 if ((member_len == &info.jited_prog_len && 558 info.jited_prog_insns == 0) || 559 (member_len == &info.xlated_prog_len && 560 info.xlated_prog_insns == 0)) { 561 p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 562 goto err_free; 563 } 564 565 if (filepath) { 566 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 567 if (fd < 0) { 568 p_err("can't open file %s: %s", filepath, 569 strerror(errno)); 570 goto err_free; 571 } 572 573 n = write(fd, buf, *member_len); 574 close(fd); 575 if (n != *member_len) { 576 p_err("error writing output file: %s", 577 n < 0 ? strerror(errno) : "short write"); 578 goto err_free; 579 } 580 581 if (json_output) 582 jsonw_null(json_wtr); 583 } else if (member_len == &info.jited_prog_len) { 584 const char *name = NULL; 585 586 if (info.ifindex) { 587 name = ifindex_to_bfd_name_ns(info.ifindex, 588 info.netns_dev, 589 info.netns_ino); 590 if (!name) 591 goto err_free; 592 } 593 594 if (info.nr_jited_func_lens && info.jited_func_lens) { 595 struct kernel_sym *sym = NULL; 596 char sym_name[SYM_MAX_NAME]; 597 unsigned char *img = buf; 598 __u64 *ksyms = NULL; 599 __u32 *lens; 600 __u32 i; 601 602 if (info.nr_jited_ksyms) { 603 kernel_syms_load(&dd); 604 ksyms = (__u64 *) info.jited_ksyms; 605 } 606 607 if (json_output) 608 jsonw_start_array(json_wtr); 609 610 lens = (__u32 *) info.jited_func_lens; 611 for (i = 0; i < info.nr_jited_func_lens; i++) { 612 if (ksyms) { 613 sym = kernel_syms_search(&dd, ksyms[i]); 614 if (sym) 615 sprintf(sym_name, "%s", sym->name); 616 else 617 sprintf(sym_name, "0x%016llx", ksyms[i]); 618 } else { 619 strcpy(sym_name, "unknown"); 620 } 621 622 if (json_output) { 623 jsonw_start_object(json_wtr); 624 jsonw_name(json_wtr, "name"); 625 jsonw_string(json_wtr, sym_name); 626 jsonw_name(json_wtr, "insns"); 627 } else { 628 printf("%s:\n", sym_name); 629 } 630 631 disasm_print_insn(img, lens[i], opcodes, name); 632 img += lens[i]; 633 634 if (json_output) 635 jsonw_end_object(json_wtr); 636 else 637 printf("\n"); 638 } 639 640 if (json_output) 641 jsonw_end_array(json_wtr); 642 } else { 643 disasm_print_insn(buf, *member_len, opcodes, name); 644 } 645 } else if (visual) { 646 if (json_output) 647 jsonw_null(json_wtr); 648 else 649 dump_xlated_cfg(buf, *member_len); 650 } else { 651 kernel_syms_load(&dd); 652 dd.nr_jited_ksyms = info.nr_jited_ksyms; 653 dd.jited_ksyms = (__u64 *) info.jited_ksyms; 654 655 if (json_output) 656 dump_xlated_json(&dd, buf, *member_len, opcodes); 657 else 658 dump_xlated_plain(&dd, buf, *member_len, opcodes); 659 kernel_syms_destroy(&dd); 660 } 661 662 free(buf); 663 free(func_ksyms); 664 free(func_lens); 665 return 0; 666 667 err_free: 668 free(buf); 669 free(func_ksyms); 670 free(func_lens); 671 return -1; 672 } 673 674 static int do_pin(int argc, char **argv) 675 { 676 int err; 677 678 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 679 if (!err && json_output) 680 jsonw_null(json_wtr); 681 return err; 682 } 683 684 static int do_load(int argc, char **argv) 685 { 686 struct bpf_object *obj; 687 int prog_fd; 688 689 if (argc != 2) 690 usage(); 691 692 if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) { 693 p_err("failed to load program"); 694 return -1; 695 } 696 697 if (do_pin_fd(prog_fd, argv[1])) { 698 p_err("failed to pin program"); 699 return -1; 700 } 701 702 if (json_output) 703 jsonw_null(json_wtr); 704 705 return 0; 706 } 707 708 static int do_help(int argc, char **argv) 709 { 710 if (json_output) { 711 jsonw_null(json_wtr); 712 return 0; 713 } 714 715 fprintf(stderr, 716 "Usage: %s %s { show | list } [PROG]\n" 717 " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" 718 " %s %s dump jited PROG [{ file FILE | opcodes }]\n" 719 " %s %s pin PROG FILE\n" 720 " %s %s load OBJ FILE\n" 721 " %s %s help\n" 722 "\n" 723 " " HELP_SPEC_PROGRAM "\n" 724 " " HELP_SPEC_OPTIONS "\n" 725 "", 726 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 727 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 728 729 return 0; 730 } 731 732 static const struct cmd cmds[] = { 733 { "show", do_show }, 734 { "list", do_show }, 735 { "help", do_help }, 736 { "dump", do_dump }, 737 { "pin", do_pin }, 738 { "load", do_load }, 739 { 0 } 740 }; 741 742 int do_prog(int argc, char **argv) 743 { 744 return cmd_select(cmds, argc, argv, do_help); 745 } 746