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 nsecs / 1000000000; 94 95 if (!localtime_r(&wallclock_secs, &load_tm)) { 96 snprintf(buf, size, "%llu", nsecs / 1000000000); 97 return; 98 } 99 100 if (json_output) 101 strftime(buf, size, "%s", &load_tm); 102 else 103 strftime(buf, size, "%FT%T%z", &load_tm); 104 } 105 106 static int prog_fd_by_tag(unsigned char *tag) 107 { 108 struct bpf_prog_info info = {}; 109 __u32 len = sizeof(info); 110 unsigned int id = 0; 111 int err; 112 int fd; 113 114 while (true) { 115 err = bpf_prog_get_next_id(id, &id); 116 if (err) { 117 p_err("%s", strerror(errno)); 118 return -1; 119 } 120 121 fd = bpf_prog_get_fd_by_id(id); 122 if (fd < 0) { 123 p_err("can't get prog by id (%u): %s", 124 id, strerror(errno)); 125 return -1; 126 } 127 128 err = bpf_obj_get_info_by_fd(fd, &info, &len); 129 if (err) { 130 p_err("can't get prog info (%u): %s", 131 id, strerror(errno)); 132 close(fd); 133 return -1; 134 } 135 136 if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 137 return fd; 138 139 close(fd); 140 } 141 } 142 143 int prog_parse_fd(int *argc, char ***argv) 144 { 145 int fd; 146 147 if (is_prefix(**argv, "id")) { 148 unsigned int id; 149 char *endptr; 150 151 NEXT_ARGP(); 152 153 id = strtoul(**argv, &endptr, 0); 154 if (*endptr) { 155 p_err("can't parse %s as ID", **argv); 156 return -1; 157 } 158 NEXT_ARGP(); 159 160 fd = bpf_prog_get_fd_by_id(id); 161 if (fd < 0) 162 p_err("get by id (%u): %s", id, strerror(errno)); 163 return fd; 164 } else if (is_prefix(**argv, "tag")) { 165 unsigned char tag[BPF_TAG_SIZE]; 166 167 NEXT_ARGP(); 168 169 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 170 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 171 != BPF_TAG_SIZE) { 172 p_err("can't parse tag"); 173 return -1; 174 } 175 NEXT_ARGP(); 176 177 return prog_fd_by_tag(tag); 178 } else if (is_prefix(**argv, "pinned")) { 179 char *path; 180 181 NEXT_ARGP(); 182 183 path = **argv; 184 NEXT_ARGP(); 185 186 return open_obj_pinned_any(path, BPF_OBJ_PROG); 187 } 188 189 p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 190 return -1; 191 } 192 193 static void show_prog_maps(int fd, u32 num_maps) 194 { 195 struct bpf_prog_info info = {}; 196 __u32 len = sizeof(info); 197 __u32 map_ids[num_maps]; 198 unsigned int i; 199 int err; 200 201 info.nr_map_ids = num_maps; 202 info.map_ids = ptr_to_u64(map_ids); 203 204 err = bpf_obj_get_info_by_fd(fd, &info, &len); 205 if (err || !info.nr_map_ids) 206 return; 207 208 if (json_output) { 209 jsonw_name(json_wtr, "map_ids"); 210 jsonw_start_array(json_wtr); 211 for (i = 0; i < info.nr_map_ids; i++) 212 jsonw_uint(json_wtr, map_ids[i]); 213 jsonw_end_array(json_wtr); 214 } else { 215 printf(" map_ids "); 216 for (i = 0; i < info.nr_map_ids; i++) 217 printf("%u%s", map_ids[i], 218 i == info.nr_map_ids - 1 ? "" : ","); 219 } 220 } 221 222 static void print_prog_json(struct bpf_prog_info *info, int fd) 223 { 224 char *memlock; 225 226 jsonw_start_object(json_wtr); 227 jsonw_uint_field(json_wtr, "id", info->id); 228 if (info->type < ARRAY_SIZE(prog_type_name)) 229 jsonw_string_field(json_wtr, "type", 230 prog_type_name[info->type]); 231 else 232 jsonw_uint_field(json_wtr, "type", info->type); 233 234 if (*info->name) 235 jsonw_string_field(json_wtr, "name", info->name); 236 237 jsonw_name(json_wtr, "tag"); 238 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 239 info->tag[0], info->tag[1], info->tag[2], info->tag[3], 240 info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 241 242 jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 243 244 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 245 246 if (info->load_time) { 247 char buf[32]; 248 249 print_boot_time(info->load_time, buf, sizeof(buf)); 250 251 /* Piggy back on load_time, since 0 uid is a valid one */ 252 jsonw_name(json_wtr, "loaded_at"); 253 jsonw_printf(json_wtr, "%s", buf); 254 jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 255 } 256 257 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 258 259 if (info->jited_prog_len) { 260 jsonw_bool_field(json_wtr, "jited", true); 261 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 262 } else { 263 jsonw_bool_field(json_wtr, "jited", false); 264 } 265 266 memlock = get_fdinfo(fd, "memlock"); 267 if (memlock) 268 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 269 free(memlock); 270 271 if (info->nr_map_ids) 272 show_prog_maps(fd, info->nr_map_ids); 273 274 if (!hash_empty(prog_table.table)) { 275 struct pinned_obj *obj; 276 277 jsonw_name(json_wtr, "pinned"); 278 jsonw_start_array(json_wtr); 279 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 280 if (obj->id == info->id) 281 jsonw_string(json_wtr, obj->path); 282 } 283 jsonw_end_array(json_wtr); 284 } 285 286 jsonw_end_object(json_wtr); 287 } 288 289 static void print_prog_plain(struct bpf_prog_info *info, int fd) 290 { 291 char *memlock; 292 293 printf("%u: ", info->id); 294 if (info->type < ARRAY_SIZE(prog_type_name)) 295 printf("%s ", prog_type_name[info->type]); 296 else 297 printf("type %u ", info->type); 298 299 if (*info->name) 300 printf("name %s ", info->name); 301 302 printf("tag "); 303 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 304 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 305 printf("%s", info->gpl_compatible ? " gpl" : ""); 306 printf("\n"); 307 308 if (info->load_time) { 309 char buf[32]; 310 311 print_boot_time(info->load_time, buf, sizeof(buf)); 312 313 /* Piggy back on load_time, since 0 uid is a valid one */ 314 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 315 } 316 317 printf("\txlated %uB", info->xlated_prog_len); 318 319 if (info->jited_prog_len) 320 printf(" jited %uB", info->jited_prog_len); 321 else 322 printf(" not jited"); 323 324 memlock = get_fdinfo(fd, "memlock"); 325 if (memlock) 326 printf(" memlock %sB", memlock); 327 free(memlock); 328 329 if (info->nr_map_ids) 330 show_prog_maps(fd, info->nr_map_ids); 331 332 if (!hash_empty(prog_table.table)) { 333 struct pinned_obj *obj; 334 335 printf("\n"); 336 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 337 if (obj->id == info->id) 338 printf("\tpinned %s\n", obj->path); 339 } 340 } 341 342 printf("\n"); 343 } 344 345 static int show_prog(int fd) 346 { 347 struct bpf_prog_info info = {}; 348 __u32 len = sizeof(info); 349 int err; 350 351 err = bpf_obj_get_info_by_fd(fd, &info, &len); 352 if (err) { 353 p_err("can't get prog info: %s", strerror(errno)); 354 return -1; 355 } 356 357 if (json_output) 358 print_prog_json(&info, fd); 359 else 360 print_prog_plain(&info, fd); 361 362 return 0; 363 } 364 365 static int do_show(int argc, char **argv) 366 { 367 __u32 id = 0; 368 int err; 369 int fd; 370 371 if (show_pinned) 372 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 373 374 if (argc == 2) { 375 fd = prog_parse_fd(&argc, &argv); 376 if (fd < 0) 377 return -1; 378 379 return show_prog(fd); 380 } 381 382 if (argc) 383 return BAD_ARG(); 384 385 if (json_output) 386 jsonw_start_array(json_wtr); 387 while (true) { 388 err = bpf_prog_get_next_id(id, &id); 389 if (err) { 390 if (errno == ENOENT) { 391 err = 0; 392 break; 393 } 394 p_err("can't get next program: %s%s", strerror(errno), 395 errno == EINVAL ? " -- kernel too old?" : ""); 396 err = -1; 397 break; 398 } 399 400 fd = bpf_prog_get_fd_by_id(id); 401 if (fd < 0) { 402 if (errno == ENOENT) 403 continue; 404 p_err("can't get prog by id (%u): %s", 405 id, strerror(errno)); 406 err = -1; 407 break; 408 } 409 410 err = show_prog(fd); 411 close(fd); 412 if (err) 413 break; 414 } 415 416 if (json_output) 417 jsonw_end_array(json_wtr); 418 419 return err; 420 } 421 422 static int do_dump(int argc, char **argv) 423 { 424 unsigned long *func_ksyms = NULL; 425 struct bpf_prog_info info = {}; 426 unsigned int *func_lens = NULL; 427 unsigned int nr_func_ksyms; 428 unsigned int nr_func_lens; 429 struct dump_data dd = {}; 430 __u32 len = sizeof(info); 431 unsigned int buf_size; 432 char *filepath = NULL; 433 bool opcodes = false; 434 bool visual = false; 435 unsigned char *buf; 436 __u32 *member_len; 437 __u64 *member_ptr; 438 ssize_t n; 439 int err; 440 int fd; 441 442 if (is_prefix(*argv, "jited")) { 443 member_len = &info.jited_prog_len; 444 member_ptr = &info.jited_prog_insns; 445 } else if (is_prefix(*argv, "xlated")) { 446 member_len = &info.xlated_prog_len; 447 member_ptr = &info.xlated_prog_insns; 448 } else { 449 p_err("expected 'xlated' or 'jited', got: %s", *argv); 450 return -1; 451 } 452 NEXT_ARG(); 453 454 if (argc < 2) 455 usage(); 456 457 fd = prog_parse_fd(&argc, &argv); 458 if (fd < 0) 459 return -1; 460 461 if (is_prefix(*argv, "file")) { 462 NEXT_ARG(); 463 if (!argc) { 464 p_err("expected file path"); 465 return -1; 466 } 467 468 filepath = *argv; 469 NEXT_ARG(); 470 } else if (is_prefix(*argv, "opcodes")) { 471 opcodes = true; 472 NEXT_ARG(); 473 } else if (is_prefix(*argv, "visual")) { 474 visual = true; 475 NEXT_ARG(); 476 } 477 478 if (argc) { 479 usage(); 480 return -1; 481 } 482 483 err = bpf_obj_get_info_by_fd(fd, &info, &len); 484 if (err) { 485 p_err("can't get prog info: %s", strerror(errno)); 486 return -1; 487 } 488 489 if (!*member_len) { 490 p_info("no instructions returned"); 491 close(fd); 492 return 0; 493 } 494 495 buf_size = *member_len; 496 497 buf = malloc(buf_size); 498 if (!buf) { 499 p_err("mem alloc failed"); 500 close(fd); 501 return -1; 502 } 503 504 nr_func_ksyms = info.nr_jited_ksyms; 505 if (nr_func_ksyms) { 506 func_ksyms = malloc(nr_func_ksyms * sizeof(__u64)); 507 if (!func_ksyms) { 508 p_err("mem alloc failed"); 509 close(fd); 510 goto err_free; 511 } 512 } 513 514 nr_func_lens = info.nr_jited_func_lens; 515 if (nr_func_lens) { 516 func_lens = malloc(nr_func_lens * sizeof(__u32)); 517 if (!func_lens) { 518 p_err("mem alloc failed"); 519 close(fd); 520 goto err_free; 521 } 522 } 523 524 memset(&info, 0, sizeof(info)); 525 526 *member_ptr = ptr_to_u64(buf); 527 *member_len = buf_size; 528 info.jited_ksyms = ptr_to_u64(func_ksyms); 529 info.nr_jited_ksyms = nr_func_ksyms; 530 info.jited_func_lens = ptr_to_u64(func_lens); 531 info.nr_jited_func_lens = nr_func_lens; 532 533 err = bpf_obj_get_info_by_fd(fd, &info, &len); 534 close(fd); 535 if (err) { 536 p_err("can't get prog info: %s", strerror(errno)); 537 goto err_free; 538 } 539 540 if (*member_len > buf_size) { 541 p_err("too many instructions returned"); 542 goto err_free; 543 } 544 545 if (info.nr_jited_ksyms > nr_func_ksyms) { 546 p_err("too many addresses returned"); 547 goto err_free; 548 } 549 550 if (info.nr_jited_func_lens > nr_func_lens) { 551 p_err("too many values returned"); 552 goto err_free; 553 } 554 555 if ((member_len == &info.jited_prog_len && 556 info.jited_prog_insns == 0) || 557 (member_len == &info.xlated_prog_len && 558 info.xlated_prog_insns == 0)) { 559 p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 560 goto err_free; 561 } 562 563 if (filepath) { 564 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 565 if (fd < 0) { 566 p_err("can't open file %s: %s", filepath, 567 strerror(errno)); 568 goto err_free; 569 } 570 571 n = write(fd, buf, *member_len); 572 close(fd); 573 if (n != *member_len) { 574 p_err("error writing output file: %s", 575 n < 0 ? strerror(errno) : "short write"); 576 goto err_free; 577 } 578 579 if (json_output) 580 jsonw_null(json_wtr); 581 } else if (member_len == &info.jited_prog_len) { 582 const char *name = NULL; 583 584 if (info.ifindex) { 585 name = ifindex_to_bfd_name_ns(info.ifindex, 586 info.netns_dev, 587 info.netns_ino); 588 if (!name) 589 goto err_free; 590 } 591 592 if (info.nr_jited_func_lens && info.jited_func_lens) { 593 struct kernel_sym *sym = NULL; 594 char sym_name[SYM_MAX_NAME]; 595 unsigned char *img = buf; 596 __u64 *ksyms = NULL; 597 __u32 *lens; 598 __u32 i; 599 600 if (info.nr_jited_ksyms) { 601 kernel_syms_load(&dd); 602 ksyms = (__u64 *) info.jited_ksyms; 603 } 604 605 if (json_output) 606 jsonw_start_array(json_wtr); 607 608 lens = (__u32 *) info.jited_func_lens; 609 for (i = 0; i < info.nr_jited_func_lens; i++) { 610 if (ksyms) { 611 sym = kernel_syms_search(&dd, ksyms[i]); 612 if (sym) 613 sprintf(sym_name, "%s", sym->name); 614 else 615 sprintf(sym_name, "0x%016llx", ksyms[i]); 616 } else { 617 strcpy(sym_name, "unknown"); 618 } 619 620 if (json_output) { 621 jsonw_start_object(json_wtr); 622 jsonw_name(json_wtr, "name"); 623 jsonw_string(json_wtr, sym_name); 624 jsonw_name(json_wtr, "insns"); 625 } else { 626 printf("%s:\n", sym_name); 627 } 628 629 disasm_print_insn(img, lens[i], opcodes, name); 630 img += lens[i]; 631 632 if (json_output) 633 jsonw_end_object(json_wtr); 634 else 635 printf("\n"); 636 } 637 638 if (json_output) 639 jsonw_end_array(json_wtr); 640 } else { 641 disasm_print_insn(buf, *member_len, opcodes, name); 642 } 643 } else if (visual) { 644 if (json_output) 645 jsonw_null(json_wtr); 646 else 647 dump_xlated_cfg(buf, *member_len); 648 } else { 649 kernel_syms_load(&dd); 650 dd.nr_jited_ksyms = info.nr_jited_ksyms; 651 dd.jited_ksyms = (__u64 *) info.jited_ksyms; 652 653 if (json_output) 654 dump_xlated_json(&dd, buf, *member_len, opcodes); 655 else 656 dump_xlated_plain(&dd, buf, *member_len, opcodes); 657 kernel_syms_destroy(&dd); 658 } 659 660 free(buf); 661 free(func_ksyms); 662 free(func_lens); 663 return 0; 664 665 err_free: 666 free(buf); 667 free(func_ksyms); 668 free(func_lens); 669 return -1; 670 } 671 672 static int do_pin(int argc, char **argv) 673 { 674 int err; 675 676 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 677 if (!err && json_output) 678 jsonw_null(json_wtr); 679 return err; 680 } 681 682 static int do_load(int argc, char **argv) 683 { 684 struct bpf_object *obj; 685 int prog_fd; 686 687 if (argc != 2) 688 usage(); 689 690 if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) { 691 p_err("failed to load program"); 692 return -1; 693 } 694 695 if (do_pin_fd(prog_fd, argv[1])) { 696 p_err("failed to pin program"); 697 return -1; 698 } 699 700 if (json_output) 701 jsonw_null(json_wtr); 702 703 return 0; 704 } 705 706 static int do_help(int argc, char **argv) 707 { 708 if (json_output) { 709 jsonw_null(json_wtr); 710 return 0; 711 } 712 713 fprintf(stderr, 714 "Usage: %s %s { show | list } [PROG]\n" 715 " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" 716 " %s %s dump jited PROG [{ file FILE | opcodes }]\n" 717 " %s %s pin PROG FILE\n" 718 " %s %s load OBJ FILE\n" 719 " %s %s help\n" 720 "\n" 721 " " HELP_SPEC_PROGRAM "\n" 722 " " HELP_SPEC_OPTIONS "\n" 723 "", 724 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 725 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 726 727 return 0; 728 } 729 730 static const struct cmd cmds[] = { 731 { "show", do_show }, 732 { "list", do_show }, 733 { "help", do_help }, 734 { "dump", do_dump }, 735 { "pin", do_pin }, 736 { "load", do_load }, 737 { 0 } 738 }; 739 740 int do_prog(int argc, char **argv) 741 { 742 return cmd_select(cmds, argc, argv, do_help); 743 } 744