diff options
author | Dave Airlie <airlied@redhat.com> | 2018-01-17 18:32:15 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2018-01-17 18:32:15 -0500 |
commit | 4a6cc7a44e98a0460bd094b68c75f0705fdc450a (patch) | |
tree | b8c86a1e0342b1166ab52c4d79e404eede57abec /tools | |
parent | 8563188e37b000979ab66521f4337df9a3453223 (diff) | |
parent | a8750ddca918032d6349adbf9a4b6555e7db20da (diff) |
BackMerge tag 'v4.15-rc8' into drm-next
Linux 4.15-rc8
Daniel requested this for so the intel CI won't fall over on drm-next
so often.
Diffstat (limited to 'tools')
27 files changed, 1414 insertions, 170 deletions
diff --git a/tools/arch/s390/include/uapi/asm/bpf_perf_event.h b/tools/arch/s390/include/uapi/asm/bpf_perf_event.h index cefe7c7cd4f6..0a8e37a519f2 100644 --- a/tools/arch/s390/include/uapi/asm/bpf_perf_event.h +++ b/tools/arch/s390/include/uapi/asm/bpf_perf_event.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #ifndef _UAPI__ASM_BPF_PERF_EVENT_H__ | 2 | #ifndef _UAPI__ASM_BPF_PERF_EVENT_H__ |
3 | #define _UAPI__ASM_BPF_PERF_EVENT_H__ | 3 | #define _UAPI__ASM_BPF_PERF_EVENT_H__ |
4 | 4 | ||
5 | #include <asm/ptrace.h> | 5 | #include "ptrace.h" |
6 | 6 | ||
7 | typedef user_pt_regs bpf_user_pt_regs_t; | 7 | typedef user_pt_regs bpf_user_pt_regs_t; |
8 | 8 | ||
diff --git a/tools/arch/s390/include/uapi/asm/perf_regs.h b/tools/arch/s390/include/uapi/asm/perf_regs.h new file mode 100644 index 000000000000..d17dd9e5d516 --- /dev/null +++ b/tools/arch/s390/include/uapi/asm/perf_regs.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ | ||
2 | #ifndef _ASM_S390_PERF_REGS_H | ||
3 | #define _ASM_S390_PERF_REGS_H | ||
4 | |||
5 | enum perf_event_s390_regs { | ||
6 | PERF_REG_S390_R0, | ||
7 | PERF_REG_S390_R1, | ||
8 | PERF_REG_S390_R2, | ||
9 | PERF_REG_S390_R3, | ||
10 | PERF_REG_S390_R4, | ||
11 | PERF_REG_S390_R5, | ||
12 | PERF_REG_S390_R6, | ||
13 | PERF_REG_S390_R7, | ||
14 | PERF_REG_S390_R8, | ||
15 | PERF_REG_S390_R9, | ||
16 | PERF_REG_S390_R10, | ||
17 | PERF_REG_S390_R11, | ||
18 | PERF_REG_S390_R12, | ||
19 | PERF_REG_S390_R13, | ||
20 | PERF_REG_S390_R14, | ||
21 | PERF_REG_S390_R15, | ||
22 | PERF_REG_S390_FP0, | ||
23 | PERF_REG_S390_FP1, | ||
24 | PERF_REG_S390_FP2, | ||
25 | PERF_REG_S390_FP3, | ||
26 | PERF_REG_S390_FP4, | ||
27 | PERF_REG_S390_FP5, | ||
28 | PERF_REG_S390_FP6, | ||
29 | PERF_REG_S390_FP7, | ||
30 | PERF_REG_S390_FP8, | ||
31 | PERF_REG_S390_FP9, | ||
32 | PERF_REG_S390_FP10, | ||
33 | PERF_REG_S390_FP11, | ||
34 | PERF_REG_S390_FP12, | ||
35 | PERF_REG_S390_FP13, | ||
36 | PERF_REG_S390_FP14, | ||
37 | PERF_REG_S390_FP15, | ||
38 | PERF_REG_S390_MASK, | ||
39 | PERF_REG_S390_PC, | ||
40 | |||
41 | PERF_REG_S390_MAX | ||
42 | }; | ||
43 | |||
44 | #endif /* _ASM_S390_PERF_REGS_H */ | ||
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index e2450c8e88e6..a8c3a33dd185 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c | |||
@@ -523,21 +523,23 @@ static int do_show(int argc, char **argv) | |||
523 | break; | 523 | break; |
524 | p_err("can't get next map: %s%s", strerror(errno), | 524 | p_err("can't get next map: %s%s", strerror(errno), |
525 | errno == EINVAL ? " -- kernel too old?" : ""); | 525 | errno == EINVAL ? " -- kernel too old?" : ""); |
526 | return -1; | 526 | break; |
527 | } | 527 | } |
528 | 528 | ||
529 | fd = bpf_map_get_fd_by_id(id); | 529 | fd = bpf_map_get_fd_by_id(id); |
530 | if (fd < 0) { | 530 | if (fd < 0) { |
531 | if (errno == ENOENT) | ||
532 | continue; | ||
531 | p_err("can't get map by id (%u): %s", | 533 | p_err("can't get map by id (%u): %s", |
532 | id, strerror(errno)); | 534 | id, strerror(errno)); |
533 | return -1; | 535 | break; |
534 | } | 536 | } |
535 | 537 | ||
536 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | 538 | err = bpf_obj_get_info_by_fd(fd, &info, &len); |
537 | if (err) { | 539 | if (err) { |
538 | p_err("can't get map info: %s", strerror(errno)); | 540 | p_err("can't get map info: %s", strerror(errno)); |
539 | close(fd); | 541 | close(fd); |
540 | return -1; | 542 | break; |
541 | } | 543 | } |
542 | 544 | ||
543 | if (json_output) | 545 | if (json_output) |
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index ad619b96c276..dded77345bfb 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c | |||
@@ -382,6 +382,8 @@ static int do_show(int argc, char **argv) | |||
382 | 382 | ||
383 | fd = bpf_prog_get_fd_by_id(id); | 383 | fd = bpf_prog_get_fd_by_id(id); |
384 | if (fd < 0) { | 384 | if (fd < 0) { |
385 | if (errno == ENOENT) | ||
386 | continue; | ||
385 | p_err("can't get prog by id (%u): %s", | 387 | p_err("can't get prog by id (%u): %s", |
386 | id, strerror(errno)); | 388 | id, strerror(errno)); |
387 | err = -1; | 389 | err = -1; |
diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 217cf6f95c36..a5684d0968b4 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat | |||
@@ -478,7 +478,7 @@ class Provider(object): | |||
478 | @staticmethod | 478 | @staticmethod |
479 | def is_field_wanted(fields_filter, field): | 479 | def is_field_wanted(fields_filter, field): |
480 | """Indicate whether field is valid according to fields_filter.""" | 480 | """Indicate whether field is valid according to fields_filter.""" |
481 | if not fields_filter or fields_filter == "help": | 481 | if not fields_filter: |
482 | return True | 482 | return True |
483 | return re.match(fields_filter, field) is not None | 483 | return re.match(fields_filter, field) is not None |
484 | 484 | ||
@@ -549,8 +549,8 @@ class TracepointProvider(Provider): | |||
549 | 549 | ||
550 | def update_fields(self, fields_filter): | 550 | def update_fields(self, fields_filter): |
551 | """Refresh fields, applying fields_filter""" | 551 | """Refresh fields, applying fields_filter""" |
552 | self._fields = [field for field in self.get_available_fields() | 552 | self.fields = [field for field in self.get_available_fields() |
553 | if self.is_field_wanted(fields_filter, field)] | 553 | if self.is_field_wanted(fields_filter, field)] |
554 | 554 | ||
555 | @staticmethod | 555 | @staticmethod |
556 | def get_online_cpus(): | 556 | def get_online_cpus(): |
@@ -950,7 +950,8 @@ class Tui(object): | |||
950 | curses.nocbreak() | 950 | curses.nocbreak() |
951 | curses.endwin() | 951 | curses.endwin() |
952 | 952 | ||
953 | def get_all_gnames(self): | 953 | @staticmethod |
954 | def get_all_gnames(): | ||
954 | """Returns a list of (pid, gname) tuples of all running guests""" | 955 | """Returns a list of (pid, gname) tuples of all running guests""" |
955 | res = [] | 956 | res = [] |
956 | try: | 957 | try: |
@@ -963,7 +964,7 @@ class Tui(object): | |||
963 | # perform a sanity check before calling the more expensive | 964 | # perform a sanity check before calling the more expensive |
964 | # function to possibly extract the guest name | 965 | # function to possibly extract the guest name |
965 | if ' -name ' in line[1]: | 966 | if ' -name ' in line[1]: |
966 | res.append((line[0], self.get_gname_from_pid(line[0]))) | 967 | res.append((line[0], Tui.get_gname_from_pid(line[0]))) |
967 | child.stdout.close() | 968 | child.stdout.close() |
968 | 969 | ||
969 | return res | 970 | return res |
@@ -984,7 +985,8 @@ class Tui(object): | |||
984 | except Exception: | 985 | except Exception: |
985 | self.screen.addstr(row + 1, 2, 'Not available') | 986 | self.screen.addstr(row + 1, 2, 'Not available') |
986 | 987 | ||
987 | def get_pid_from_gname(self, gname): | 988 | @staticmethod |
989 | def get_pid_from_gname(gname): | ||
988 | """Fuzzy function to convert guest name to QEMU process pid. | 990 | """Fuzzy function to convert guest name to QEMU process pid. |
989 | 991 | ||
990 | Returns a list of potential pids, can be empty if no match found. | 992 | Returns a list of potential pids, can be empty if no match found. |
@@ -992,7 +994,7 @@ class Tui(object): | |||
992 | 994 | ||
993 | """ | 995 | """ |
994 | pids = [] | 996 | pids = [] |
995 | for line in self.get_all_gnames(): | 997 | for line in Tui.get_all_gnames(): |
996 | if gname == line[1]: | 998 | if gname == line[1]: |
997 | pids.append(int(line[0])) | 999 | pids.append(int(line[0])) |
998 | 1000 | ||
@@ -1090,15 +1092,16 @@ class Tui(object): | |||
1090 | # sort by totals | 1092 | # sort by totals |
1091 | return (0, -stats[x][0]) | 1093 | return (0, -stats[x][0]) |
1092 | total = 0. | 1094 | total = 0. |
1093 | for val in stats.values(): | 1095 | for key in stats.keys(): |
1094 | total += val[0] | 1096 | if key.find('(') is -1: |
1097 | total += stats[key][0] | ||
1095 | if self._sorting == SORT_DEFAULT: | 1098 | if self._sorting == SORT_DEFAULT: |
1096 | sortkey = sortCurAvg | 1099 | sortkey = sortCurAvg |
1097 | else: | 1100 | else: |
1098 | sortkey = sortTotal | 1101 | sortkey = sortTotal |
1102 | tavg = 0 | ||
1099 | for key in sorted(stats.keys(), key=sortkey): | 1103 | for key in sorted(stats.keys(), key=sortkey): |
1100 | 1104 | if row >= self.screen.getmaxyx()[0] - 1: | |
1101 | if row >= self.screen.getmaxyx()[0]: | ||
1102 | break | 1105 | break |
1103 | values = stats[key] | 1106 | values = stats[key] |
1104 | if not values[0] and not values[1]: | 1107 | if not values[0] and not values[1]: |
@@ -1110,9 +1113,15 @@ class Tui(object): | |||
1110 | self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' % | 1113 | self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' % |
1111 | (key, values[0], values[0] * 100 / total, | 1114 | (key, values[0], values[0] * 100 / total, |
1112 | cur)) | 1115 | cur)) |
1116 | if cur is not '' and key.find('(') is -1: | ||
1117 | tavg += cur | ||
1113 | row += 1 | 1118 | row += 1 |
1114 | if row == 3: | 1119 | if row == 3: |
1115 | self.screen.addstr(4, 1, 'No matching events reported yet') | 1120 | self.screen.addstr(4, 1, 'No matching events reported yet') |
1121 | else: | ||
1122 | self.screen.addstr(row, 1, '%-40s %10d %8s' % | ||
1123 | ('Total', total, tavg if tavg else ''), | ||
1124 | curses.A_BOLD) | ||
1116 | self.screen.refresh() | 1125 | self.screen.refresh() |
1117 | 1126 | ||
1118 | def show_msg(self, text): | 1127 | def show_msg(self, text): |
@@ -1358,7 +1367,7 @@ class Tui(object): | |||
1358 | if char == 'x': | 1367 | if char == 'x': |
1359 | self.update_drilldown() | 1368 | self.update_drilldown() |
1360 | # prevents display of current values on next refresh | 1369 | # prevents display of current values on next refresh |
1361 | self.stats.get() | 1370 | self.stats.get(self._display_guests) |
1362 | except KeyboardInterrupt: | 1371 | except KeyboardInterrupt: |
1363 | break | 1372 | break |
1364 | except curses.error: | 1373 | except curses.error: |
@@ -1451,16 +1460,13 @@ Press any other key to refresh statistics immediately. | |||
1451 | try: | 1460 | try: |
1452 | pids = Tui.get_pid_from_gname(val) | 1461 | pids = Tui.get_pid_from_gname(val) |
1453 | except: | 1462 | except: |
1454 | raise optparse.OptionValueError('Error while searching for guest ' | 1463 | sys.exit('Error while searching for guest "{}". Use "-p" to ' |
1455 | '"{}", use "-p" to specify a pid ' | 1464 | 'specify a pid instead?'.format(val)) |
1456 | 'instead'.format(val)) | ||
1457 | if len(pids) == 0: | 1465 | if len(pids) == 0: |
1458 | raise optparse.OptionValueError('No guest by the name "{}" ' | 1466 | sys.exit('Error: No guest by the name "{}" found'.format(val)) |
1459 | 'found'.format(val)) | ||
1460 | if len(pids) > 1: | 1467 | if len(pids) > 1: |
1461 | raise optparse.OptionValueError('Multiple processes found (pids: ' | 1468 | sys.exit('Error: Multiple processes found (pids: {}). Use "-p" ' |
1462 | '{}) - use "-p" to specify a pid ' | 1469 | 'to specify the desired pid'.format(" ".join(pids))) |
1463 | 'instead'.format(" ".join(pids))) | ||
1464 | parser.values.pid = pids[0] | 1470 | parser.values.pid = pids[0] |
1465 | 1471 | ||
1466 | optparser = optparse.OptionParser(description=description_text, | 1472 | optparser = optparse.OptionParser(description=description_text, |
@@ -1518,7 +1524,16 @@ Press any other key to refresh statistics immediately. | |||
1518 | help='restrict statistics to guest by name', | 1524 | help='restrict statistics to guest by name', |
1519 | callback=cb_guest_to_pid, | 1525 | callback=cb_guest_to_pid, |
1520 | ) | 1526 | ) |
1521 | (options, _) = optparser.parse_args(sys.argv) | 1527 | options, unkn = optparser.parse_args(sys.argv) |
1528 | if len(unkn) != 1: | ||
1529 | sys.exit('Error: Extra argument(s): ' + ' '.join(unkn[1:])) | ||
1530 | try: | ||
1531 | # verify that we were passed a valid regex up front | ||
1532 | re.compile(options.fields) | ||
1533 | except re.error: | ||
1534 | sys.exit('Error: "' + options.fields + '" is not a valid regular ' | ||
1535 | 'expression') | ||
1536 | |||
1522 | return options | 1537 | return options |
1523 | 1538 | ||
1524 | 1539 | ||
@@ -1564,16 +1579,13 @@ def main(): | |||
1564 | 1579 | ||
1565 | stats = Stats(options) | 1580 | stats = Stats(options) |
1566 | 1581 | ||
1567 | if options.fields == "help": | 1582 | if options.fields == 'help': |
1568 | event_list = "\n" | 1583 | stats.fields_filter = None |
1569 | s = stats.get() | 1584 | event_list = [] |
1570 | for key in s.keys(): | 1585 | for key in stats.get().keys(): |
1571 | if key.find('(') != -1: | 1586 | event_list.append(key.split('(', 1)[0]) |
1572 | key = key[0:key.find('(')] | 1587 | sys.stdout.write(' ' + '\n '.join(sorted(set(event_list))) + '\n') |
1573 | if event_list.find('\n' + key + '\n') == -1: | 1588 | sys.exit(0) |
1574 | event_list += key + '\n' | ||
1575 | sys.stdout.write(event_list) | ||
1576 | return "" | ||
1577 | 1589 | ||
1578 | if options.log: | 1590 | if options.log: |
1579 | log(stats) | 1591 | log(stats) |
diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt index e5cf836be8a1..b5b3810c9e94 100644 --- a/tools/kvm/kvm_stat/kvm_stat.txt +++ b/tools/kvm/kvm_stat/kvm_stat.txt | |||
@@ -50,6 +50,8 @@ INTERACTIVE COMMANDS | |||
50 | *s*:: set update interval | 50 | *s*:: set update interval |
51 | 51 | ||
52 | *x*:: toggle reporting of stats for child trace events | 52 | *x*:: toggle reporting of stats for child trace events |
53 | :: *Note*: The stats for the parents summarize the respective child trace | ||
54 | events | ||
53 | 55 | ||
54 | Press any other key to refresh statistics immediately. | 56 | Press any other key to refresh statistics immediately. |
55 | 57 | ||
@@ -86,7 +88,7 @@ OPTIONS | |||
86 | 88 | ||
87 | -f<fields>:: | 89 | -f<fields>:: |
88 | --fields=<fields>:: | 90 | --fields=<fields>:: |
89 | fields to display (regex) | 91 | fields to display (regex), "-f help" for a list of available events |
90 | 92 | ||
91 | -h:: | 93 | -h:: |
92 | --help:: | 94 | --help:: |
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index ae0272f9a091..e6acc281dd37 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile | |||
@@ -46,7 +46,7 @@ $(OBJTOOL_IN): fixdep FORCE | |||
46 | @$(MAKE) $(build)=objtool | 46 | @$(MAKE) $(build)=objtool |
47 | 47 | ||
48 | $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) | 48 | $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) |
49 | @./sync-check.sh | 49 | @$(CONFIG_SHELL) ./sync-check.sh |
50 | $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ | 50 | $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ |
51 | 51 | ||
52 | 52 | ||
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 8acfc47af70e..540a209b78ab 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c | |||
@@ -138,7 +138,7 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | |||
138 | *type = INSN_STACK; | 138 | *type = INSN_STACK; |
139 | op->src.type = OP_SRC_ADD; | 139 | op->src.type = OP_SRC_ADD; |
140 | op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; | 140 | op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; |
141 | op->dest.type = OP_SRC_REG; | 141 | op->dest.type = OP_DEST_REG; |
142 | op->dest.reg = CFI_SP; | 142 | op->dest.reg = CFI_SP; |
143 | } | 143 | } |
144 | break; | 144 | break; |
diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c index 4c6b5c9ef073..91e8e19ff5e0 100644 --- a/tools/objtool/builtin-orc.c +++ b/tools/objtool/builtin-orc.c | |||
@@ -44,6 +44,9 @@ int cmd_orc(int argc, const char **argv) | |||
44 | const char *objname; | 44 | const char *objname; |
45 | 45 | ||
46 | argc--; argv++; | 46 | argc--; argv++; |
47 | if (argc <= 0) | ||
48 | usage_with_options(orc_usage, check_options); | ||
49 | |||
47 | if (!strncmp(argv[0], "gen", 3)) { | 50 | if (!strncmp(argv[0], "gen", 3)) { |
48 | argc = parse_options(argc, argv, check_options, orc_usage, 0); | 51 | argc = parse_options(argc, argv, check_options, orc_usage, 0); |
49 | if (argc != 1) | 52 | if (argc != 1) |
@@ -52,7 +55,6 @@ int cmd_orc(int argc, const char **argv) | |||
52 | objname = argv[0]; | 55 | objname = argv[0]; |
53 | 56 | ||
54 | return check(objname, no_fp, no_unreachable, true); | 57 | return check(objname, no_fp, no_unreachable, true); |
55 | |||
56 | } | 58 | } |
57 | 59 | ||
58 | if (!strcmp(argv[0], "dump")) { | 60 | if (!strcmp(argv[0], "dump")) { |
diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 9b341584eb1b..f40d46e24bcc 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c | |||
@@ -428,6 +428,40 @@ static void add_ignores(struct objtool_file *file) | |||
428 | } | 428 | } |
429 | 429 | ||
430 | /* | 430 | /* |
431 | * FIXME: For now, just ignore any alternatives which add retpolines. This is | ||
432 | * a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline. | ||
433 | * But it at least allows objtool to understand the control flow *around* the | ||
434 | * retpoline. | ||
435 | */ | ||
436 | static int add_nospec_ignores(struct objtool_file *file) | ||
437 | { | ||
438 | struct section *sec; | ||
439 | struct rela *rela; | ||
440 | struct instruction *insn; | ||
441 | |||
442 | sec = find_section_by_name(file->elf, ".rela.discard.nospec"); | ||
443 | if (!sec) | ||
444 | return 0; | ||
445 | |||
446 | list_for_each_entry(rela, &sec->rela_list, list) { | ||
447 | if (rela->sym->type != STT_SECTION) { | ||
448 | WARN("unexpected relocation symbol type in %s", sec->name); | ||
449 | return -1; | ||
450 | } | ||
451 | |||
452 | insn = find_insn(file, rela->sym->sec, rela->addend); | ||
453 | if (!insn) { | ||
454 | WARN("bad .discard.nospec entry"); | ||
455 | return -1; | ||
456 | } | ||
457 | |||
458 | insn->ignore_alts = true; | ||
459 | } | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | /* | ||
431 | * Find the destination instructions for all jumps. | 465 | * Find the destination instructions for all jumps. |
432 | */ | 466 | */ |
433 | static int add_jump_destinations(struct objtool_file *file) | 467 | static int add_jump_destinations(struct objtool_file *file) |
@@ -456,6 +490,13 @@ static int add_jump_destinations(struct objtool_file *file) | |||
456 | } else if (rela->sym->sec->idx) { | 490 | } else if (rela->sym->sec->idx) { |
457 | dest_sec = rela->sym->sec; | 491 | dest_sec = rela->sym->sec; |
458 | dest_off = rela->sym->sym.st_value + rela->addend + 4; | 492 | dest_off = rela->sym->sym.st_value + rela->addend + 4; |
493 | } else if (strstr(rela->sym->name, "_indirect_thunk_")) { | ||
494 | /* | ||
495 | * Retpoline jumps are really dynamic jumps in | ||
496 | * disguise, so convert them accordingly. | ||
497 | */ | ||
498 | insn->type = INSN_JUMP_DYNAMIC; | ||
499 | continue; | ||
459 | } else { | 500 | } else { |
460 | /* sibling call */ | 501 | /* sibling call */ |
461 | insn->jump_dest = 0; | 502 | insn->jump_dest = 0; |
@@ -502,11 +543,18 @@ static int add_call_destinations(struct objtool_file *file) | |||
502 | dest_off = insn->offset + insn->len + insn->immediate; | 543 | dest_off = insn->offset + insn->len + insn->immediate; |
503 | insn->call_dest = find_symbol_by_offset(insn->sec, | 544 | insn->call_dest = find_symbol_by_offset(insn->sec, |
504 | dest_off); | 545 | dest_off); |
546 | /* | ||
547 | * FIXME: Thanks to retpolines, it's now considered | ||
548 | * normal for a function to call within itself. So | ||
549 | * disable this warning for now. | ||
550 | */ | ||
551 | #if 0 | ||
505 | if (!insn->call_dest) { | 552 | if (!insn->call_dest) { |
506 | WARN_FUNC("can't find call dest symbol at offset 0x%lx", | 553 | WARN_FUNC("can't find call dest symbol at offset 0x%lx", |
507 | insn->sec, insn->offset, dest_off); | 554 | insn->sec, insn->offset, dest_off); |
508 | return -1; | 555 | return -1; |
509 | } | 556 | } |
557 | #endif | ||
510 | } else if (rela->sym->type == STT_SECTION) { | 558 | } else if (rela->sym->type == STT_SECTION) { |
511 | insn->call_dest = find_symbol_by_offset(rela->sym->sec, | 559 | insn->call_dest = find_symbol_by_offset(rela->sym->sec, |
512 | rela->addend+4); | 560 | rela->addend+4); |
@@ -671,12 +719,6 @@ static int add_special_section_alts(struct objtool_file *file) | |||
671 | return ret; | 719 | return ret; |
672 | 720 | ||
673 | list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { | 721 | list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { |
674 | alt = malloc(sizeof(*alt)); | ||
675 | if (!alt) { | ||
676 | WARN("malloc failed"); | ||
677 | ret = -1; | ||
678 | goto out; | ||
679 | } | ||
680 | 722 | ||
681 | orig_insn = find_insn(file, special_alt->orig_sec, | 723 | orig_insn = find_insn(file, special_alt->orig_sec, |
682 | special_alt->orig_off); | 724 | special_alt->orig_off); |
@@ -687,6 +729,10 @@ static int add_special_section_alts(struct objtool_file *file) | |||
687 | goto out; | 729 | goto out; |
688 | } | 730 | } |
689 | 731 | ||
732 | /* Ignore retpoline alternatives. */ | ||
733 | if (orig_insn->ignore_alts) | ||
734 | continue; | ||
735 | |||
690 | new_insn = NULL; | 736 | new_insn = NULL; |
691 | if (!special_alt->group || special_alt->new_len) { | 737 | if (!special_alt->group || special_alt->new_len) { |
692 | new_insn = find_insn(file, special_alt->new_sec, | 738 | new_insn = find_insn(file, special_alt->new_sec, |
@@ -712,6 +758,13 @@ static int add_special_section_alts(struct objtool_file *file) | |||
712 | goto out; | 758 | goto out; |
713 | } | 759 | } |
714 | 760 | ||
761 | alt = malloc(sizeof(*alt)); | ||
762 | if (!alt) { | ||
763 | WARN("malloc failed"); | ||
764 | ret = -1; | ||
765 | goto out; | ||
766 | } | ||
767 | |||
715 | alt->insn = new_insn; | 768 | alt->insn = new_insn; |
716 | list_add_tail(&alt->list, &orig_insn->alts); | 769 | list_add_tail(&alt->list, &orig_insn->alts); |
717 | 770 | ||
@@ -1028,6 +1081,10 @@ static int decode_sections(struct objtool_file *file) | |||
1028 | 1081 | ||
1029 | add_ignores(file); | 1082 | add_ignores(file); |
1030 | 1083 | ||
1084 | ret = add_nospec_ignores(file); | ||
1085 | if (ret) | ||
1086 | return ret; | ||
1087 | |||
1031 | ret = add_jump_destinations(file); | 1088 | ret = add_jump_destinations(file); |
1032 | if (ret) | 1089 | if (ret) |
1033 | return ret; | 1090 | return ret; |
diff --git a/tools/objtool/check.h b/tools/objtool/check.h index 47d9ea70a83d..dbadb304a410 100644 --- a/tools/objtool/check.h +++ b/tools/objtool/check.h | |||
@@ -44,7 +44,7 @@ struct instruction { | |||
44 | unsigned int len; | 44 | unsigned int len; |
45 | unsigned char type; | 45 | unsigned char type; |
46 | unsigned long immediate; | 46 | unsigned long immediate; |
47 | bool alt_group, visited, dead_end, ignore, hint, save, restore; | 47 | bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; |
48 | struct symbol *call_dest; | 48 | struct symbol *call_dest; |
49 | struct instruction *jump_dest; | 49 | struct instruction *jump_dest; |
50 | struct list_head alts; | 50 | struct list_head alts; |
diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index e5ca31429c9b..e61fe703197b 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c | |||
@@ -165,6 +165,8 @@ int create_orc_sections(struct objtool_file *file) | |||
165 | 165 | ||
166 | /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */ | 166 | /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */ |
167 | sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx); | 167 | sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx); |
168 | if (!sec) | ||
169 | return -1; | ||
168 | 170 | ||
169 | ip_relasec = elf_create_rela_section(file->elf, sec); | 171 | ip_relasec = elf_create_rela_section(file->elf, sec); |
170 | if (!ip_relasec) | 172 | if (!ip_relasec) |
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index ed65e82f034e..0294bfb6c5f8 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config | |||
@@ -188,9 +188,7 @@ ifdef PYTHON_CONFIG | |||
188 | PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) | 188 | PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) |
189 | PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil | 189 | PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil |
190 | PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) | 190 | PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) |
191 | ifeq ($(CC_NO_CLANG), 1) | 191 | PYTHON_EMBED_CCOPTS := $(filter-out -specs=%,$(PYTHON_EMBED_CCOPTS)) |
192 | PYTHON_EMBED_CCOPTS := $(filter-out -specs=%,$(PYTHON_EMBED_CCOPTS)) | ||
193 | endif | ||
194 | FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) | 192 | FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) |
195 | endif | 193 | endif |
196 | 194 | ||
@@ -576,14 +574,15 @@ ifndef NO_GTK2 | |||
576 | endif | 574 | endif |
577 | endif | 575 | endif |
578 | 576 | ||
579 | |||
580 | ifdef NO_LIBPERL | 577 | ifdef NO_LIBPERL |
581 | CFLAGS += -DNO_LIBPERL | 578 | CFLAGS += -DNO_LIBPERL |
582 | else | 579 | else |
583 | PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null) | 580 | PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null) |
584 | PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS)) | 581 | PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS)) |
585 | PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) | 582 | PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) |
586 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` | 583 | PERL_EMBED_CCOPTS = $(shell perl -MExtUtils::Embed -e ccopts 2>/dev/null) |
584 | PERL_EMBED_CCOPTS := $(filter-out -specs=%,$(PERL_EMBED_CCOPTS)) | ||
585 | PERL_EMBED_LDOPTS := $(filter-out -specs=%,$(PERL_EMBED_LDOPTS)) | ||
587 | FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) | 586 | FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) |
588 | 587 | ||
589 | ifneq ($(feature-libperl), 1) | 588 | ifneq ($(feature-libperl), 1) |
diff --git a/tools/perf/arch/s390/include/perf_regs.h b/tools/perf/arch/s390/include/perf_regs.h index d2df54a6bc5a..bcfbaed78cc2 100644 --- a/tools/perf/arch/s390/include/perf_regs.h +++ b/tools/perf/arch/s390/include/perf_regs.h | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
6 | #include <../../../../arch/s390/include/uapi/asm/perf_regs.h> | 6 | #include <asm/perf_regs.h> |
7 | 7 | ||
8 | void perf_regs_load(u64 *regs); | 8 | void perf_regs_load(u64 *regs); |
9 | 9 | ||
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 6db9d809fe97..3e64f10b6d66 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh | |||
@@ -21,6 +21,7 @@ arch/x86/include/asm/cpufeatures.h | |||
21 | arch/arm/include/uapi/asm/perf_regs.h | 21 | arch/arm/include/uapi/asm/perf_regs.h |
22 | arch/arm64/include/uapi/asm/perf_regs.h | 22 | arch/arm64/include/uapi/asm/perf_regs.h |
23 | arch/powerpc/include/uapi/asm/perf_regs.h | 23 | arch/powerpc/include/uapi/asm/perf_regs.h |
24 | arch/s390/include/uapi/asm/perf_regs.h | ||
24 | arch/x86/include/uapi/asm/perf_regs.h | 25 | arch/x86/include/uapi/asm/perf_regs.h |
25 | arch/x86/include/uapi/asm/kvm.h | 26 | arch/x86/include/uapi/asm/kvm.h |
26 | arch/x86/include/uapi/asm/kvm_perf.h | 27 | arch/x86/include/uapi/asm/kvm_perf.h |
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c index cf36de7ea255..0c6d1002b524 100644 --- a/tools/perf/jvmti/jvmti_agent.c +++ b/tools/perf/jvmti/jvmti_agent.c | |||
@@ -384,13 +384,13 @@ jvmti_write_code(void *agent, char const *sym, | |||
384 | } | 384 | } |
385 | 385 | ||
386 | int | 386 | int |
387 | jvmti_write_debug_info(void *agent, uint64_t code, const char *file, | 387 | jvmti_write_debug_info(void *agent, uint64_t code, |
388 | jvmti_line_info_t *li, int nr_lines) | 388 | int nr_lines, jvmti_line_info_t *li, |
389 | const char * const * file_names) | ||
389 | { | 390 | { |
390 | struct jr_code_debug_info rec; | 391 | struct jr_code_debug_info rec; |
391 | size_t sret, len, size, flen; | 392 | size_t sret, len, size, flen = 0; |
392 | uint64_t addr; | 393 | uint64_t addr; |
393 | const char *fn = file; | ||
394 | FILE *fp = agent; | 394 | FILE *fp = agent; |
395 | int i; | 395 | int i; |
396 | 396 | ||
@@ -405,7 +405,9 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file, | |||
405 | return -1; | 405 | return -1; |
406 | } | 406 | } |
407 | 407 | ||
408 | flen = strlen(file) + 1; | 408 | for (i = 0; i < nr_lines; ++i) { |
409 | flen += strlen(file_names[i]) + 1; | ||
410 | } | ||
409 | 411 | ||
410 | rec.p.id = JIT_CODE_DEBUG_INFO; | 412 | rec.p.id = JIT_CODE_DEBUG_INFO; |
411 | size = sizeof(rec); | 413 | size = sizeof(rec); |
@@ -421,7 +423,7 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file, | |||
421 | * file[] : source file name | 423 | * file[] : source file name |
422 | */ | 424 | */ |
423 | size += nr_lines * sizeof(struct debug_entry); | 425 | size += nr_lines * sizeof(struct debug_entry); |
424 | size += flen * nr_lines; | 426 | size += flen; |
425 | rec.p.total_size = size; | 427 | rec.p.total_size = size; |
426 | 428 | ||
427 | /* | 429 | /* |
@@ -452,7 +454,7 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file, | |||
452 | if (sret != 1) | 454 | if (sret != 1) |
453 | goto error; | 455 | goto error; |
454 | 456 | ||
455 | sret = fwrite_unlocked(fn, flen, 1, fp); | 457 | sret = fwrite_unlocked(file_names[i], strlen(file_names[i]) + 1, 1, fp); |
456 | if (sret != 1) | 458 | if (sret != 1) |
457 | goto error; | 459 | goto error; |
458 | } | 460 | } |
diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h index fe32d8344a82..6ed82f6c06dd 100644 --- a/tools/perf/jvmti/jvmti_agent.h +++ b/tools/perf/jvmti/jvmti_agent.h | |||
@@ -14,6 +14,7 @@ typedef struct { | |||
14 | unsigned long pc; | 14 | unsigned long pc; |
15 | int line_number; | 15 | int line_number; |
16 | int discrim; /* discriminator -- 0 for now */ | 16 | int discrim; /* discriminator -- 0 for now */ |
17 | jmethodID methodID; | ||
17 | } jvmti_line_info_t; | 18 | } jvmti_line_info_t; |
18 | 19 | ||
19 | void *jvmti_open(void); | 20 | void *jvmti_open(void); |
@@ -22,11 +23,9 @@ int jvmti_write_code(void *agent, char const *symbol_name, | |||
22 | uint64_t vma, void const *code, | 23 | uint64_t vma, void const *code, |
23 | const unsigned int code_size); | 24 | const unsigned int code_size); |
24 | 25 | ||
25 | int jvmti_write_debug_info(void *agent, | 26 | int jvmti_write_debug_info(void *agent, uint64_t code, int nr_lines, |
26 | uint64_t code, | ||
27 | const char *file, | ||
28 | jvmti_line_info_t *li, | 27 | jvmti_line_info_t *li, |
29 | int nr_lines); | 28 | const char * const * file_names); |
30 | 29 | ||
31 | #if defined(__cplusplus) | 30 | #if defined(__cplusplus) |
32 | } | 31 | } |
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c index c62c9fc9a525..6add3e982614 100644 --- a/tools/perf/jvmti/libjvmti.c +++ b/tools/perf/jvmti/libjvmti.c | |||
@@ -47,6 +47,7 @@ do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci, | |||
47 | tab[lines].pc = (unsigned long)pc; | 47 | tab[lines].pc = (unsigned long)pc; |
48 | tab[lines].line_number = loc_tab[i].line_number; | 48 | tab[lines].line_number = loc_tab[i].line_number; |
49 | tab[lines].discrim = 0; /* not yet used */ | 49 | tab[lines].discrim = 0; /* not yet used */ |
50 | tab[lines].methodID = m; | ||
50 | lines++; | 51 | lines++; |
51 | } else { | 52 | } else { |
52 | break; | 53 | break; |
@@ -125,6 +126,99 @@ get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t ** | |||
125 | return JVMTI_ERROR_NONE; | 126 | return JVMTI_ERROR_NONE; |
126 | } | 127 | } |
127 | 128 | ||
129 | static void | ||
130 | copy_class_filename(const char * class_sign, const char * file_name, char * result, size_t max_length) | ||
131 | { | ||
132 | /* | ||
133 | * Assume path name is class hierarchy, this is a common practice with Java programs | ||
134 | */ | ||
135 | if (*class_sign == 'L') { | ||
136 | int j, i = 0; | ||
137 | char *p = strrchr(class_sign, '/'); | ||
138 | if (p) { | ||
139 | /* drop the 'L' prefix and copy up to the final '/' */ | ||
140 | for (i = 0; i < (p - class_sign); i++) | ||
141 | result[i] = class_sign[i+1]; | ||
142 | } | ||
143 | /* | ||
144 | * append file name, we use loops and not string ops to avoid modifying | ||
145 | * class_sign which is used later for the symbol name | ||
146 | */ | ||
147 | for (j = 0; i < (max_length - 1) && file_name && j < strlen(file_name); j++, i++) | ||
148 | result[i] = file_name[j]; | ||
149 | |||
150 | result[i] = '\0'; | ||
151 | } else { | ||
152 | /* fallback case */ | ||
153 | size_t file_name_len = strlen(file_name); | ||
154 | strncpy(result, file_name, file_name_len < max_length ? file_name_len : max_length); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | static jvmtiError | ||
159 | get_source_filename(jvmtiEnv *jvmti, jmethodID methodID, char ** buffer) | ||
160 | { | ||
161 | jvmtiError ret; | ||
162 | jclass decl_class; | ||
163 | char *file_name = NULL; | ||
164 | char *class_sign = NULL; | ||
165 | char fn[PATH_MAX]; | ||
166 | size_t len; | ||
167 | |||
168 | ret = (*jvmti)->GetMethodDeclaringClass(jvmti, methodID, &decl_class); | ||
169 | if (ret != JVMTI_ERROR_NONE) { | ||
170 | print_error(jvmti, "GetMethodDeclaringClass", ret); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name); | ||
175 | if (ret != JVMTI_ERROR_NONE) { | ||
176 | print_error(jvmti, "GetSourceFileName", ret); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | ret = (*jvmti)->GetClassSignature(jvmti, decl_class, &class_sign, NULL); | ||
181 | if (ret != JVMTI_ERROR_NONE) { | ||
182 | print_error(jvmti, "GetClassSignature", ret); | ||
183 | goto free_file_name_error; | ||
184 | } | ||
185 | |||
186 | copy_class_filename(class_sign, file_name, fn, PATH_MAX); | ||
187 | len = strlen(fn); | ||
188 | *buffer = malloc((len + 1) * sizeof(char)); | ||
189 | if (!*buffer) { | ||
190 | print_error(jvmti, "GetClassSignature", ret); | ||
191 | ret = JVMTI_ERROR_OUT_OF_MEMORY; | ||
192 | goto free_class_sign_error; | ||
193 | } | ||
194 | strcpy(*buffer, fn); | ||
195 | ret = JVMTI_ERROR_NONE; | ||
196 | |||
197 | free_class_sign_error: | ||
198 | (*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign); | ||
199 | free_file_name_error: | ||
200 | (*jvmti)->Deallocate(jvmti, (unsigned char *)file_name); | ||
201 | |||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | static jvmtiError | ||
206 | fill_source_filenames(jvmtiEnv *jvmti, int nr_lines, | ||
207 | const jvmti_line_info_t * line_tab, | ||
208 | char ** file_names) | ||
209 | { | ||
210 | int index; | ||
211 | jvmtiError ret; | ||
212 | |||
213 | for (index = 0; index < nr_lines; ++index) { | ||
214 | ret = get_source_filename(jvmti, line_tab[index].methodID, &(file_names[index])); | ||
215 | if (ret != JVMTI_ERROR_NONE) | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | return JVMTI_ERROR_NONE; | ||
220 | } | ||
221 | |||
128 | static void JNICALL | 222 | static void JNICALL |
129 | compiled_method_load_cb(jvmtiEnv *jvmti, | 223 | compiled_method_load_cb(jvmtiEnv *jvmti, |
130 | jmethodID method, | 224 | jmethodID method, |
@@ -135,16 +229,18 @@ compiled_method_load_cb(jvmtiEnv *jvmti, | |||
135 | const void *compile_info) | 229 | const void *compile_info) |
136 | { | 230 | { |
137 | jvmti_line_info_t *line_tab = NULL; | 231 | jvmti_line_info_t *line_tab = NULL; |
232 | char ** line_file_names = NULL; | ||
138 | jclass decl_class; | 233 | jclass decl_class; |
139 | char *class_sign = NULL; | 234 | char *class_sign = NULL; |
140 | char *func_name = NULL; | 235 | char *func_name = NULL; |
141 | char *func_sign = NULL; | 236 | char *func_sign = NULL; |
142 | char *file_name= NULL; | 237 | char *file_name = NULL; |
143 | char fn[PATH_MAX]; | 238 | char fn[PATH_MAX]; |
144 | uint64_t addr = (uint64_t)(uintptr_t)code_addr; | 239 | uint64_t addr = (uint64_t)(uintptr_t)code_addr; |
145 | jvmtiError ret; | 240 | jvmtiError ret; |
146 | int nr_lines = 0; /* in line_tab[] */ | 241 | int nr_lines = 0; /* in line_tab[] */ |
147 | size_t len; | 242 | size_t len; |
243 | int output_debug_info = 0; | ||
148 | 244 | ||
149 | ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method, | 245 | ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method, |
150 | &decl_class); | 246 | &decl_class); |
@@ -158,6 +254,19 @@ compiled_method_load_cb(jvmtiEnv *jvmti, | |||
158 | if (ret != JVMTI_ERROR_NONE) { | 254 | if (ret != JVMTI_ERROR_NONE) { |
159 | warnx("jvmti: cannot get line table for method"); | 255 | warnx("jvmti: cannot get line table for method"); |
160 | nr_lines = 0; | 256 | nr_lines = 0; |
257 | } else if (nr_lines > 0) { | ||
258 | line_file_names = malloc(sizeof(char*) * nr_lines); | ||
259 | if (!line_file_names) { | ||
260 | warnx("jvmti: cannot allocate space for line table method names"); | ||
261 | } else { | ||
262 | memset(line_file_names, 0, sizeof(char*) * nr_lines); | ||
263 | ret = fill_source_filenames(jvmti, nr_lines, line_tab, line_file_names); | ||
264 | if (ret != JVMTI_ERROR_NONE) { | ||
265 | warnx("jvmti: fill_source_filenames failed"); | ||
266 | } else { | ||
267 | output_debug_info = 1; | ||
268 | } | ||
269 | } | ||
161 | } | 270 | } |
162 | } | 271 | } |
163 | 272 | ||
@@ -181,33 +290,14 @@ compiled_method_load_cb(jvmtiEnv *jvmti, | |||
181 | goto error; | 290 | goto error; |
182 | } | 291 | } |
183 | 292 | ||
184 | /* | 293 | copy_class_filename(class_sign, file_name, fn, PATH_MAX); |
185 | * Assume path name is class hierarchy, this is a common practice with Java programs | 294 | |
186 | */ | ||
187 | if (*class_sign == 'L') { | ||
188 | int j, i = 0; | ||
189 | char *p = strrchr(class_sign, '/'); | ||
190 | if (p) { | ||
191 | /* drop the 'L' prefix and copy up to the final '/' */ | ||
192 | for (i = 0; i < (p - class_sign); i++) | ||
193 | fn[i] = class_sign[i+1]; | ||
194 | } | ||
195 | /* | ||
196 | * append file name, we use loops and not string ops to avoid modifying | ||
197 | * class_sign which is used later for the symbol name | ||
198 | */ | ||
199 | for (j = 0; i < (PATH_MAX - 1) && file_name && j < strlen(file_name); j++, i++) | ||
200 | fn[i] = file_name[j]; | ||
201 | fn[i] = '\0'; | ||
202 | } else { | ||
203 | /* fallback case */ | ||
204 | strcpy(fn, file_name); | ||
205 | } | ||
206 | /* | 295 | /* |
207 | * write source line info record if we have it | 296 | * write source line info record if we have it |
208 | */ | 297 | */ |
209 | if (jvmti_write_debug_info(jvmti_agent, addr, fn, line_tab, nr_lines)) | 298 | if (output_debug_info) |
210 | warnx("jvmti: write_debug_info() failed"); | 299 | if (jvmti_write_debug_info(jvmti_agent, addr, nr_lines, line_tab, (const char * const *) line_file_names)) |
300 | warnx("jvmti: write_debug_info() failed"); | ||
211 | 301 | ||
212 | len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2; | 302 | len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2; |
213 | { | 303 | { |
@@ -223,6 +313,13 @@ error: | |||
223 | (*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign); | 313 | (*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign); |
224 | (*jvmti)->Deallocate(jvmti, (unsigned char *)file_name); | 314 | (*jvmti)->Deallocate(jvmti, (unsigned char *)file_name); |
225 | free(line_tab); | 315 | free(line_tab); |
316 | while (line_file_names && (nr_lines > 0)) { | ||
317 | if (line_file_names[nr_lines - 1]) { | ||
318 | free(line_file_names[nr_lines - 1]); | ||
319 | } | ||
320 | nr_lines -= 1; | ||
321 | } | ||
322 | free(line_file_names); | ||
226 | } | 323 | } |
227 | 324 | ||
228 | static void JNICALL | 325 | static void JNICALL |
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 792af7c3b74f..9316e648a880 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile | |||
@@ -11,7 +11,7 @@ ifneq ($(wildcard $(GENHDR)),) | |||
11 | endif | 11 | endif |
12 | 12 | ||
13 | CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include | 13 | CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include |
14 | LDLIBS += -lcap -lelf | 14 | LDLIBS += -lcap -lelf -lrt |
15 | 15 | ||
16 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ | 16 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ |
17 | test_align test_verifier_log test_dev_cgroup | 17 | test_align test_verifier_log test_dev_cgroup |
@@ -39,7 +39,7 @@ $(BPFOBJ): force | |||
39 | CLANG ?= clang | 39 | CLANG ?= clang |
40 | LLC ?= llc | 40 | LLC ?= llc |
41 | 41 | ||
42 | PROBE := $(shell llc -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1) | 42 | PROBE := $(shell $(LLC) -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1) |
43 | 43 | ||
44 | # Let newer LLVM versions transparently probe the kernel for availability | 44 | # Let newer LLVM versions transparently probe the kernel for availability |
45 | # of full BPF instruction set. | 45 | # of full BPF instruction set. |
diff --git a/tools/testing/selftests/bpf/test_align.c b/tools/testing/selftests/bpf/test_align.c index 8591c89c0828..471bbbdb94db 100644 --- a/tools/testing/selftests/bpf/test_align.c +++ b/tools/testing/selftests/bpf/test_align.c | |||
@@ -474,27 +474,7 @@ static struct bpf_align_test tests[] = { | |||
474 | .result = REJECT, | 474 | .result = REJECT, |
475 | .matches = { | 475 | .matches = { |
476 | {4, "R5=pkt(id=0,off=0,r=0,imm=0)"}, | 476 | {4, "R5=pkt(id=0,off=0,r=0,imm=0)"}, |
477 | /* ptr & 0x40 == either 0 or 0x40 */ | 477 | /* R5 bitwise operator &= on pointer prohibited */ |
478 | {5, "R5=inv(id=0,umax_value=64,var_off=(0x0; 0x40))"}, | ||
479 | /* ptr << 2 == unknown, (4n) */ | ||
480 | {7, "R5=inv(id=0,smax_value=9223372036854775804,umax_value=18446744073709551612,var_off=(0x0; 0xfffffffffffffffc))"}, | ||
481 | /* (4n) + 14 == (4n+2). We blow our bounds, because | ||
482 | * the add could overflow. | ||
483 | */ | ||
484 | {8, "R5=inv(id=0,var_off=(0x2; 0xfffffffffffffffc))"}, | ||
485 | /* Checked s>=0 */ | ||
486 | {10, "R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, | ||
487 | /* packet pointer + nonnegative (4n+2) */ | ||
488 | {12, "R6=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, | ||
489 | {14, "R4=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, | ||
490 | /* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine. | ||
491 | * We checked the bounds, but it might have been able | ||
492 | * to overflow if the packet pointer started in the | ||
493 | * upper half of the address space. | ||
494 | * So we did not get a 'range' on R6, and the access | ||
495 | * attempt will fail. | ||
496 | */ | ||
497 | {16, "R6=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, | ||
498 | } | 478 | } |
499 | }, | 479 | }, |
500 | { | 480 | { |
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 69427531408d..6761be18a91f 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c | |||
@@ -351,7 +351,7 @@ static void test_bpf_obj_id(void) | |||
351 | info_len != sizeof(struct bpf_map_info) || | 351 | info_len != sizeof(struct bpf_map_info) || |
352 | strcmp((char *)map_infos[i].name, expected_map_name), | 352 | strcmp((char *)map_infos[i].name, expected_map_name), |
353 | "get-map-info(fd)", | 353 | "get-map-info(fd)", |
354 | "err %d errno %d type %d(%d) info_len %u(%lu) key_size %u value_size %u max_entries %u map_flags %X name %s(%s)\n", | 354 | "err %d errno %d type %d(%d) info_len %u(%Zu) key_size %u value_size %u max_entries %u map_flags %X name %s(%s)\n", |
355 | err, errno, | 355 | err, errno, |
356 | map_infos[i].type, BPF_MAP_TYPE_ARRAY, | 356 | map_infos[i].type, BPF_MAP_TYPE_ARRAY, |
357 | info_len, sizeof(struct bpf_map_info), | 357 | info_len, sizeof(struct bpf_map_info), |
@@ -395,7 +395,7 @@ static void test_bpf_obj_id(void) | |||
395 | *(int *)prog_infos[i].map_ids != map_infos[i].id || | 395 | *(int *)prog_infos[i].map_ids != map_infos[i].id || |
396 | strcmp((char *)prog_infos[i].name, expected_prog_name), | 396 | strcmp((char *)prog_infos[i].name, expected_prog_name), |
397 | "get-prog-info(fd)", | 397 | "get-prog-info(fd)", |
398 | "err %d errno %d i %d type %d(%d) info_len %u(%lu) jit_enabled %d jited_prog_len %u xlated_prog_len %u jited_prog %d xlated_prog %d load_time %lu(%lu) uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) name %s(%s)\n", | 398 | "err %d errno %d i %d type %d(%d) info_len %u(%Zu) jit_enabled %d jited_prog_len %u xlated_prog_len %u jited_prog %d xlated_prog %d load_time %lu(%lu) uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) name %s(%s)\n", |
399 | err, errno, i, | 399 | err, errno, i, |
400 | prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER, | 400 | prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER, |
401 | info_len, sizeof(struct bpf_prog_info), | 401 | info_len, sizeof(struct bpf_prog_info), |
@@ -463,7 +463,7 @@ static void test_bpf_obj_id(void) | |||
463 | memcmp(&prog_info, &prog_infos[i], info_len) || | 463 | memcmp(&prog_info, &prog_infos[i], info_len) || |
464 | *(int *)prog_info.map_ids != saved_map_id, | 464 | *(int *)prog_info.map_ids != saved_map_id, |
465 | "get-prog-info(next_id->fd)", | 465 | "get-prog-info(next_id->fd)", |
466 | "err %d errno %d info_len %u(%lu) memcmp %d map_id %u(%u)\n", | 466 | "err %d errno %d info_len %u(%Zu) memcmp %d map_id %u(%u)\n", |
467 | err, errno, info_len, sizeof(struct bpf_prog_info), | 467 | err, errno, info_len, sizeof(struct bpf_prog_info), |
468 | memcmp(&prog_info, &prog_infos[i], info_len), | 468 | memcmp(&prog_info, &prog_infos[i], info_len), |
469 | *(int *)prog_info.map_ids, saved_map_id); | 469 | *(int *)prog_info.map_ids, saved_map_id); |
@@ -509,7 +509,7 @@ static void test_bpf_obj_id(void) | |||
509 | memcmp(&map_info, &map_infos[i], info_len) || | 509 | memcmp(&map_info, &map_infos[i], info_len) || |
510 | array_value != array_magic_value, | 510 | array_value != array_magic_value, |
511 | "check get-map-info(next_id->fd)", | 511 | "check get-map-info(next_id->fd)", |
512 | "err %d errno %d info_len %u(%lu) memcmp %d array_value %llu(%llu)\n", | 512 | "err %d errno %d info_len %u(%Zu) memcmp %d array_value %llu(%llu)\n", |
513 | err, errno, info_len, sizeof(struct bpf_map_info), | 513 | err, errno, info_len, sizeof(struct bpf_map_info), |
514 | memcmp(&map_info, &map_infos[i], info_len), | 514 | memcmp(&map_info, &map_infos[i], info_len), |
515 | array_value, array_magic_value); | 515 | array_value, array_magic_value); |
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 3c64f30cf63c..b51017404c62 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
@@ -422,9 +422,7 @@ static struct bpf_test tests[] = { | |||
422 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0), | 422 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0), |
423 | BPF_EXIT_INSN(), | 423 | BPF_EXIT_INSN(), |
424 | }, | 424 | }, |
425 | .errstr_unpriv = "R1 subtraction from stack pointer", | 425 | .errstr = "R1 subtraction from stack pointer", |
426 | .result_unpriv = REJECT, | ||
427 | .errstr = "R1 invalid mem access", | ||
428 | .result = REJECT, | 426 | .result = REJECT, |
429 | }, | 427 | }, |
430 | { | 428 | { |
@@ -606,7 +604,6 @@ static struct bpf_test tests[] = { | |||
606 | }, | 604 | }, |
607 | .errstr = "misaligned stack access", | 605 | .errstr = "misaligned stack access", |
608 | .result = REJECT, | 606 | .result = REJECT, |
609 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
610 | }, | 607 | }, |
611 | { | 608 | { |
612 | "invalid map_fd for function call", | 609 | "invalid map_fd for function call", |
@@ -1797,7 +1794,6 @@ static struct bpf_test tests[] = { | |||
1797 | }, | 1794 | }, |
1798 | .result = REJECT, | 1795 | .result = REJECT, |
1799 | .errstr = "misaligned stack access off (0x0; 0x0)+-8+2 size 8", | 1796 | .errstr = "misaligned stack access off (0x0; 0x0)+-8+2 size 8", |
1800 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1801 | }, | 1797 | }, |
1802 | { | 1798 | { |
1803 | "PTR_TO_STACK store/load - bad alignment on reg", | 1799 | "PTR_TO_STACK store/load - bad alignment on reg", |
@@ -1810,7 +1806,6 @@ static struct bpf_test tests[] = { | |||
1810 | }, | 1806 | }, |
1811 | .result = REJECT, | 1807 | .result = REJECT, |
1812 | .errstr = "misaligned stack access off (0x0; 0x0)+-10+8 size 8", | 1808 | .errstr = "misaligned stack access off (0x0; 0x0)+-10+8 size 8", |
1813 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | ||
1814 | }, | 1809 | }, |
1815 | { | 1810 | { |
1816 | "PTR_TO_STACK store/load - out of bounds low", | 1811 | "PTR_TO_STACK store/load - out of bounds low", |
@@ -1862,9 +1857,8 @@ static struct bpf_test tests[] = { | |||
1862 | BPF_MOV64_IMM(BPF_REG_0, 0), | 1857 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1863 | BPF_EXIT_INSN(), | 1858 | BPF_EXIT_INSN(), |
1864 | }, | 1859 | }, |
1865 | .result = ACCEPT, | 1860 | .result = REJECT, |
1866 | .result_unpriv = REJECT, | 1861 | .errstr = "R1 pointer += pointer", |
1867 | .errstr_unpriv = "R1 pointer += pointer", | ||
1868 | }, | 1862 | }, |
1869 | { | 1863 | { |
1870 | "unpriv: neg pointer", | 1864 | "unpriv: neg pointer", |
@@ -2592,7 +2586,8 @@ static struct bpf_test tests[] = { | |||
2592 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | 2586 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, |
2593 | offsetof(struct __sk_buff, data)), | 2587 | offsetof(struct __sk_buff, data)), |
2594 | BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_4), | 2588 | BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_4), |
2595 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), | 2589 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, |
2590 | offsetof(struct __sk_buff, len)), | ||
2596 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 49), | 2591 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 49), |
2597 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 49), | 2592 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 49), |
2598 | BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_2), | 2593 | BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_2), |
@@ -2899,7 +2894,7 @@ static struct bpf_test tests[] = { | |||
2899 | BPF_MOV64_IMM(BPF_REG_0, 0), | 2894 | BPF_MOV64_IMM(BPF_REG_0, 0), |
2900 | BPF_EXIT_INSN(), | 2895 | BPF_EXIT_INSN(), |
2901 | }, | 2896 | }, |
2902 | .errstr = "invalid access to packet", | 2897 | .errstr = "R3 pointer arithmetic on PTR_TO_PACKET_END", |
2903 | .result = REJECT, | 2898 | .result = REJECT, |
2904 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2899 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2905 | }, | 2900 | }, |
@@ -3885,9 +3880,7 @@ static struct bpf_test tests[] = { | |||
3885 | BPF_EXIT_INSN(), | 3880 | BPF_EXIT_INSN(), |
3886 | }, | 3881 | }, |
3887 | .fixup_map2 = { 3, 11 }, | 3882 | .fixup_map2 = { 3, 11 }, |
3888 | .errstr_unpriv = "R0 pointer += pointer", | 3883 | .errstr = "R0 pointer += pointer", |
3889 | .errstr = "R0 invalid mem access 'inv'", | ||
3890 | .result_unpriv = REJECT, | ||
3891 | .result = REJECT, | 3884 | .result = REJECT, |
3892 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 3885 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
3893 | }, | 3886 | }, |
@@ -3928,7 +3921,7 @@ static struct bpf_test tests[] = { | |||
3928 | BPF_EXIT_INSN(), | 3921 | BPF_EXIT_INSN(), |
3929 | }, | 3922 | }, |
3930 | .fixup_map1 = { 4 }, | 3923 | .fixup_map1 = { 4 }, |
3931 | .errstr = "R4 invalid mem access", | 3924 | .errstr = "R4 pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL", |
3932 | .result = REJECT, | 3925 | .result = REJECT, |
3933 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 3926 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
3934 | }, | 3927 | }, |
@@ -3949,7 +3942,7 @@ static struct bpf_test tests[] = { | |||
3949 | BPF_EXIT_INSN(), | 3942 | BPF_EXIT_INSN(), |
3950 | }, | 3943 | }, |
3951 | .fixup_map1 = { 4 }, | 3944 | .fixup_map1 = { 4 }, |
3952 | .errstr = "R4 invalid mem access", | 3945 | .errstr = "R4 pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL", |
3953 | .result = REJECT, | 3946 | .result = REJECT, |
3954 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 3947 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
3955 | }, | 3948 | }, |
@@ -3970,7 +3963,7 @@ static struct bpf_test tests[] = { | |||
3970 | BPF_EXIT_INSN(), | 3963 | BPF_EXIT_INSN(), |
3971 | }, | 3964 | }, |
3972 | .fixup_map1 = { 4 }, | 3965 | .fixup_map1 = { 4 }, |
3973 | .errstr = "R4 invalid mem access", | 3966 | .errstr = "R4 pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL", |
3974 | .result = REJECT, | 3967 | .result = REJECT, |
3975 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 3968 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
3976 | }, | 3969 | }, |
@@ -5195,10 +5188,8 @@ static struct bpf_test tests[] = { | |||
5195 | BPF_EXIT_INSN(), | 5188 | BPF_EXIT_INSN(), |
5196 | }, | 5189 | }, |
5197 | .fixup_map2 = { 3 }, | 5190 | .fixup_map2 = { 3 }, |
5198 | .errstr_unpriv = "R0 bitwise operator &= on pointer", | 5191 | .errstr = "R0 bitwise operator &= on pointer", |
5199 | .errstr = "invalid mem access 'inv'", | ||
5200 | .result = REJECT, | 5192 | .result = REJECT, |
5201 | .result_unpriv = REJECT, | ||
5202 | }, | 5193 | }, |
5203 | { | 5194 | { |
5204 | "map element value illegal alu op, 2", | 5195 | "map element value illegal alu op, 2", |
@@ -5214,10 +5205,8 @@ static struct bpf_test tests[] = { | |||
5214 | BPF_EXIT_INSN(), | 5205 | BPF_EXIT_INSN(), |
5215 | }, | 5206 | }, |
5216 | .fixup_map2 = { 3 }, | 5207 | .fixup_map2 = { 3 }, |
5217 | .errstr_unpriv = "R0 32-bit pointer arithmetic prohibited", | 5208 | .errstr = "R0 32-bit pointer arithmetic prohibited", |
5218 | .errstr = "invalid mem access 'inv'", | ||
5219 | .result = REJECT, | 5209 | .result = REJECT, |
5220 | .result_unpriv = REJECT, | ||
5221 | }, | 5210 | }, |
5222 | { | 5211 | { |
5223 | "map element value illegal alu op, 3", | 5212 | "map element value illegal alu op, 3", |
@@ -5233,10 +5222,8 @@ static struct bpf_test tests[] = { | |||
5233 | BPF_EXIT_INSN(), | 5222 | BPF_EXIT_INSN(), |
5234 | }, | 5223 | }, |
5235 | .fixup_map2 = { 3 }, | 5224 | .fixup_map2 = { 3 }, |
5236 | .errstr_unpriv = "R0 pointer arithmetic with /= operator", | 5225 | .errstr = "R0 pointer arithmetic with /= operator", |
5237 | .errstr = "invalid mem access 'inv'", | ||
5238 | .result = REJECT, | 5226 | .result = REJECT, |
5239 | .result_unpriv = REJECT, | ||
5240 | }, | 5227 | }, |
5241 | { | 5228 | { |
5242 | "map element value illegal alu op, 4", | 5229 | "map element value illegal alu op, 4", |
@@ -6019,8 +6006,7 @@ static struct bpf_test tests[] = { | |||
6019 | BPF_EXIT_INSN(), | 6006 | BPF_EXIT_INSN(), |
6020 | }, | 6007 | }, |
6021 | .fixup_map_in_map = { 3 }, | 6008 | .fixup_map_in_map = { 3 }, |
6022 | .errstr = "R1 type=inv expected=map_ptr", | 6009 | .errstr = "R1 pointer arithmetic on CONST_PTR_TO_MAP prohibited", |
6023 | .errstr_unpriv = "R1 pointer arithmetic on CONST_PTR_TO_MAP prohibited", | ||
6024 | .result = REJECT, | 6010 | .result = REJECT, |
6025 | }, | 6011 | }, |
6026 | { | 6012 | { |
@@ -6117,6 +6103,30 @@ static struct bpf_test tests[] = { | |||
6117 | .result = ACCEPT, | 6103 | .result = ACCEPT, |
6118 | }, | 6104 | }, |
6119 | { | 6105 | { |
6106 | "ld_abs: tests on r6 and skb data reload helper", | ||
6107 | .insns = { | ||
6108 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
6109 | BPF_LD_ABS(BPF_B, 0), | ||
6110 | BPF_LD_ABS(BPF_H, 0), | ||
6111 | BPF_LD_ABS(BPF_W, 0), | ||
6112 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_6), | ||
6113 | BPF_MOV64_IMM(BPF_REG_6, 0), | ||
6114 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), | ||
6115 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
6116 | BPF_MOV64_IMM(BPF_REG_3, 2), | ||
6117 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6118 | BPF_FUNC_skb_vlan_push), | ||
6119 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_7), | ||
6120 | BPF_LD_ABS(BPF_B, 0), | ||
6121 | BPF_LD_ABS(BPF_H, 0), | ||
6122 | BPF_LD_ABS(BPF_W, 0), | ||
6123 | BPF_MOV64_IMM(BPF_REG_0, 42), | ||
6124 | BPF_EXIT_INSN(), | ||
6125 | }, | ||
6126 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
6127 | .result = ACCEPT, | ||
6128 | }, | ||
6129 | { | ||
6120 | "ld_ind: check calling conv, r1", | 6130 | "ld_ind: check calling conv, r1", |
6121 | .insns = { | 6131 | .insns = { |
6122 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | 6132 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), |
@@ -6300,7 +6310,7 @@ static struct bpf_test tests[] = { | |||
6300 | BPF_EXIT_INSN(), | 6310 | BPF_EXIT_INSN(), |
6301 | }, | 6311 | }, |
6302 | .fixup_map1 = { 3 }, | 6312 | .fixup_map1 = { 3 }, |
6303 | .errstr = "R0 min value is negative", | 6313 | .errstr = "unbounded min value", |
6304 | .result = REJECT, | 6314 | .result = REJECT, |
6305 | }, | 6315 | }, |
6306 | { | 6316 | { |
@@ -6324,7 +6334,7 @@ static struct bpf_test tests[] = { | |||
6324 | BPF_EXIT_INSN(), | 6334 | BPF_EXIT_INSN(), |
6325 | }, | 6335 | }, |
6326 | .fixup_map1 = { 3 }, | 6336 | .fixup_map1 = { 3 }, |
6327 | .errstr = "R0 min value is negative", | 6337 | .errstr = "unbounded min value", |
6328 | .result = REJECT, | 6338 | .result = REJECT, |
6329 | }, | 6339 | }, |
6330 | { | 6340 | { |
@@ -6350,7 +6360,7 @@ static struct bpf_test tests[] = { | |||
6350 | BPF_EXIT_INSN(), | 6360 | BPF_EXIT_INSN(), |
6351 | }, | 6361 | }, |
6352 | .fixup_map1 = { 3 }, | 6362 | .fixup_map1 = { 3 }, |
6353 | .errstr = "R8 invalid mem access 'inv'", | 6363 | .errstr = "unbounded min value", |
6354 | .result = REJECT, | 6364 | .result = REJECT, |
6355 | }, | 6365 | }, |
6356 | { | 6366 | { |
@@ -6375,7 +6385,7 @@ static struct bpf_test tests[] = { | |||
6375 | BPF_EXIT_INSN(), | 6385 | BPF_EXIT_INSN(), |
6376 | }, | 6386 | }, |
6377 | .fixup_map1 = { 3 }, | 6387 | .fixup_map1 = { 3 }, |
6378 | .errstr = "R8 invalid mem access 'inv'", | 6388 | .errstr = "unbounded min value", |
6379 | .result = REJECT, | 6389 | .result = REJECT, |
6380 | }, | 6390 | }, |
6381 | { | 6391 | { |
@@ -6423,7 +6433,7 @@ static struct bpf_test tests[] = { | |||
6423 | BPF_EXIT_INSN(), | 6433 | BPF_EXIT_INSN(), |
6424 | }, | 6434 | }, |
6425 | .fixup_map1 = { 3 }, | 6435 | .fixup_map1 = { 3 }, |
6426 | .errstr = "R0 min value is negative", | 6436 | .errstr = "unbounded min value", |
6427 | .result = REJECT, | 6437 | .result = REJECT, |
6428 | }, | 6438 | }, |
6429 | { | 6439 | { |
@@ -6494,7 +6504,7 @@ static struct bpf_test tests[] = { | |||
6494 | BPF_EXIT_INSN(), | 6504 | BPF_EXIT_INSN(), |
6495 | }, | 6505 | }, |
6496 | .fixup_map1 = { 3 }, | 6506 | .fixup_map1 = { 3 }, |
6497 | .errstr = "R0 min value is negative", | 6507 | .errstr = "unbounded min value", |
6498 | .result = REJECT, | 6508 | .result = REJECT, |
6499 | }, | 6509 | }, |
6500 | { | 6510 | { |
@@ -6545,7 +6555,7 @@ static struct bpf_test tests[] = { | |||
6545 | BPF_EXIT_INSN(), | 6555 | BPF_EXIT_INSN(), |
6546 | }, | 6556 | }, |
6547 | .fixup_map1 = { 3 }, | 6557 | .fixup_map1 = { 3 }, |
6548 | .errstr = "R0 min value is negative", | 6558 | .errstr = "unbounded min value", |
6549 | .result = REJECT, | 6559 | .result = REJECT, |
6550 | }, | 6560 | }, |
6551 | { | 6561 | { |
@@ -6572,7 +6582,7 @@ static struct bpf_test tests[] = { | |||
6572 | BPF_EXIT_INSN(), | 6582 | BPF_EXIT_INSN(), |
6573 | }, | 6583 | }, |
6574 | .fixup_map1 = { 3 }, | 6584 | .fixup_map1 = { 3 }, |
6575 | .errstr = "R0 min value is negative", | 6585 | .errstr = "unbounded min value", |
6576 | .result = REJECT, | 6586 | .result = REJECT, |
6577 | }, | 6587 | }, |
6578 | { | 6588 | { |
@@ -6598,7 +6608,7 @@ static struct bpf_test tests[] = { | |||
6598 | BPF_EXIT_INSN(), | 6608 | BPF_EXIT_INSN(), |
6599 | }, | 6609 | }, |
6600 | .fixup_map1 = { 3 }, | 6610 | .fixup_map1 = { 3 }, |
6601 | .errstr = "R0 min value is negative", | 6611 | .errstr = "unbounded min value", |
6602 | .result = REJECT, | 6612 | .result = REJECT, |
6603 | }, | 6613 | }, |
6604 | { | 6614 | { |
@@ -6627,7 +6637,7 @@ static struct bpf_test tests[] = { | |||
6627 | BPF_EXIT_INSN(), | 6637 | BPF_EXIT_INSN(), |
6628 | }, | 6638 | }, |
6629 | .fixup_map1 = { 3 }, | 6639 | .fixup_map1 = { 3 }, |
6630 | .errstr = "R0 min value is negative", | 6640 | .errstr = "unbounded min value", |
6631 | .result = REJECT, | 6641 | .result = REJECT, |
6632 | }, | 6642 | }, |
6633 | { | 6643 | { |
@@ -6657,7 +6667,7 @@ static struct bpf_test tests[] = { | |||
6657 | BPF_JMP_IMM(BPF_JA, 0, 0, -7), | 6667 | BPF_JMP_IMM(BPF_JA, 0, 0, -7), |
6658 | }, | 6668 | }, |
6659 | .fixup_map1 = { 4 }, | 6669 | .fixup_map1 = { 4 }, |
6660 | .errstr = "R0 min value is negative", | 6670 | .errstr = "unbounded min value", |
6661 | .result = REJECT, | 6671 | .result = REJECT, |
6662 | }, | 6672 | }, |
6663 | { | 6673 | { |
@@ -6685,8 +6695,7 @@ static struct bpf_test tests[] = { | |||
6685 | BPF_EXIT_INSN(), | 6695 | BPF_EXIT_INSN(), |
6686 | }, | 6696 | }, |
6687 | .fixup_map1 = { 3 }, | 6697 | .fixup_map1 = { 3 }, |
6688 | .errstr_unpriv = "R0 pointer comparison prohibited", | 6698 | .errstr = "unbounded min value", |
6689 | .errstr = "R0 min value is negative", | ||
6690 | .result = REJECT, | 6699 | .result = REJECT, |
6691 | .result_unpriv = REJECT, | 6700 | .result_unpriv = REJECT, |
6692 | }, | 6701 | }, |
@@ -6742,6 +6751,462 @@ static struct bpf_test tests[] = { | |||
6742 | .result = REJECT, | 6751 | .result = REJECT, |
6743 | }, | 6752 | }, |
6744 | { | 6753 | { |
6754 | "bounds check based on zero-extended MOV", | ||
6755 | .insns = { | ||
6756 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6757 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
6758 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
6759 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
6760 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6761 | BPF_FUNC_map_lookup_elem), | ||
6762 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
6763 | /* r2 = 0x0000'0000'ffff'ffff */ | ||
6764 | BPF_MOV32_IMM(BPF_REG_2, 0xffffffff), | ||
6765 | /* r2 = 0 */ | ||
6766 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 32), | ||
6767 | /* no-op */ | ||
6768 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), | ||
6769 | /* access at offset 0 */ | ||
6770 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
6771 | /* exit */ | ||
6772 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6773 | BPF_EXIT_INSN(), | ||
6774 | }, | ||
6775 | .fixup_map1 = { 3 }, | ||
6776 | .result = ACCEPT | ||
6777 | }, | ||
6778 | { | ||
6779 | "bounds check based on sign-extended MOV. test1", | ||
6780 | .insns = { | ||
6781 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6782 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
6783 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
6784 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
6785 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6786 | BPF_FUNC_map_lookup_elem), | ||
6787 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
6788 | /* r2 = 0xffff'ffff'ffff'ffff */ | ||
6789 | BPF_MOV64_IMM(BPF_REG_2, 0xffffffff), | ||
6790 | /* r2 = 0xffff'ffff */ | ||
6791 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 32), | ||
6792 | /* r0 = <oob pointer> */ | ||
6793 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), | ||
6794 | /* access to OOB pointer */ | ||
6795 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
6796 | /* exit */ | ||
6797 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6798 | BPF_EXIT_INSN(), | ||
6799 | }, | ||
6800 | .fixup_map1 = { 3 }, | ||
6801 | .errstr = "map_value pointer and 4294967295", | ||
6802 | .result = REJECT | ||
6803 | }, | ||
6804 | { | ||
6805 | "bounds check based on sign-extended MOV. test2", | ||
6806 | .insns = { | ||
6807 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6808 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
6809 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
6810 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
6811 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6812 | BPF_FUNC_map_lookup_elem), | ||
6813 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
6814 | /* r2 = 0xffff'ffff'ffff'ffff */ | ||
6815 | BPF_MOV64_IMM(BPF_REG_2, 0xffffffff), | ||
6816 | /* r2 = 0xfff'ffff */ | ||
6817 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 36), | ||
6818 | /* r0 = <oob pointer> */ | ||
6819 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), | ||
6820 | /* access to OOB pointer */ | ||
6821 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
6822 | /* exit */ | ||
6823 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6824 | BPF_EXIT_INSN(), | ||
6825 | }, | ||
6826 | .fixup_map1 = { 3 }, | ||
6827 | .errstr = "R0 min value is outside of the array range", | ||
6828 | .result = REJECT | ||
6829 | }, | ||
6830 | { | ||
6831 | "bounds check based on reg_off + var_off + insn_off. test1", | ||
6832 | .insns = { | ||
6833 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
6834 | offsetof(struct __sk_buff, mark)), | ||
6835 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6836 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
6837 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
6838 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
6839 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6840 | BPF_FUNC_map_lookup_elem), | ||
6841 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
6842 | BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 1), | ||
6843 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, (1 << 29) - 1), | ||
6844 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_6), | ||
6845 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, (1 << 29) - 1), | ||
6846 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 3), | ||
6847 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6848 | BPF_EXIT_INSN(), | ||
6849 | }, | ||
6850 | .fixup_map1 = { 4 }, | ||
6851 | .errstr = "value_size=8 off=1073741825", | ||
6852 | .result = REJECT, | ||
6853 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
6854 | }, | ||
6855 | { | ||
6856 | "bounds check based on reg_off + var_off + insn_off. test2", | ||
6857 | .insns = { | ||
6858 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
6859 | offsetof(struct __sk_buff, mark)), | ||
6860 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6861 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
6862 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
6863 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
6864 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6865 | BPF_FUNC_map_lookup_elem), | ||
6866 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
6867 | BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 1), | ||
6868 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, (1 << 30) - 1), | ||
6869 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_6), | ||
6870 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, (1 << 29) - 1), | ||
6871 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 3), | ||
6872 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6873 | BPF_EXIT_INSN(), | ||
6874 | }, | ||
6875 | .fixup_map1 = { 4 }, | ||
6876 | .errstr = "value 1073741823", | ||
6877 | .result = REJECT, | ||
6878 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
6879 | }, | ||
6880 | { | ||
6881 | "bounds check after truncation of non-boundary-crossing range", | ||
6882 | .insns = { | ||
6883 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6884 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
6885 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
6886 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
6887 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6888 | BPF_FUNC_map_lookup_elem), | ||
6889 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9), | ||
6890 | /* r1 = [0x00, 0xff] */ | ||
6891 | BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), | ||
6892 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
6893 | /* r2 = 0x10'0000'0000 */ | ||
6894 | BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 36), | ||
6895 | /* r1 = [0x10'0000'0000, 0x10'0000'00ff] */ | ||
6896 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2), | ||
6897 | /* r1 = [0x10'7fff'ffff, 0x10'8000'00fe] */ | ||
6898 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff), | ||
6899 | /* r1 = [0x00, 0xff] */ | ||
6900 | BPF_ALU32_IMM(BPF_SUB, BPF_REG_1, 0x7fffffff), | ||
6901 | /* r1 = 0 */ | ||
6902 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8), | ||
6903 | /* no-op */ | ||
6904 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
6905 | /* access at offset 0 */ | ||
6906 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
6907 | /* exit */ | ||
6908 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6909 | BPF_EXIT_INSN(), | ||
6910 | }, | ||
6911 | .fixup_map1 = { 3 }, | ||
6912 | .result = ACCEPT | ||
6913 | }, | ||
6914 | { | ||
6915 | "bounds check after truncation of boundary-crossing range (1)", | ||
6916 | .insns = { | ||
6917 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6918 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
6919 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
6920 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
6921 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6922 | BPF_FUNC_map_lookup_elem), | ||
6923 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9), | ||
6924 | /* r1 = [0x00, 0xff] */ | ||
6925 | BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), | ||
6926 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1), | ||
6927 | /* r1 = [0xffff'ff80, 0x1'0000'007f] */ | ||
6928 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1), | ||
6929 | /* r1 = [0xffff'ff80, 0xffff'ffff] or | ||
6930 | * [0x0000'0000, 0x0000'007f] | ||
6931 | */ | ||
6932 | BPF_ALU32_IMM(BPF_ADD, BPF_REG_1, 0), | ||
6933 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1), | ||
6934 | /* r1 = [0x00, 0xff] or | ||
6935 | * [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff] | ||
6936 | */ | ||
6937 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1), | ||
6938 | /* r1 = 0 or | ||
6939 | * [0x00ff'ffff'ff00'0000, 0x00ff'ffff'ffff'ffff] | ||
6940 | */ | ||
6941 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8), | ||
6942 | /* no-op or OOB pointer computation */ | ||
6943 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
6944 | /* potentially OOB access */ | ||
6945 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
6946 | /* exit */ | ||
6947 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6948 | BPF_EXIT_INSN(), | ||
6949 | }, | ||
6950 | .fixup_map1 = { 3 }, | ||
6951 | /* not actually fully unbounded, but the bound is very high */ | ||
6952 | .errstr = "R0 unbounded memory access", | ||
6953 | .result = REJECT | ||
6954 | }, | ||
6955 | { | ||
6956 | "bounds check after truncation of boundary-crossing range (2)", | ||
6957 | .insns = { | ||
6958 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
6959 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
6960 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
6961 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
6962 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6963 | BPF_FUNC_map_lookup_elem), | ||
6964 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9), | ||
6965 | /* r1 = [0x00, 0xff] */ | ||
6966 | BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), | ||
6967 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1), | ||
6968 | /* r1 = [0xffff'ff80, 0x1'0000'007f] */ | ||
6969 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1), | ||
6970 | /* r1 = [0xffff'ff80, 0xffff'ffff] or | ||
6971 | * [0x0000'0000, 0x0000'007f] | ||
6972 | * difference to previous test: truncation via MOV32 | ||
6973 | * instead of ALU32. | ||
6974 | */ | ||
6975 | BPF_MOV32_REG(BPF_REG_1, BPF_REG_1), | ||
6976 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1), | ||
6977 | /* r1 = [0x00, 0xff] or | ||
6978 | * [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff] | ||
6979 | */ | ||
6980 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1), | ||
6981 | /* r1 = 0 or | ||
6982 | * [0x00ff'ffff'ff00'0000, 0x00ff'ffff'ffff'ffff] | ||
6983 | */ | ||
6984 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8), | ||
6985 | /* no-op or OOB pointer computation */ | ||
6986 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
6987 | /* potentially OOB access */ | ||
6988 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
6989 | /* exit */ | ||
6990 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6991 | BPF_EXIT_INSN(), | ||
6992 | }, | ||
6993 | .fixup_map1 = { 3 }, | ||
6994 | /* not actually fully unbounded, but the bound is very high */ | ||
6995 | .errstr = "R0 unbounded memory access", | ||
6996 | .result = REJECT | ||
6997 | }, | ||
6998 | { | ||
6999 | "bounds check after wrapping 32-bit addition", | ||
7000 | .insns = { | ||
7001 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
7002 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
7003 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
7004 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
7005 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
7006 | BPF_FUNC_map_lookup_elem), | ||
7007 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5), | ||
7008 | /* r1 = 0x7fff'ffff */ | ||
7009 | BPF_MOV64_IMM(BPF_REG_1, 0x7fffffff), | ||
7010 | /* r1 = 0xffff'fffe */ | ||
7011 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff), | ||
7012 | /* r1 = 0 */ | ||
7013 | BPF_ALU32_IMM(BPF_ADD, BPF_REG_1, 2), | ||
7014 | /* no-op */ | ||
7015 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
7016 | /* access at offset 0 */ | ||
7017 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
7018 | /* exit */ | ||
7019 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7020 | BPF_EXIT_INSN(), | ||
7021 | }, | ||
7022 | .fixup_map1 = { 3 }, | ||
7023 | .result = ACCEPT | ||
7024 | }, | ||
7025 | { | ||
7026 | "bounds check after shift with oversized count operand", | ||
7027 | .insns = { | ||
7028 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
7029 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
7030 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
7031 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
7032 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
7033 | BPF_FUNC_map_lookup_elem), | ||
7034 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6), | ||
7035 | BPF_MOV64_IMM(BPF_REG_2, 32), | ||
7036 | BPF_MOV64_IMM(BPF_REG_1, 1), | ||
7037 | /* r1 = (u32)1 << (u32)32 = ? */ | ||
7038 | BPF_ALU32_REG(BPF_LSH, BPF_REG_1, BPF_REG_2), | ||
7039 | /* r1 = [0x0000, 0xffff] */ | ||
7040 | BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xffff), | ||
7041 | /* computes unknown pointer, potentially OOB */ | ||
7042 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
7043 | /* potentially OOB access */ | ||
7044 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
7045 | /* exit */ | ||
7046 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7047 | BPF_EXIT_INSN(), | ||
7048 | }, | ||
7049 | .fixup_map1 = { 3 }, | ||
7050 | .errstr = "R0 max value is outside of the array range", | ||
7051 | .result = REJECT | ||
7052 | }, | ||
7053 | { | ||
7054 | "bounds check after right shift of maybe-negative number", | ||
7055 | .insns = { | ||
7056 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
7057 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
7058 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
7059 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
7060 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
7061 | BPF_FUNC_map_lookup_elem), | ||
7062 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6), | ||
7063 | /* r1 = [0x00, 0xff] */ | ||
7064 | BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), | ||
7065 | /* r1 = [-0x01, 0xfe] */ | ||
7066 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 1), | ||
7067 | /* r1 = 0 or 0xff'ffff'ffff'ffff */ | ||
7068 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8), | ||
7069 | /* r1 = 0 or 0xffff'ffff'ffff */ | ||
7070 | BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8), | ||
7071 | /* computes unknown pointer, potentially OOB */ | ||
7072 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
7073 | /* potentially OOB access */ | ||
7074 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
7075 | /* exit */ | ||
7076 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7077 | BPF_EXIT_INSN(), | ||
7078 | }, | ||
7079 | .fixup_map1 = { 3 }, | ||
7080 | .errstr = "R0 unbounded memory access", | ||
7081 | .result = REJECT | ||
7082 | }, | ||
7083 | { | ||
7084 | "bounds check map access with off+size signed 32bit overflow. test1", | ||
7085 | .insns = { | ||
7086 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
7087 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
7088 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
7089 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
7090 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
7091 | BPF_FUNC_map_lookup_elem), | ||
7092 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | ||
7093 | BPF_EXIT_INSN(), | ||
7094 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x7ffffffe), | ||
7095 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), | ||
7096 | BPF_JMP_A(0), | ||
7097 | BPF_EXIT_INSN(), | ||
7098 | }, | ||
7099 | .fixup_map1 = { 3 }, | ||
7100 | .errstr = "map_value pointer and 2147483646", | ||
7101 | .result = REJECT | ||
7102 | }, | ||
7103 | { | ||
7104 | "bounds check map access with off+size signed 32bit overflow. test2", | ||
7105 | .insns = { | ||
7106 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
7107 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
7108 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
7109 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
7110 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
7111 | BPF_FUNC_map_lookup_elem), | ||
7112 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | ||
7113 | BPF_EXIT_INSN(), | ||
7114 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x1fffffff), | ||
7115 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x1fffffff), | ||
7116 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x1fffffff), | ||
7117 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), | ||
7118 | BPF_JMP_A(0), | ||
7119 | BPF_EXIT_INSN(), | ||
7120 | }, | ||
7121 | .fixup_map1 = { 3 }, | ||
7122 | .errstr = "pointer offset 1073741822", | ||
7123 | .result = REJECT | ||
7124 | }, | ||
7125 | { | ||
7126 | "bounds check map access with off+size signed 32bit overflow. test3", | ||
7127 | .insns = { | ||
7128 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
7129 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
7130 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
7131 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
7132 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
7133 | BPF_FUNC_map_lookup_elem), | ||
7134 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | ||
7135 | BPF_EXIT_INSN(), | ||
7136 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 0x1fffffff), | ||
7137 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 0x1fffffff), | ||
7138 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 2), | ||
7139 | BPF_JMP_A(0), | ||
7140 | BPF_EXIT_INSN(), | ||
7141 | }, | ||
7142 | .fixup_map1 = { 3 }, | ||
7143 | .errstr = "pointer offset -1073741822", | ||
7144 | .result = REJECT | ||
7145 | }, | ||
7146 | { | ||
7147 | "bounds check map access with off+size signed 32bit overflow. test4", | ||
7148 | .insns = { | ||
7149 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
7150 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
7151 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
7152 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
7153 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
7154 | BPF_FUNC_map_lookup_elem), | ||
7155 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | ||
7156 | BPF_EXIT_INSN(), | ||
7157 | BPF_MOV64_IMM(BPF_REG_1, 1000000), | ||
7158 | BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, 1000000), | ||
7159 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
7160 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 2), | ||
7161 | BPF_JMP_A(0), | ||
7162 | BPF_EXIT_INSN(), | ||
7163 | }, | ||
7164 | .fixup_map1 = { 3 }, | ||
7165 | .errstr = "map_value pointer and 1000000000000", | ||
7166 | .result = REJECT | ||
7167 | }, | ||
7168 | { | ||
7169 | "pointer/scalar confusion in state equality check (way 1)", | ||
7170 | .insns = { | ||
7171 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
7172 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
7173 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
7174 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
7175 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
7176 | BPF_FUNC_map_lookup_elem), | ||
7177 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
7178 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), | ||
7179 | BPF_JMP_A(1), | ||
7180 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_10), | ||
7181 | BPF_JMP_A(0), | ||
7182 | BPF_EXIT_INSN(), | ||
7183 | }, | ||
7184 | .fixup_map1 = { 3 }, | ||
7185 | .result = ACCEPT, | ||
7186 | .result_unpriv = REJECT, | ||
7187 | .errstr_unpriv = "R0 leaks addr as return value" | ||
7188 | }, | ||
7189 | { | ||
7190 | "pointer/scalar confusion in state equality check (way 2)", | ||
7191 | .insns = { | ||
7192 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
7193 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
7194 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
7195 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
7196 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
7197 | BPF_FUNC_map_lookup_elem), | ||
7198 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), | ||
7199 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_10), | ||
7200 | BPF_JMP_A(1), | ||
7201 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), | ||
7202 | BPF_EXIT_INSN(), | ||
7203 | }, | ||
7204 | .fixup_map1 = { 3 }, | ||
7205 | .result = ACCEPT, | ||
7206 | .result_unpriv = REJECT, | ||
7207 | .errstr_unpriv = "R0 leaks addr as return value" | ||
7208 | }, | ||
7209 | { | ||
6745 | "variable-offset ctx access", | 7210 | "variable-offset ctx access", |
6746 | .insns = { | 7211 | .insns = { |
6747 | /* Get an unknown value */ | 7212 | /* Get an unknown value */ |
@@ -6783,6 +7248,71 @@ static struct bpf_test tests[] = { | |||
6783 | .prog_type = BPF_PROG_TYPE_LWT_IN, | 7248 | .prog_type = BPF_PROG_TYPE_LWT_IN, |
6784 | }, | 7249 | }, |
6785 | { | 7250 | { |
7251 | "indirect variable-offset stack access", | ||
7252 | .insns = { | ||
7253 | /* Fill the top 8 bytes of the stack */ | ||
7254 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
7255 | /* Get an unknown value */ | ||
7256 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), | ||
7257 | /* Make it small and 4-byte aligned */ | ||
7258 | BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), | ||
7259 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8), | ||
7260 | /* add it to fp. We now have either fp-4 or fp-8, but | ||
7261 | * we don't know which | ||
7262 | */ | ||
7263 | BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), | ||
7264 | /* dereference it indirectly */ | ||
7265 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
7266 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
7267 | BPF_FUNC_map_lookup_elem), | ||
7268 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7269 | BPF_EXIT_INSN(), | ||
7270 | }, | ||
7271 | .fixup_map1 = { 5 }, | ||
7272 | .errstr = "variable stack read R2", | ||
7273 | .result = REJECT, | ||
7274 | .prog_type = BPF_PROG_TYPE_LWT_IN, | ||
7275 | }, | ||
7276 | { | ||
7277 | "direct stack access with 32-bit wraparound. test1", | ||
7278 | .insns = { | ||
7279 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
7280 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff), | ||
7281 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff), | ||
7282 | BPF_MOV32_IMM(BPF_REG_0, 0), | ||
7283 | BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), | ||
7284 | BPF_EXIT_INSN() | ||
7285 | }, | ||
7286 | .errstr = "fp pointer and 2147483647", | ||
7287 | .result = REJECT | ||
7288 | }, | ||
7289 | { | ||
7290 | "direct stack access with 32-bit wraparound. test2", | ||
7291 | .insns = { | ||
7292 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
7293 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x3fffffff), | ||
7294 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x3fffffff), | ||
7295 | BPF_MOV32_IMM(BPF_REG_0, 0), | ||
7296 | BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), | ||
7297 | BPF_EXIT_INSN() | ||
7298 | }, | ||
7299 | .errstr = "fp pointer and 1073741823", | ||
7300 | .result = REJECT | ||
7301 | }, | ||
7302 | { | ||
7303 | "direct stack access with 32-bit wraparound. test3", | ||
7304 | .insns = { | ||
7305 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
7306 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x1fffffff), | ||
7307 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x1fffffff), | ||
7308 | BPF_MOV32_IMM(BPF_REG_0, 0), | ||
7309 | BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), | ||
7310 | BPF_EXIT_INSN() | ||
7311 | }, | ||
7312 | .errstr = "fp pointer offset 1073741822", | ||
7313 | .result = REJECT | ||
7314 | }, | ||
7315 | { | ||
6786 | "liveness pruning and write screening", | 7316 | "liveness pruning and write screening", |
6787 | .insns = { | 7317 | .insns = { |
6788 | /* Get an unknown value */ | 7318 | /* Get an unknown value */ |
@@ -7104,6 +7634,19 @@ static struct bpf_test tests[] = { | |||
7104 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 7634 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
7105 | }, | 7635 | }, |
7106 | { | 7636 | { |
7637 | "pkt_end - pkt_start is allowed", | ||
7638 | .insns = { | ||
7639 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
7640 | offsetof(struct __sk_buff, data_end)), | ||
7641 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7642 | offsetof(struct __sk_buff, data)), | ||
7643 | BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_2), | ||
7644 | BPF_EXIT_INSN(), | ||
7645 | }, | ||
7646 | .result = ACCEPT, | ||
7647 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
7648 | }, | ||
7649 | { | ||
7107 | "XDP pkt read, pkt_end mangling, bad access 1", | 7650 | "XDP pkt read, pkt_end mangling, bad access 1", |
7108 | .insns = { | 7651 | .insns = { |
7109 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | 7652 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, |
@@ -7118,7 +7661,7 @@ static struct bpf_test tests[] = { | |||
7118 | BPF_MOV64_IMM(BPF_REG_0, 0), | 7661 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7119 | BPF_EXIT_INSN(), | 7662 | BPF_EXIT_INSN(), |
7120 | }, | 7663 | }, |
7121 | .errstr = "R1 offset is outside of the packet", | 7664 | .errstr = "R3 pointer arithmetic on PTR_TO_PACKET_END", |
7122 | .result = REJECT, | 7665 | .result = REJECT, |
7123 | .prog_type = BPF_PROG_TYPE_XDP, | 7666 | .prog_type = BPF_PROG_TYPE_XDP, |
7124 | }, | 7667 | }, |
@@ -7137,7 +7680,7 @@ static struct bpf_test tests[] = { | |||
7137 | BPF_MOV64_IMM(BPF_REG_0, 0), | 7680 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7138 | BPF_EXIT_INSN(), | 7681 | BPF_EXIT_INSN(), |
7139 | }, | 7682 | }, |
7140 | .errstr = "R1 offset is outside of the packet", | 7683 | .errstr = "R3 pointer arithmetic on PTR_TO_PACKET_END", |
7141 | .result = REJECT, | 7684 | .result = REJECT, |
7142 | .prog_type = BPF_PROG_TYPE_XDP, | 7685 | .prog_type = BPF_PROG_TYPE_XDP, |
7143 | }, | 7686 | }, |
diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config index e57b4ac40e72..7177bea1fdfa 100644 --- a/tools/testing/selftests/net/config +++ b/tools/testing/selftests/net/config | |||
@@ -1,3 +1,4 @@ | |||
1 | CONFIG_USER_NS=y | 1 | CONFIG_USER_NS=y |
2 | CONFIG_BPF_SYSCALL=y | 2 | CONFIG_BPF_SYSCALL=y |
3 | CONFIG_TEST_BPF=m | 3 | CONFIG_TEST_BPF=m |
4 | CONFIG_NUMA=y | ||
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 939a337128db..5d4f10ac2af2 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile | |||
@@ -7,7 +7,7 @@ include ../lib.mk | |||
7 | 7 | ||
8 | TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \ | 8 | TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \ |
9 | check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test ioperm \ | 9 | check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test ioperm \ |
10 | protection_keys test_vdso | 10 | protection_keys test_vdso test_vsyscall |
11 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ | 11 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ |
12 | test_FCMOV test_FCOMI test_FISTTP \ | 12 | test_FCMOV test_FCOMI test_FISTTP \ |
13 | vdso_restorer | 13 | vdso_restorer |
diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c index 66e5ce5b91f0..1aef72df20a1 100644 --- a/tools/testing/selftests/x86/ldt_gdt.c +++ b/tools/testing/selftests/x86/ldt_gdt.c | |||
@@ -122,8 +122,7 @@ static void check_valid_segment(uint16_t index, int ldt, | |||
122 | * NB: Different Linux versions do different things with the | 122 | * NB: Different Linux versions do different things with the |
123 | * accessed bit in set_thread_area(). | 123 | * accessed bit in set_thread_area(). |
124 | */ | 124 | */ |
125 | if (ar != expected_ar && | 125 | if (ar != expected_ar && ar != (expected_ar | AR_ACCESSED)) { |
126 | (ldt || ar != (expected_ar | AR_ACCESSED))) { | ||
127 | printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n", | 126 | printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n", |
128 | (ldt ? "LDT" : "GDT"), index, ar, expected_ar); | 127 | (ldt ? "LDT" : "GDT"), index, ar, expected_ar); |
129 | nerrs++; | 128 | nerrs++; |
@@ -627,13 +626,10 @@ static void do_multicpu_tests(void) | |||
627 | static int finish_exec_test(void) | 626 | static int finish_exec_test(void) |
628 | { | 627 | { |
629 | /* | 628 | /* |
630 | * In a sensible world, this would be check_invalid_segment(0, 1); | 629 | * Older kernel versions did inherit the LDT on exec() which is |
631 | * For better or for worse, though, the LDT is inherited across exec. | 630 | * wrong because exec() starts from a clean state. |
632 | * We can probably change this safely, but for now we test it. | ||
633 | */ | 631 | */ |
634 | check_valid_segment(0, 1, | 632 | check_invalid_segment(0, 1); |
635 | AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB, | ||
636 | 42, true); | ||
637 | 633 | ||
638 | return nerrs ? 1 : 0; | 634 | return nerrs ? 1 : 0; |
639 | } | 635 | } |
diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c new file mode 100644 index 000000000000..7a744fa7b786 --- /dev/null +++ b/tools/testing/selftests/x86/test_vsyscall.c | |||
@@ -0,0 +1,500 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | |||
3 | #define _GNU_SOURCE | ||
4 | |||
5 | #include <stdio.h> | ||
6 | #include <sys/time.h> | ||
7 | #include <time.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <sys/syscall.h> | ||
10 | #include <unistd.h> | ||
11 | #include <dlfcn.h> | ||
12 | #include <string.h> | ||
13 | #include <inttypes.h> | ||
14 | #include <signal.h> | ||
15 | #include <sys/ucontext.h> | ||
16 | #include <errno.h> | ||
17 | #include <err.h> | ||
18 | #include <sched.h> | ||
19 | #include <stdbool.h> | ||
20 | #include <setjmp.h> | ||
21 | |||
22 | #ifdef __x86_64__ | ||
23 | # define VSYS(x) (x) | ||
24 | #else | ||
25 | # define VSYS(x) 0 | ||
26 | #endif | ||
27 | |||
28 | #ifndef SYS_getcpu | ||
29 | # ifdef __x86_64__ | ||
30 | # define SYS_getcpu 309 | ||
31 | # else | ||
32 | # define SYS_getcpu 318 | ||
33 | # endif | ||
34 | #endif | ||
35 | |||
36 | static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), | ||
37 | int flags) | ||
38 | { | ||
39 | struct sigaction sa; | ||
40 | memset(&sa, 0, sizeof(sa)); | ||
41 | sa.sa_sigaction = handler; | ||
42 | sa.sa_flags = SA_SIGINFO | flags; | ||
43 | sigemptyset(&sa.sa_mask); | ||
44 | if (sigaction(sig, &sa, 0)) | ||
45 | err(1, "sigaction"); | ||
46 | } | ||
47 | |||
48 | /* vsyscalls and vDSO */ | ||
49 | bool should_read_vsyscall = false; | ||
50 | |||
51 | typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz); | ||
52 | gtod_t vgtod = (gtod_t)VSYS(0xffffffffff600000); | ||
53 | gtod_t vdso_gtod; | ||
54 | |||
55 | typedef int (*vgettime_t)(clockid_t, struct timespec *); | ||
56 | vgettime_t vdso_gettime; | ||
57 | |||
58 | typedef long (*time_func_t)(time_t *t); | ||
59 | time_func_t vtime = (time_func_t)VSYS(0xffffffffff600400); | ||
60 | time_func_t vdso_time; | ||
61 | |||
62 | typedef long (*getcpu_t)(unsigned *, unsigned *, void *); | ||
63 | getcpu_t vgetcpu = (getcpu_t)VSYS(0xffffffffff600800); | ||
64 | getcpu_t vdso_getcpu; | ||
65 | |||
66 | static void init_vdso(void) | ||
67 | { | ||
68 | void *vdso = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); | ||
69 | if (!vdso) | ||
70 | vdso = dlopen("linux-gate.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); | ||
71 | if (!vdso) { | ||
72 | printf("[WARN]\tfailed to find vDSO\n"); | ||
73 | return; | ||
74 | } | ||
75 | |||
76 | vdso_gtod = (gtod_t)dlsym(vdso, "__vdso_gettimeofday"); | ||
77 | if (!vdso_gtod) | ||
78 | printf("[WARN]\tfailed to find gettimeofday in vDSO\n"); | ||
79 | |||
80 | vdso_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime"); | ||
81 | if (!vdso_gettime) | ||
82 | printf("[WARN]\tfailed to find clock_gettime in vDSO\n"); | ||
83 | |||
84 | vdso_time = (time_func_t)dlsym(vdso, "__vdso_time"); | ||
85 | if (!vdso_time) | ||
86 | printf("[WARN]\tfailed to find time in vDSO\n"); | ||
87 | |||
88 | vdso_getcpu = (getcpu_t)dlsym(vdso, "__vdso_getcpu"); | ||
89 | if (!vdso_getcpu) { | ||
90 | /* getcpu() was never wired up in the 32-bit vDSO. */ | ||
91 | printf("[%s]\tfailed to find getcpu in vDSO\n", | ||
92 | sizeof(long) == 8 ? "WARN" : "NOTE"); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | static int init_vsys(void) | ||
97 | { | ||
98 | #ifdef __x86_64__ | ||
99 | int nerrs = 0; | ||
100 | FILE *maps; | ||
101 | char line[128]; | ||
102 | bool found = false; | ||
103 | |||
104 | maps = fopen("/proc/self/maps", "r"); | ||
105 | if (!maps) { | ||
106 | printf("[WARN]\tCould not open /proc/self/maps -- assuming vsyscall is r-x\n"); | ||
107 | should_read_vsyscall = true; | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | while (fgets(line, sizeof(line), maps)) { | ||
112 | char r, x; | ||
113 | void *start, *end; | ||
114 | char name[128]; | ||
115 | if (sscanf(line, "%p-%p %c-%cp %*x %*x:%*x %*u %s", | ||
116 | &start, &end, &r, &x, name) != 5) | ||
117 | continue; | ||
118 | |||
119 | if (strcmp(name, "[vsyscall]")) | ||
120 | continue; | ||
121 | |||
122 | printf("\tvsyscall map: %s", line); | ||
123 | |||
124 | if (start != (void *)0xffffffffff600000 || | ||
125 | end != (void *)0xffffffffff601000) { | ||
126 | printf("[FAIL]\taddress range is nonsense\n"); | ||
127 | nerrs++; | ||
128 | } | ||
129 | |||
130 | printf("\tvsyscall permissions are %c-%c\n", r, x); | ||
131 | should_read_vsyscall = (r == 'r'); | ||
132 | if (x != 'x') { | ||
133 | vgtod = NULL; | ||
134 | vtime = NULL; | ||
135 | vgetcpu = NULL; | ||
136 | } | ||
137 | |||
138 | found = true; | ||
139 | break; | ||
140 | } | ||
141 | |||
142 | fclose(maps); | ||
143 | |||
144 | if (!found) { | ||
145 | printf("\tno vsyscall map in /proc/self/maps\n"); | ||
146 | should_read_vsyscall = false; | ||
147 | vgtod = NULL; | ||
148 | vtime = NULL; | ||
149 | vgetcpu = NULL; | ||
150 | } | ||
151 | |||
152 | return nerrs; | ||
153 | #else | ||
154 | return 0; | ||
155 | #endif | ||
156 | } | ||
157 | |||
158 | /* syscalls */ | ||
159 | static inline long sys_gtod(struct timeval *tv, struct timezone *tz) | ||
160 | { | ||
161 | return syscall(SYS_gettimeofday, tv, tz); | ||
162 | } | ||
163 | |||
164 | static inline int sys_clock_gettime(clockid_t id, struct timespec *ts) | ||
165 | { | ||
166 | return syscall(SYS_clock_gettime, id, ts); | ||
167 | } | ||
168 | |||
169 | static inline long sys_time(time_t *t) | ||
170 | { | ||
171 | return syscall(SYS_time, t); | ||
172 | } | ||
173 | |||
174 | static inline long sys_getcpu(unsigned * cpu, unsigned * node, | ||
175 | void* cache) | ||
176 | { | ||
177 | return syscall(SYS_getcpu, cpu, node, cache); | ||
178 | } | ||
179 | |||
180 | static jmp_buf jmpbuf; | ||
181 | |||
182 | static void sigsegv(int sig, siginfo_t *info, void *ctx_void) | ||
183 | { | ||
184 | siglongjmp(jmpbuf, 1); | ||
185 | } | ||
186 | |||
187 | static double tv_diff(const struct timeval *a, const struct timeval *b) | ||
188 | { | ||
189 | return (double)(a->tv_sec - b->tv_sec) + | ||
190 | (double)((int)a->tv_usec - (int)b->tv_usec) * 1e-6; | ||
191 | } | ||
192 | |||
193 | static int check_gtod(const struct timeval *tv_sys1, | ||
194 | const struct timeval *tv_sys2, | ||
195 | const struct timezone *tz_sys, | ||
196 | const char *which, | ||
197 | const struct timeval *tv_other, | ||
198 | const struct timezone *tz_other) | ||
199 | { | ||
200 | int nerrs = 0; | ||
201 | double d1, d2; | ||
202 | |||
203 | if (tz_other && (tz_sys->tz_minuteswest != tz_other->tz_minuteswest || tz_sys->tz_dsttime != tz_other->tz_dsttime)) { | ||
204 | printf("[FAIL] %s tz mismatch\n", which); | ||
205 | nerrs++; | ||
206 | } | ||
207 | |||
208 | d1 = tv_diff(tv_other, tv_sys1); | ||
209 | d2 = tv_diff(tv_sys2, tv_other); | ||
210 | printf("\t%s time offsets: %lf %lf\n", which, d1, d2); | ||
211 | |||
212 | if (d1 < 0 || d2 < 0) { | ||
213 | printf("[FAIL]\t%s time was inconsistent with the syscall\n", which); | ||
214 | nerrs++; | ||
215 | } else { | ||
216 | printf("[OK]\t%s gettimeofday()'s timeval was okay\n", which); | ||
217 | } | ||
218 | |||
219 | return nerrs; | ||
220 | } | ||
221 | |||
222 | static int test_gtod(void) | ||
223 | { | ||
224 | struct timeval tv_sys1, tv_sys2, tv_vdso, tv_vsys; | ||
225 | struct timezone tz_sys, tz_vdso, tz_vsys; | ||
226 | long ret_vdso = -1; | ||
227 | long ret_vsys = -1; | ||
228 | int nerrs = 0; | ||
229 | |||
230 | printf("[RUN]\ttest gettimeofday()\n"); | ||
231 | |||
232 | if (sys_gtod(&tv_sys1, &tz_sys) != 0) | ||
233 | err(1, "syscall gettimeofday"); | ||
234 | if (vdso_gtod) | ||
235 | ret_vdso = vdso_gtod(&tv_vdso, &tz_vdso); | ||
236 | if (vgtod) | ||
237 | ret_vsys = vgtod(&tv_vsys, &tz_vsys); | ||
238 | if (sys_gtod(&tv_sys2, &tz_sys) != 0) | ||
239 | err(1, "syscall gettimeofday"); | ||
240 | |||
241 | if (vdso_gtod) { | ||
242 | if (ret_vdso == 0) { | ||
243 | nerrs += check_gtod(&tv_sys1, &tv_sys2, &tz_sys, "vDSO", &tv_vdso, &tz_vdso); | ||
244 | } else { | ||
245 | printf("[FAIL]\tvDSO gettimeofday() failed: %ld\n", ret_vdso); | ||
246 | nerrs++; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | if (vgtod) { | ||
251 | if (ret_vsys == 0) { | ||
252 | nerrs += check_gtod(&tv_sys1, &tv_sys2, &tz_sys, "vsyscall", &tv_vsys, &tz_vsys); | ||
253 | } else { | ||
254 | printf("[FAIL]\tvsys gettimeofday() failed: %ld\n", ret_vsys); | ||
255 | nerrs++; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | return nerrs; | ||
260 | } | ||
261 | |||
262 | static int test_time(void) { | ||
263 | int nerrs = 0; | ||
264 | |||
265 | printf("[RUN]\ttest time()\n"); | ||
266 | long t_sys1, t_sys2, t_vdso = 0, t_vsys = 0; | ||
267 | long t2_sys1 = -1, t2_sys2 = -1, t2_vdso = -1, t2_vsys = -1; | ||
268 | t_sys1 = sys_time(&t2_sys1); | ||
269 | if (vdso_time) | ||
270 | t_vdso = vdso_time(&t2_vdso); | ||
271 | if (vtime) | ||
272 | t_vsys = vtime(&t2_vsys); | ||
273 | t_sys2 = sys_time(&t2_sys2); | ||
274 | if (t_sys1 < 0 || t_sys1 != t2_sys1 || t_sys2 < 0 || t_sys2 != t2_sys2) { | ||
275 | printf("[FAIL]\tsyscall failed (ret1:%ld output1:%ld ret2:%ld output2:%ld)\n", t_sys1, t2_sys1, t_sys2, t2_sys2); | ||
276 | nerrs++; | ||
277 | return nerrs; | ||
278 | } | ||
279 | |||
280 | if (vdso_time) { | ||
281 | if (t_vdso < 0 || t_vdso != t2_vdso) { | ||
282 | printf("[FAIL]\tvDSO failed (ret:%ld output:%ld)\n", t_vdso, t2_vdso); | ||
283 | nerrs++; | ||
284 | } else if (t_vdso < t_sys1 || t_vdso > t_sys2) { | ||
285 | printf("[FAIL]\tvDSO returned the wrong time (%ld %ld %ld)\n", t_sys1, t_vdso, t_sys2); | ||
286 | nerrs++; | ||
287 | } else { | ||
288 | printf("[OK]\tvDSO time() is okay\n"); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | if (vtime) { | ||
293 | if (t_vsys < 0 || t_vsys != t2_vsys) { | ||
294 | printf("[FAIL]\tvsyscall failed (ret:%ld output:%ld)\n", t_vsys, t2_vsys); | ||
295 | nerrs++; | ||
296 | } else if (t_vsys < t_sys1 || t_vsys > t_sys2) { | ||
297 | printf("[FAIL]\tvsyscall returned the wrong time (%ld %ld %ld)\n", t_sys1, t_vsys, t_sys2); | ||
298 | nerrs++; | ||
299 | } else { | ||
300 | printf("[OK]\tvsyscall time() is okay\n"); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | return nerrs; | ||
305 | } | ||
306 | |||
307 | static int test_getcpu(int cpu) | ||
308 | { | ||
309 | int nerrs = 0; | ||
310 | long ret_sys, ret_vdso = -1, ret_vsys = -1; | ||
311 | |||
312 | printf("[RUN]\tgetcpu() on CPU %d\n", cpu); | ||
313 | |||
314 | cpu_set_t cpuset; | ||
315 | CPU_ZERO(&cpuset); | ||
316 | CPU_SET(cpu, &cpuset); | ||
317 | if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) { | ||
318 | printf("[SKIP]\tfailed to force CPU %d\n", cpu); | ||
319 | return nerrs; | ||
320 | } | ||
321 | |||
322 | unsigned cpu_sys, cpu_vdso, cpu_vsys, node_sys, node_vdso, node_vsys; | ||
323 | unsigned node = 0; | ||
324 | bool have_node = false; | ||
325 | ret_sys = sys_getcpu(&cpu_sys, &node_sys, 0); | ||
326 | if (vdso_getcpu) | ||
327 | ret_vdso = vdso_getcpu(&cpu_vdso, &node_vdso, 0); | ||
328 | if (vgetcpu) | ||
329 | ret_vsys = vgetcpu(&cpu_vsys, &node_vsys, 0); | ||
330 | |||
331 | if (ret_sys == 0) { | ||
332 | if (cpu_sys != cpu) { | ||
333 | printf("[FAIL]\tsyscall reported CPU %hu but should be %d\n", cpu_sys, cpu); | ||
334 | nerrs++; | ||
335 | } | ||
336 | |||
337 | have_node = true; | ||
338 | node = node_sys; | ||
339 | } | ||
340 | |||
341 | if (vdso_getcpu) { | ||
342 | if (ret_vdso) { | ||
343 | printf("[FAIL]\tvDSO getcpu() failed\n"); | ||
344 | nerrs++; | ||
345 | } else { | ||
346 | if (!have_node) { | ||
347 | have_node = true; | ||
348 | node = node_vdso; | ||
349 | } | ||
350 | |||
351 | if (cpu_vdso != cpu) { | ||
352 | printf("[FAIL]\tvDSO reported CPU %hu but should be %d\n", cpu_vdso, cpu); | ||
353 | nerrs++; | ||
354 | } else { | ||
355 | printf("[OK]\tvDSO reported correct CPU\n"); | ||
356 | } | ||
357 | |||
358 | if (node_vdso != node) { | ||
359 | printf("[FAIL]\tvDSO reported node %hu but should be %hu\n", node_vdso, node); | ||
360 | nerrs++; | ||
361 | } else { | ||
362 | printf("[OK]\tvDSO reported correct node\n"); | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | |||
367 | if (vgetcpu) { | ||
368 | if (ret_vsys) { | ||
369 | printf("[FAIL]\tvsyscall getcpu() failed\n"); | ||
370 | nerrs++; | ||
371 | } else { | ||
372 | if (!have_node) { | ||
373 | have_node = true; | ||
374 | node = node_vsys; | ||
375 | } | ||
376 | |||
377 | if (cpu_vsys != cpu) { | ||
378 | printf("[FAIL]\tvsyscall reported CPU %hu but should be %d\n", cpu_vsys, cpu); | ||
379 | nerrs++; | ||
380 | } else { | ||
381 | printf("[OK]\tvsyscall reported correct CPU\n"); | ||
382 | } | ||
383 | |||
384 | if (node_vsys != node) { | ||
385 | printf("[FAIL]\tvsyscall reported node %hu but should be %hu\n", node_vsys, node); | ||
386 | nerrs++; | ||
387 | } else { | ||
388 | printf("[OK]\tvsyscall reported correct node\n"); | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | |||
393 | return nerrs; | ||
394 | } | ||
395 | |||
396 | static int test_vsys_r(void) | ||
397 | { | ||
398 | #ifdef __x86_64__ | ||
399 | printf("[RUN]\tChecking read access to the vsyscall page\n"); | ||
400 | bool can_read; | ||
401 | if (sigsetjmp(jmpbuf, 1) == 0) { | ||
402 | *(volatile int *)0xffffffffff600000; | ||
403 | can_read = true; | ||
404 | } else { | ||
405 | can_read = false; | ||
406 | } | ||
407 | |||
408 | if (can_read && !should_read_vsyscall) { | ||
409 | printf("[FAIL]\tWe have read access, but we shouldn't\n"); | ||
410 | return 1; | ||
411 | } else if (!can_read && should_read_vsyscall) { | ||
412 | printf("[FAIL]\tWe don't have read access, but we should\n"); | ||
413 | return 1; | ||
414 | } else { | ||
415 | printf("[OK]\tgot expected result\n"); | ||
416 | } | ||
417 | #endif | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | |||
423 | #ifdef __x86_64__ | ||
424 | #define X86_EFLAGS_TF (1UL << 8) | ||
425 | static volatile sig_atomic_t num_vsyscall_traps; | ||
426 | |||
427 | static unsigned long get_eflags(void) | ||
428 | { | ||
429 | unsigned long eflags; | ||
430 | asm volatile ("pushfq\n\tpopq %0" : "=rm" (eflags)); | ||
431 | return eflags; | ||
432 | } | ||
433 | |||
434 | static void set_eflags(unsigned long eflags) | ||
435 | { | ||
436 | asm volatile ("pushq %0\n\tpopfq" : : "rm" (eflags) : "flags"); | ||
437 | } | ||
438 | |||
439 | static void sigtrap(int sig, siginfo_t *info, void *ctx_void) | ||
440 | { | ||
441 | ucontext_t *ctx = (ucontext_t *)ctx_void; | ||
442 | unsigned long ip = ctx->uc_mcontext.gregs[REG_RIP]; | ||
443 | |||
444 | if (((ip ^ 0xffffffffff600000UL) & ~0xfffUL) == 0) | ||
445 | num_vsyscall_traps++; | ||
446 | } | ||
447 | |||
448 | static int test_native_vsyscall(void) | ||
449 | { | ||
450 | time_t tmp; | ||
451 | bool is_native; | ||
452 | |||
453 | if (!vtime) | ||
454 | return 0; | ||
455 | |||
456 | printf("[RUN]\tchecking for native vsyscall\n"); | ||
457 | sethandler(SIGTRAP, sigtrap, 0); | ||
458 | set_eflags(get_eflags() | X86_EFLAGS_TF); | ||
459 | vtime(&tmp); | ||
460 | set_eflags(get_eflags() & ~X86_EFLAGS_TF); | ||
461 | |||
462 | /* | ||
463 | * If vsyscalls are emulated, we expect a single trap in the | ||
464 | * vsyscall page -- the call instruction will trap with RIP | ||
465 | * pointing to the entry point before emulation takes over. | ||
466 | * In native mode, we expect two traps, since whatever code | ||
467 | * the vsyscall page contains will be more than just a ret | ||
468 | * instruction. | ||
469 | */ | ||
470 | is_native = (num_vsyscall_traps > 1); | ||
471 | |||
472 | printf("\tvsyscalls are %s (%d instructions in vsyscall page)\n", | ||
473 | (is_native ? "native" : "emulated"), | ||
474 | (int)num_vsyscall_traps); | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | #endif | ||
479 | |||
480 | int main(int argc, char **argv) | ||
481 | { | ||
482 | int nerrs = 0; | ||
483 | |||
484 | init_vdso(); | ||
485 | nerrs += init_vsys(); | ||
486 | |||
487 | nerrs += test_gtod(); | ||
488 | nerrs += test_time(); | ||
489 | nerrs += test_getcpu(0); | ||
490 | nerrs += test_getcpu(1); | ||
491 | |||
492 | sethandler(SIGSEGV, sigsegv, 0); | ||
493 | nerrs += test_vsys_r(); | ||
494 | |||
495 | #ifdef __x86_64__ | ||
496 | nerrs += test_native_vsyscall(); | ||
497 | #endif | ||
498 | |||
499 | return nerrs ? 1 : 0; | ||
500 | } | ||
diff --git a/tools/usb/usbip/src/utils.c b/tools/usb/usbip/src/utils.c index 2b3d6d235015..3d7b42e77299 100644 --- a/tools/usb/usbip/src/utils.c +++ b/tools/usb/usbip/src/utils.c | |||
@@ -30,6 +30,7 @@ int modify_match_busid(char *busid, int add) | |||
30 | char command[SYSFS_BUS_ID_SIZE + 4]; | 30 | char command[SYSFS_BUS_ID_SIZE + 4]; |
31 | char match_busid_attr_path[SYSFS_PATH_MAX]; | 31 | char match_busid_attr_path[SYSFS_PATH_MAX]; |
32 | int rc; | 32 | int rc; |
33 | int cmd_size; | ||
33 | 34 | ||
34 | snprintf(match_busid_attr_path, sizeof(match_busid_attr_path), | 35 | snprintf(match_busid_attr_path, sizeof(match_busid_attr_path), |
35 | "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME, | 36 | "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME, |
@@ -37,12 +38,14 @@ int modify_match_busid(char *busid, int add) | |||
37 | attr_name); | 38 | attr_name); |
38 | 39 | ||
39 | if (add) | 40 | if (add) |
40 | snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid); | 41 | cmd_size = snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", |
42 | busid); | ||
41 | else | 43 | else |
42 | snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid); | 44 | cmd_size = snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", |
45 | busid); | ||
43 | 46 | ||
44 | rc = write_sysfs_attribute(match_busid_attr_path, command, | 47 | rc = write_sysfs_attribute(match_busid_attr_path, command, |
45 | sizeof(command)); | 48 | cmd_size); |
46 | if (rc < 0) { | 49 | if (rc < 0) { |
47 | dbg("failed to write match_busid: %s", strerror(errno)); | 50 | dbg("failed to write match_busid: %s", strerror(errno)); |
48 | return -1; | 51 | return -1; |