1
2
3
4
5
6#include <string.h>
7#include <stdlib.h>
8
9#include "builtin.h"
10#include "cfi.h"
11#include "arch.h"
12#include "check.h"
13#include "special.h"
14#include "warn.h"
15#include "arch_elf.h"
16
17#include <linux/objtool.h>
18#include <linux/hashtable.h>
19#include <linux/kernel.h>
20#include <linux/static_call_types.h>
21
22#define FAKE_JUMP_OFFSET -1
23
24struct alternative {
25 struct list_head list;
26 struct instruction *insn;
27 bool skip_orig;
28};
29
30struct cfi_init_state initial_func_cfi;
31
32struct instruction *find_insn(struct objtool_file *file,
33 struct section *sec, unsigned long offset)
34{
35 struct instruction *insn;
36
37 hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) {
38 if (insn->sec == sec && insn->offset == offset)
39 return insn;
40 }
41
42 return NULL;
43}
44
45static struct instruction *next_insn_same_sec(struct objtool_file *file,
46 struct instruction *insn)
47{
48 struct instruction *next = list_next_entry(insn, list);
49
50 if (!next || &next->list == &file->insn_list || next->sec != insn->sec)
51 return NULL;
52
53 return next;
54}
55
56static struct instruction *next_insn_same_func(struct objtool_file *file,
57 struct instruction *insn)
58{
59 struct instruction *next = list_next_entry(insn, list);
60 struct symbol *func = insn->func;
61
62 if (!func)
63 return NULL;
64
65 if (&next->list != &file->insn_list && next->func == func)
66 return next;
67
68
69 if (func == func->cfunc)
70 return NULL;
71
72
73 return find_insn(file, func->cfunc->sec, func->cfunc->offset);
74}
75
76static struct instruction *prev_insn_same_sym(struct objtool_file *file,
77 struct instruction *insn)
78{
79 struct instruction *prev = list_prev_entry(insn, list);
80
81 if (&prev->list != &file->insn_list && prev->func == insn->func)
82 return prev;
83
84 return NULL;
85}
86
87#define func_for_each_insn(file, func, insn) \
88 for (insn = find_insn(file, func->sec, func->offset); \
89 insn; \
90 insn = next_insn_same_func(file, insn))
91
92#define sym_for_each_insn(file, sym, insn) \
93 for (insn = find_insn(file, sym->sec, sym->offset); \
94 insn && &insn->list != &file->insn_list && \
95 insn->sec == sym->sec && \
96 insn->offset < sym->offset + sym->len; \
97 insn = list_next_entry(insn, list))
98
99#define sym_for_each_insn_continue_reverse(file, sym, insn) \
100 for (insn = list_prev_entry(insn, list); \
101 &insn->list != &file->insn_list && \
102 insn->sec == sym->sec && insn->offset >= sym->offset; \
103 insn = list_prev_entry(insn, list))
104
105#define sec_for_each_insn_from(file, insn) \
106 for (; insn; insn = next_insn_same_sec(file, insn))
107
108#define sec_for_each_insn_continue(file, insn) \
109 for (insn = next_insn_same_sec(file, insn); insn; \
110 insn = next_insn_same_sec(file, insn))
111
112static bool is_sibling_call(struct instruction *insn)
113{
114
115 if (insn->type == INSN_JUMP_DYNAMIC)
116 return list_empty(&insn->alts);
117
118 if (!is_static_jump(insn))
119 return false;
120
121
122 return !!insn->call_dest;
123}
124
125
126
127
128
129
130
131
132
133
134static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
135 int recursion)
136{
137 int i;
138 struct instruction *insn;
139 bool empty = true;
140
141
142
143
144
145 static const char * const global_noreturns[] = {
146 "__stack_chk_fail",
147 "panic",
148 "do_exit",
149 "do_task_dead",
150 "__module_put_and_exit",
151 "complete_and_exit",
152 "__reiserfs_panic",
153 "lbug_with_loc",
154 "fortify_panic",
155 "usercopy_abort",
156 "machine_real_restart",
157 "rewind_stack_do_exit",
158 "kunit_try_catch_throw",
159 };
160
161 if (!func)
162 return false;
163
164 if (func->bind == STB_WEAK)
165 return false;
166
167 if (func->bind == STB_GLOBAL)
168 for (i = 0; i < ARRAY_SIZE(global_noreturns); i++)
169 if (!strcmp(func->name, global_noreturns[i]))
170 return true;
171
172 if (!func->len)
173 return false;
174
175 insn = find_insn(file, func->sec, func->offset);
176 if (!insn->func)
177 return false;
178
179 func_for_each_insn(file, func, insn) {
180 empty = false;
181
182 if (insn->type == INSN_RETURN)
183 return false;
184 }
185
186 if (empty)
187 return false;
188
189
190
191
192
193
194 func_for_each_insn(file, func, insn) {
195 if (is_sibling_call(insn)) {
196 struct instruction *dest = insn->jump_dest;
197
198 if (!dest)
199
200 return false;
201
202
203 if (recursion == 5) {
204
205
206
207
208
209 return false;
210 }
211
212 return __dead_end_function(file, dest->func, recursion+1);
213 }
214 }
215
216 return true;
217}
218
219static bool dead_end_function(struct objtool_file *file, struct symbol *func)
220{
221 return __dead_end_function(file, func, 0);
222}
223
224static void init_cfi_state(struct cfi_state *cfi)
225{
226 int i;
227
228 for (i = 0; i < CFI_NUM_REGS; i++) {
229 cfi->regs[i].base = CFI_UNDEFINED;
230 cfi->vals[i].base = CFI_UNDEFINED;
231 }
232 cfi->cfa.base = CFI_UNDEFINED;
233 cfi->drap_reg = CFI_UNDEFINED;
234 cfi->drap_offset = -1;
235}
236
237static void init_insn_state(struct insn_state *state, struct section *sec)
238{
239 memset(state, 0, sizeof(*state));
240 init_cfi_state(&state->cfi);
241
242
243
244
245
246
247 if (vmlinux && sec)
248 state->noinstr = sec->noinstr;
249}
250
251
252
253
254
255static int decode_instructions(struct objtool_file *file)
256{
257 struct section *sec;
258 struct symbol *func;
259 unsigned long offset;
260 struct instruction *insn;
261 unsigned long nr_insns = 0;
262 int ret;
263
264 for_each_sec(file, sec) {
265
266 if (!(sec->sh.sh_flags & SHF_EXECINSTR))
267 continue;
268
269 if (strcmp(sec->name, ".altinstr_replacement") &&
270 strcmp(sec->name, ".altinstr_aux") &&
271 strncmp(sec->name, ".discard.", 9))
272 sec->text = true;
273
274 if (!strcmp(sec->name, ".noinstr.text") ||
275 !strcmp(sec->name, ".entry.text"))
276 sec->noinstr = true;
277
278 for (offset = 0; offset < sec->len; offset += insn->len) {
279 insn = malloc(sizeof(*insn));
280 if (!insn) {
281 WARN("malloc failed");
282 return -1;
283 }
284 memset(insn, 0, sizeof(*insn));
285 INIT_LIST_HEAD(&insn->alts);
286 INIT_LIST_HEAD(&insn->stack_ops);
287 init_cfi_state(&insn->cfi);
288
289 insn->sec = sec;
290 insn->offset = offset;
291
292 ret = arch_decode_instruction(file->elf, sec, offset,
293 sec->len - offset,
294 &insn->len, &insn->type,
295 &insn->immediate,
296 &insn->stack_ops);
297 if (ret)
298 goto err;
299
300 hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset));
301 list_add_tail(&insn->list, &file->insn_list);
302 nr_insns++;
303 }
304
305 list_for_each_entry(func, &sec->symbol_list, list) {
306 if (func->type != STT_FUNC || func->alias != func)
307 continue;
308
309 if (!find_insn(file, sec, func->offset)) {
310 WARN("%s(): can't find starting instruction",
311 func->name);
312 return -1;
313 }
314
315 sym_for_each_insn(file, func, insn)
316 insn->func = func;
317 }
318 }
319
320 if (stats)
321 printf("nr_insns: %lu\n", nr_insns);
322
323 return 0;
324
325err:
326 free(insn);
327 return ret;
328}
329
330static struct instruction *find_last_insn(struct objtool_file *file,
331 struct section *sec)
332{
333 struct instruction *insn = NULL;
334 unsigned int offset;
335 unsigned int end = (sec->len > 10) ? sec->len - 10 : 0;
336
337 for (offset = sec->len - 1; offset >= end && !insn; offset--)
338 insn = find_insn(file, sec, offset);
339
340 return insn;
341}
342
343
344
345
346static int add_dead_ends(struct objtool_file *file)
347{
348 struct section *sec;
349 struct reloc *reloc;
350 struct instruction *insn;
351
352
353
354
355
356 for_each_insn(file, insn)
357 if (insn->type == INSN_BUG)
358 insn->dead_end = true;
359
360
361
362
363 sec = find_section_by_name(file->elf, ".rela.discard.unreachable");
364 if (!sec)
365 goto reachable;
366
367 list_for_each_entry(reloc, &sec->reloc_list, list) {
368 if (reloc->sym->type != STT_SECTION) {
369 WARN("unexpected relocation symbol type in %s", sec->name);
370 return -1;
371 }
372 insn = find_insn(file, reloc->sym->sec, reloc->addend);
373 if (insn)
374 insn = list_prev_entry(insn, list);
375 else if (reloc->addend == reloc->sym->sec->len) {
376 insn = find_last_insn(file, reloc->sym->sec);
377 if (!insn) {
378 WARN("can't find unreachable insn at %s+0x%x",
379 reloc->sym->sec->name, reloc->addend);
380 return -1;
381 }
382 } else {
383 WARN("can't find unreachable insn at %s+0x%x",
384 reloc->sym->sec->name, reloc->addend);
385 return -1;
386 }
387
388 insn->dead_end = true;
389 }
390
391reachable:
392
393
394
395
396
397
398 sec = find_section_by_name(file->elf, ".rela.discard.reachable");
399 if (!sec)
400 return 0;
401
402 list_for_each_entry(reloc, &sec->reloc_list, list) {
403 if (reloc->sym->type != STT_SECTION) {
404 WARN("unexpected relocation symbol type in %s", sec->name);
405 return -1;
406 }
407 insn = find_insn(file, reloc->sym->sec, reloc->addend);
408 if (insn)
409 insn = list_prev_entry(insn, list);
410 else if (reloc->addend == reloc->sym->sec->len) {
411 insn = find_last_insn(file, reloc->sym->sec);
412 if (!insn) {
413 WARN("can't find reachable insn at %s+0x%x",
414 reloc->sym->sec->name, reloc->addend);
415 return -1;
416 }
417 } else {
418 WARN("can't find reachable insn at %s+0x%x",
419 reloc->sym->sec->name, reloc->addend);
420 return -1;
421 }
422
423 insn->dead_end = false;
424 }
425
426 return 0;
427}
428
429static int create_static_call_sections(struct objtool_file *file)
430{
431 struct section *sec, *reloc_sec;
432 struct reloc *reloc;
433 struct static_call_site *site;
434 struct instruction *insn;
435 struct symbol *key_sym;
436 char *key_name, *tmp;
437 int idx;
438
439 sec = find_section_by_name(file->elf, ".static_call_sites");
440 if (sec) {
441 INIT_LIST_HEAD(&file->static_call_list);
442 WARN("file already has .static_call_sites section, skipping");
443 return 0;
444 }
445
446 if (list_empty(&file->static_call_list))
447 return 0;
448
449 idx = 0;
450 list_for_each_entry(insn, &file->static_call_list, static_call_node)
451 idx++;
452
453 sec = elf_create_section(file->elf, ".static_call_sites", SHF_WRITE,
454 sizeof(struct static_call_site), idx);
455 if (!sec)
456 return -1;
457
458 reloc_sec = elf_create_reloc_section(file->elf, sec, SHT_RELA);
459 if (!reloc_sec)
460 return -1;
461
462 idx = 0;
463 list_for_each_entry(insn, &file->static_call_list, static_call_node) {
464
465 site = (struct static_call_site *)sec->data->d_buf + idx;
466 memset(site, 0, sizeof(struct static_call_site));
467
468
469 reloc = malloc(sizeof(*reloc));
470 if (!reloc) {
471 perror("malloc");
472 return -1;
473 }
474 memset(reloc, 0, sizeof(*reloc));
475 reloc->sym = insn->sec->sym;
476 reloc->addend = insn->offset;
477 reloc->type = R_X86_64_PC32;
478 reloc->offset = idx * sizeof(struct static_call_site);
479 reloc->sec = reloc_sec;
480 elf_add_reloc(file->elf, reloc);
481
482
483 key_name = strdup(insn->call_dest->name);
484 if (!key_name) {
485 perror("strdup");
486 return -1;
487 }
488 if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR,
489 STATIC_CALL_TRAMP_PREFIX_LEN)) {
490 WARN("static_call: trampoline name malformed: %s", key_name);
491 return -1;
492 }
493 tmp = key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX_LEN;
494 memcpy(tmp, STATIC_CALL_KEY_PREFIX_STR, STATIC_CALL_KEY_PREFIX_LEN);
495
496 key_sym = find_symbol_by_name(file->elf, tmp);
497 if (!key_sym) {
498 WARN("static_call: can't find static_call_key symbol: %s", tmp);
499 return -1;
500 }
501 free(key_name);
502
503
504 reloc = malloc(sizeof(*reloc));
505 if (!reloc) {
506 perror("malloc");
507 return -1;
508 }
509 memset(reloc, 0, sizeof(*reloc));
510 reloc->sym = key_sym;
511 reloc->addend = is_sibling_call(insn) ? STATIC_CALL_SITE_TAIL : 0;
512 reloc->type = R_X86_64_PC32;
513 reloc->offset = idx * sizeof(struct static_call_site) + 4;
514 reloc->sec = reloc_sec;
515 elf_add_reloc(file->elf, reloc);
516
517 idx++;
518 }
519
520 if (elf_rebuild_reloc_section(file->elf, reloc_sec))
521 return -1;
522
523 return 0;
524}
525
526
527
528
529static void add_ignores(struct objtool_file *file)
530{
531 struct instruction *insn;
532 struct section *sec;
533 struct symbol *func;
534 struct reloc *reloc;
535
536 sec = find_section_by_name(file->elf, ".rela.discard.func_stack_frame_non_standard");
537 if (!sec)
538 return;
539
540 list_for_each_entry(reloc, &sec->reloc_list, list) {
541 switch (reloc->sym->type) {
542 case STT_FUNC:
543 func = reloc->sym;
544 break;
545
546 case STT_SECTION:
547 func = find_func_by_offset(reloc->sym->sec, reloc->addend);
548 if (!func)
549 continue;
550 break;
551
552 default:
553 WARN("unexpected relocation symbol type in %s: %d", sec->name, reloc->sym->type);
554 continue;
555 }
556
557 func_for_each_insn(file, func, insn)
558 insn->ignore = true;
559 }
560}
561
562
563
564
565
566
567
568
569static const char *uaccess_safe_builtin[] = {
570
571 "kasan_report",
572 "check_memory_region",
573
574 "__asan_loadN_noabort",
575 "__asan_load1_noabort",
576 "__asan_load2_noabort",
577 "__asan_load4_noabort",
578 "__asan_load8_noabort",
579 "__asan_load16_noabort",
580 "__asan_storeN_noabort",
581 "__asan_store1_noabort",
582 "__asan_store2_noabort",
583 "__asan_store4_noabort",
584 "__asan_store8_noabort",
585 "__asan_store16_noabort",
586 "__kasan_check_read",
587 "__kasan_check_write",
588
589 "__asan_report_load_n_noabort",
590 "__asan_report_load1_noabort",
591 "__asan_report_load2_noabort",
592 "__asan_report_load4_noabort",
593 "__asan_report_load8_noabort",
594 "__asan_report_load16_noabort",
595 "__asan_report_store_n_noabort",
596 "__asan_report_store1_noabort",
597 "__asan_report_store2_noabort",
598 "__asan_report_store4_noabort",
599 "__asan_report_store8_noabort",
600 "__asan_report_store16_noabort",
601
602 "__kcsan_check_access",
603 "kcsan_found_watchpoint",
604 "kcsan_setup_watchpoint",
605 "kcsan_check_scoped_accesses",
606 "kcsan_disable_current",
607 "kcsan_enable_current_nowarn",
608
609 "__tsan_func_entry",
610 "__tsan_func_exit",
611 "__tsan_read_range",
612 "__tsan_write_range",
613 "__tsan_read1",
614 "__tsan_read2",
615 "__tsan_read4",
616 "__tsan_read8",
617 "__tsan_read16",
618 "__tsan_write1",
619 "__tsan_write2",
620 "__tsan_write4",
621 "__tsan_write8",
622 "__tsan_write16",
623 "__tsan_read_write1",
624 "__tsan_read_write2",
625 "__tsan_read_write4",
626 "__tsan_read_write8",
627 "__tsan_read_write16",
628 "__tsan_atomic8_load",
629 "__tsan_atomic16_load",
630 "__tsan_atomic32_load",
631 "__tsan_atomic64_load",
632 "__tsan_atomic8_store",
633 "__tsan_atomic16_store",
634 "__tsan_atomic32_store",
635 "__tsan_atomic64_store",
636 "__tsan_atomic8_exchange",
637 "__tsan_atomic16_exchange",
638 "__tsan_atomic32_exchange",
639 "__tsan_atomic64_exchange",
640 "__tsan_atomic8_fetch_add",
641 "__tsan_atomic16_fetch_add",
642 "__tsan_atomic32_fetch_add",
643 "__tsan_atomic64_fetch_add",
644 "__tsan_atomic8_fetch_sub",
645 "__tsan_atomic16_fetch_sub",
646 "__tsan_atomic32_fetch_sub",
647 "__tsan_atomic64_fetch_sub",
648 "__tsan_atomic8_fetch_and",
649 "__tsan_atomic16_fetch_and",
650 "__tsan_atomic32_fetch_and",
651 "__tsan_atomic64_fetch_and",
652 "__tsan_atomic8_fetch_or",
653 "__tsan_atomic16_fetch_or",
654 "__tsan_atomic32_fetch_or",
655 "__tsan_atomic64_fetch_or",
656 "__tsan_atomic8_fetch_xor",
657 "__tsan_atomic16_fetch_xor",
658 "__tsan_atomic32_fetch_xor",
659 "__tsan_atomic64_fetch_xor",
660 "__tsan_atomic8_fetch_nand",
661 "__tsan_atomic16_fetch_nand",
662 "__tsan_atomic32_fetch_nand",
663 "__tsan_atomic64_fetch_nand",
664 "__tsan_atomic8_compare_exchange_strong",
665 "__tsan_atomic16_compare_exchange_strong",
666 "__tsan_atomic32_compare_exchange_strong",
667 "__tsan_atomic64_compare_exchange_strong",
668 "__tsan_atomic8_compare_exchange_weak",
669 "__tsan_atomic16_compare_exchange_weak",
670 "__tsan_atomic32_compare_exchange_weak",
671 "__tsan_atomic64_compare_exchange_weak",
672 "__tsan_atomic8_compare_exchange_val",
673 "__tsan_atomic16_compare_exchange_val",
674 "__tsan_atomic32_compare_exchange_val",
675 "__tsan_atomic64_compare_exchange_val",
676 "__tsan_atomic_thread_fence",
677 "__tsan_atomic_signal_fence",
678
679 "write_comp_data",
680 "check_kcov_mode",
681 "__sanitizer_cov_trace_pc",
682 "__sanitizer_cov_trace_const_cmp1",
683 "__sanitizer_cov_trace_const_cmp2",
684 "__sanitizer_cov_trace_const_cmp4",
685 "__sanitizer_cov_trace_const_cmp8",
686 "__sanitizer_cov_trace_cmp1",
687 "__sanitizer_cov_trace_cmp2",
688 "__sanitizer_cov_trace_cmp4",
689 "__sanitizer_cov_trace_cmp8",
690 "__sanitizer_cov_trace_switch",
691
692 "ubsan_type_mismatch_common",
693 "__ubsan_handle_type_mismatch",
694 "__ubsan_handle_type_mismatch_v1",
695 "__ubsan_handle_shift_out_of_bounds",
696
697 "csum_partial_copy_generic",
698 "copy_mc_fragile",
699 "copy_mc_fragile_handle_tail",
700 "copy_mc_enhanced_fast_string",
701 "ftrace_likely_update",
702 NULL
703};
704
705static void add_uaccess_safe(struct objtool_file *file)
706{
707 struct symbol *func;
708 const char **name;
709
710 if (!uaccess)
711 return;
712
713 for (name = uaccess_safe_builtin; *name; name++) {
714 func = find_symbol_by_name(file->elf, *name);
715 if (!func)
716 continue;
717
718 func->uaccess_safe = true;
719 }
720}
721
722
723
724
725
726
727
728static int add_ignore_alternatives(struct objtool_file *file)
729{
730 struct section *sec;
731 struct reloc *reloc;
732 struct instruction *insn;
733
734 sec = find_section_by_name(file->elf, ".rela.discard.ignore_alts");
735 if (!sec)
736 return 0;
737
738 list_for_each_entry(reloc, &sec->reloc_list, list) {
739 if (reloc->sym->type != STT_SECTION) {
740 WARN("unexpected relocation symbol type in %s", sec->name);
741 return -1;
742 }
743
744 insn = find_insn(file, reloc->sym->sec, reloc->addend);
745 if (!insn) {
746 WARN("bad .discard.ignore_alts entry");
747 return -1;
748 }
749
750 insn->ignore_alts = true;
751 }
752
753 return 0;
754}
755
756
757
758
759static int add_jump_destinations(struct objtool_file *file)
760{
761 struct instruction *insn;
762 struct reloc *reloc;
763 struct section *dest_sec;
764 unsigned long dest_off;
765
766 for_each_insn(file, insn) {
767 if (!is_static_jump(insn))
768 continue;
769
770 if (insn->offset == FAKE_JUMP_OFFSET)
771 continue;
772
773 reloc = find_reloc_by_dest_range(file->elf, insn->sec,
774 insn->offset, insn->len);
775 if (!reloc) {
776 dest_sec = insn->sec;
777 dest_off = arch_jump_destination(insn);
778 } else if (reloc->sym->type == STT_SECTION) {
779 dest_sec = reloc->sym->sec;
780 dest_off = arch_dest_reloc_offset(reloc->addend);
781 } else if (reloc->sym->sec->idx) {
782 dest_sec = reloc->sym->sec;
783 dest_off = reloc->sym->sym.st_value +
784 arch_dest_reloc_offset(reloc->addend);
785 } else if (strstr(reloc->sym->name, "_indirect_thunk_")) {
786
787
788
789
790 if (insn->type == INSN_JUMP_UNCONDITIONAL)
791 insn->type = INSN_JUMP_DYNAMIC;
792 else
793 insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL;
794
795 insn->retpoline_safe = true;
796 continue;
797 } else {
798
799 insn->call_dest = reloc->sym;
800 if (insn->call_dest->static_call_tramp) {
801 list_add_tail(&insn->static_call_node,
802 &file->static_call_list);
803 }
804 continue;
805 }
806
807 insn->jump_dest = find_insn(file, dest_sec, dest_off);
808 if (!insn->jump_dest) {
809
810
811
812
813
814
815 if (!strcmp(insn->sec->name, ".altinstr_replacement"))
816 continue;
817
818 WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
819 insn->sec, insn->offset, dest_sec->name,
820 dest_off);
821 return -1;
822 }
823
824
825
826
827 if (insn->func && insn->jump_dest->func &&
828 insn->func != insn->jump_dest->func) {
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845 if (!strstr(insn->func->name, ".cold.") &&
846 strstr(insn->jump_dest->func->name, ".cold.")) {
847 insn->func->cfunc = insn->jump_dest->func;
848 insn->jump_dest->func->pfunc = insn->func;
849
850 } else if (insn->jump_dest->func->pfunc != insn->func->pfunc &&
851 insn->jump_dest->offset == insn->jump_dest->func->offset) {
852
853
854 insn->call_dest = insn->jump_dest->func;
855 if (insn->call_dest->static_call_tramp) {
856 list_add_tail(&insn->static_call_node,
857 &file->static_call_list);
858 }
859 }
860 }
861 }
862
863 return 0;
864}
865
866static void remove_insn_ops(struct instruction *insn)
867{
868 struct stack_op *op, *tmp;
869
870 list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) {
871 list_del(&op->list);
872 free(op);
873 }
874}
875
876static struct symbol *find_call_destination(struct section *sec, unsigned long offset)
877{
878 struct symbol *call_dest;
879
880 call_dest = find_func_by_offset(sec, offset);
881 if (!call_dest)
882 call_dest = find_symbol_by_offset(sec, offset);
883
884 return call_dest;
885}
886
887
888
889
890static int add_call_destinations(struct objtool_file *file)
891{
892 struct instruction *insn;
893 unsigned long dest_off;
894 struct reloc *reloc;
895
896 for_each_insn(file, insn) {
897 if (insn->type != INSN_CALL)
898 continue;
899
900 reloc = find_reloc_by_dest_range(file->elf, insn->sec,
901 insn->offset, insn->len);
902 if (!reloc) {
903 dest_off = arch_jump_destination(insn);
904 insn->call_dest = find_call_destination(insn->sec, dest_off);
905
906 if (insn->ignore)
907 continue;
908
909 if (!insn->call_dest) {
910 WARN_FUNC("unannotated intra-function call", insn->sec, insn->offset);
911 return -1;
912 }
913
914 if (insn->func && insn->call_dest->type != STT_FUNC) {
915 WARN_FUNC("unsupported call to non-function",
916 insn->sec, insn->offset);
917 return -1;
918 }
919
920 } else if (reloc->sym->type == STT_SECTION) {
921 dest_off = arch_dest_reloc_offset(reloc->addend);
922 insn->call_dest = find_call_destination(reloc->sym->sec,
923 dest_off);
924 if (!insn->call_dest) {
925 WARN_FUNC("can't find call dest symbol at %s+0x%lx",
926 insn->sec, insn->offset,
927 reloc->sym->sec->name,
928 dest_off);
929 return -1;
930 }
931 } else
932 insn->call_dest = reloc->sym;
933
934
935
936
937
938
939 if (insn->sec->noinstr &&
940 !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) {
941 if (reloc) {
942 reloc->type = R_NONE;
943 elf_write_reloc(file->elf, reloc);
944 }
945
946 elf_write_insn(file->elf, insn->sec,
947 insn->offset, insn->len,
948 arch_nop_insn(insn->len));
949 insn->type = INSN_NOP;
950 }
951
952
953
954
955
956
957
958
959 remove_insn_ops(insn);
960 }
961
962 return 0;
963}
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982static int handle_group_alt(struct objtool_file *file,
983 struct special_alt *special_alt,
984 struct instruction *orig_insn,
985 struct instruction **new_insn)
986{
987 static unsigned int alt_group_next_index = 1;
988 struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL;
989 unsigned int alt_group = alt_group_next_index++;
990 unsigned long dest_off;
991
992 last_orig_insn = NULL;
993 insn = orig_insn;
994 sec_for_each_insn_from(file, insn) {
995 if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
996 break;
997
998 insn->alt_group = alt_group;
999 last_orig_insn = insn;
1000 }
1001
1002 if (next_insn_same_sec(file, last_orig_insn)) {
1003 fake_jump = malloc(sizeof(*fake_jump));
1004 if (!fake_jump) {
1005 WARN("malloc failed");
1006 return -1;
1007 }
1008 memset(fake_jump, 0, sizeof(*fake_jump));
1009 INIT_LIST_HEAD(&fake_jump->alts);
1010 INIT_LIST_HEAD(&fake_jump->stack_ops);
1011 init_cfi_state(&fake_jump->cfi);
1012
1013 fake_jump->sec = special_alt->new_sec;
1014 fake_jump->offset = FAKE_JUMP_OFFSET;
1015 fake_jump->type = INSN_JUMP_UNCONDITIONAL;
1016 fake_jump->jump_dest = list_next_entry(last_orig_insn, list);
1017 fake_jump->func = orig_insn->func;
1018 }
1019
1020 if (!special_alt->new_len) {
1021 if (!fake_jump) {
1022 WARN("%s: empty alternative at end of section",
1023 special_alt->orig_sec->name);
1024 return -1;
1025 }
1026
1027 *new_insn = fake_jump;
1028 return 0;
1029 }
1030
1031 last_new_insn = NULL;
1032 alt_group = alt_group_next_index++;
1033 insn = *new_insn;
1034 sec_for_each_insn_from(file, insn) {
1035 struct reloc *alt_reloc;
1036
1037 if (insn->offset >= special_alt->new_off + special_alt->new_len)
1038 break;
1039
1040 last_new_insn = insn;
1041
1042 insn->ignore = orig_insn->ignore_alts;
1043 insn->func = orig_insn->func;
1044 insn->alt_group = alt_group;
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054 alt_reloc = find_reloc_by_dest_range(file->elf, insn->sec,
1055 insn->offset, insn->len);
1056 if (alt_reloc &&
1057 !arch_support_alt_relocation(special_alt, insn, alt_reloc)) {
1058
1059 WARN_FUNC("unsupported relocation in alternatives section",
1060 insn->sec, insn->offset);
1061 return -1;
1062 }
1063
1064 if (!is_static_jump(insn))
1065 continue;
1066
1067 if (!insn->immediate)
1068 continue;
1069
1070 dest_off = arch_jump_destination(insn);
1071 if (dest_off == special_alt->new_off + special_alt->new_len) {
1072 if (!fake_jump) {
1073 WARN("%s: alternative jump to end of section",
1074 special_alt->orig_sec->name);
1075 return -1;
1076 }
1077 insn->jump_dest = fake_jump;
1078 }
1079
1080 if (!insn->jump_dest) {
1081 WARN_FUNC("can't find alternative jump destination",
1082 insn->sec, insn->offset);
1083 return -1;
1084 }
1085 }
1086
1087 if (!last_new_insn) {
1088 WARN_FUNC("can't find last new alternative instruction",
1089 special_alt->new_sec, special_alt->new_off);
1090 return -1;
1091 }
1092
1093 if (fake_jump)
1094 list_add(&fake_jump->list, &last_new_insn->list);
1095
1096 return 0;
1097}
1098
1099
1100
1101
1102
1103
1104static int handle_jump_alt(struct objtool_file *file,
1105 struct special_alt *special_alt,
1106 struct instruction *orig_insn,
1107 struct instruction **new_insn)
1108{
1109 if (orig_insn->type == INSN_NOP)
1110 return 0;
1111
1112 if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) {
1113 WARN_FUNC("unsupported instruction at jump label",
1114 orig_insn->sec, orig_insn->offset);
1115 return -1;
1116 }
1117
1118 *new_insn = list_next_entry(orig_insn, list);
1119 return 0;
1120}
1121
1122
1123
1124
1125
1126
1127
1128static int add_special_section_alts(struct objtool_file *file)
1129{
1130 struct list_head special_alts;
1131 struct instruction *orig_insn, *new_insn;
1132 struct special_alt *special_alt, *tmp;
1133 struct alternative *alt;
1134 int ret;
1135
1136 ret = special_get_alts(file->elf, &special_alts);
1137 if (ret)
1138 return ret;
1139
1140 list_for_each_entry_safe(special_alt, tmp, &special_alts, list) {
1141
1142 orig_insn = find_insn(file, special_alt->orig_sec,
1143 special_alt->orig_off);
1144 if (!orig_insn) {
1145 WARN_FUNC("special: can't find orig instruction",
1146 special_alt->orig_sec, special_alt->orig_off);
1147 ret = -1;
1148 goto out;
1149 }
1150
1151 new_insn = NULL;
1152 if (!special_alt->group || special_alt->new_len) {
1153 new_insn = find_insn(file, special_alt->new_sec,
1154 special_alt->new_off);
1155 if (!new_insn) {
1156 WARN_FUNC("special: can't find new instruction",
1157 special_alt->new_sec,
1158 special_alt->new_off);
1159 ret = -1;
1160 goto out;
1161 }
1162 }
1163
1164 if (special_alt->group) {
1165 if (!special_alt->orig_len) {
1166 WARN_FUNC("empty alternative entry",
1167 orig_insn->sec, orig_insn->offset);
1168 continue;
1169 }
1170
1171 ret = handle_group_alt(file, special_alt, orig_insn,
1172 &new_insn);
1173 if (ret)
1174 goto out;
1175 } else if (special_alt->jump_or_nop) {
1176 ret = handle_jump_alt(file, special_alt, orig_insn,
1177 &new_insn);
1178 if (ret)
1179 goto out;
1180 }
1181
1182 alt = malloc(sizeof(*alt));
1183 if (!alt) {
1184 WARN("malloc failed");
1185 ret = -1;
1186 goto out;
1187 }
1188
1189 alt->insn = new_insn;
1190 alt->skip_orig = special_alt->skip_orig;
1191 orig_insn->ignore_alts |= special_alt->skip_alt;
1192 list_add_tail(&alt->list, &orig_insn->alts);
1193
1194 list_del(&special_alt->list);
1195 free(special_alt);
1196 }
1197
1198out:
1199 return ret;
1200}
1201
1202static int add_jump_table(struct objtool_file *file, struct instruction *insn,
1203 struct reloc *table)
1204{
1205 struct reloc *reloc = table;
1206 struct instruction *dest_insn;
1207 struct alternative *alt;
1208 struct symbol *pfunc = insn->func->pfunc;
1209 unsigned int prev_offset = 0;
1210
1211
1212
1213
1214
1215 list_for_each_entry_from(reloc, &table->sec->reloc_list, list) {
1216
1217
1218 if (reloc != table && reloc->jump_table_start)
1219 break;
1220
1221
1222 if (prev_offset && reloc->offset != prev_offset + 8)
1223 break;
1224
1225
1226 if (reloc->sym->sec == pfunc->sec &&
1227 reloc->addend == pfunc->offset)
1228 break;
1229
1230 dest_insn = find_insn(file, reloc->sym->sec, reloc->addend);
1231 if (!dest_insn)
1232 break;
1233
1234
1235 if (!dest_insn->func || dest_insn->func->pfunc != pfunc)
1236 break;
1237
1238 alt = malloc(sizeof(*alt));
1239 if (!alt) {
1240 WARN("malloc failed");
1241 return -1;
1242 }
1243
1244 alt->insn = dest_insn;
1245 list_add_tail(&alt->list, &insn->alts);
1246 prev_offset = reloc->offset;
1247 }
1248
1249 if (!prev_offset) {
1250 WARN_FUNC("can't find switch jump table",
1251 insn->sec, insn->offset);
1252 return -1;
1253 }
1254
1255 return 0;
1256}
1257
1258
1259
1260
1261
1262static struct reloc *find_jump_table(struct objtool_file *file,
1263 struct symbol *func,
1264 struct instruction *insn)
1265{
1266 struct reloc *table_reloc;
1267 struct instruction *dest_insn, *orig_insn = insn;
1268
1269
1270
1271
1272
1273
1274 for (;
1275 insn && insn->func && insn->func->pfunc == func;
1276 insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) {
1277
1278 if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC)
1279 break;
1280
1281
1282 if (insn->type == INSN_JUMP_UNCONDITIONAL &&
1283 insn->jump_dest &&
1284 (insn->jump_dest->offset <= insn->offset ||
1285 insn->jump_dest->offset > orig_insn->offset))
1286 break;
1287
1288 table_reloc = arch_find_switch_table(file, insn);
1289 if (!table_reloc)
1290 continue;
1291 dest_insn = find_insn(file, table_reloc->sym->sec, table_reloc->addend);
1292 if (!dest_insn || !dest_insn->func || dest_insn->func->pfunc != func)
1293 continue;
1294
1295 return table_reloc;
1296 }
1297
1298 return NULL;
1299}
1300
1301
1302
1303
1304
1305static void mark_func_jump_tables(struct objtool_file *file,
1306 struct symbol *func)
1307{
1308 struct instruction *insn, *last = NULL;
1309 struct reloc *reloc;
1310
1311 func_for_each_insn(file, func, insn) {
1312 if (!last)
1313 last = insn;
1314
1315
1316
1317
1318
1319
1320 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
1321 insn->offset > last->offset &&
1322 insn->jump_dest->offset > insn->offset &&
1323 !insn->jump_dest->first_jump_src) {
1324
1325 insn->jump_dest->first_jump_src = insn;
1326 last = insn->jump_dest;
1327 }
1328
1329 if (insn->type != INSN_JUMP_DYNAMIC)
1330 continue;
1331
1332 reloc = find_jump_table(file, func, insn);
1333 if (reloc) {
1334 reloc->jump_table_start = true;
1335 insn->jump_table = reloc;
1336 }
1337 }
1338}
1339
1340static int add_func_jump_tables(struct objtool_file *file,
1341 struct symbol *func)
1342{
1343 struct instruction *insn;
1344 int ret;
1345
1346 func_for_each_insn(file, func, insn) {
1347 if (!insn->jump_table)
1348 continue;
1349
1350 ret = add_jump_table(file, insn, insn->jump_table);
1351 if (ret)
1352 return ret;
1353 }
1354
1355 return 0;
1356}
1357
1358
1359
1360
1361
1362
1363static int add_jump_table_alts(struct objtool_file *file)
1364{
1365 struct section *sec;
1366 struct symbol *func;
1367 int ret;
1368
1369 if (!file->rodata)
1370 return 0;
1371
1372 for_each_sec(file, sec) {
1373 list_for_each_entry(func, &sec->symbol_list, list) {
1374 if (func->type != STT_FUNC)
1375 continue;
1376
1377 mark_func_jump_tables(file, func);
1378 ret = add_func_jump_tables(file, func);
1379 if (ret)
1380 return ret;
1381 }
1382 }
1383
1384 return 0;
1385}
1386
1387static int read_unwind_hints(struct objtool_file *file)
1388{
1389 struct section *sec, *relocsec;
1390 struct reloc *reloc;
1391 struct unwind_hint *hint;
1392 struct instruction *insn;
1393 struct cfi_reg *cfa;
1394 int i;
1395
1396 sec = find_section_by_name(file->elf, ".discard.unwind_hints");
1397 if (!sec)
1398 return 0;
1399
1400 relocsec = sec->reloc;
1401 if (!relocsec) {
1402 WARN("missing .rela.discard.unwind_hints section");
1403 return -1;
1404 }
1405
1406 if (sec->len % sizeof(struct unwind_hint)) {
1407 WARN("struct unwind_hint size mismatch");
1408 return -1;
1409 }
1410
1411 file->hints = true;
1412
1413 for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) {
1414 hint = (struct unwind_hint *)sec->data->d_buf + i;
1415
1416 reloc = find_reloc_by_dest(file->elf, sec, i * sizeof(*hint));
1417 if (!reloc) {
1418 WARN("can't find reloc for unwind_hints[%d]", i);
1419 return -1;
1420 }
1421
1422 insn = find_insn(file, reloc->sym->sec, reloc->addend);
1423 if (!insn) {
1424 WARN("can't find insn for unwind_hints[%d]", i);
1425 return -1;
1426 }
1427
1428 cfa = &insn->cfi.cfa;
1429
1430 if (hint->type == UNWIND_HINT_TYPE_RET_OFFSET) {
1431 insn->ret_offset = hint->sp_offset;
1432 continue;
1433 }
1434
1435 insn->hint = true;
1436
1437 if (arch_decode_hint_reg(insn, hint->sp_reg)) {
1438 WARN_FUNC("unsupported unwind_hint sp base reg %d",
1439 insn->sec, insn->offset, hint->sp_reg);
1440 return -1;
1441 }
1442
1443 cfa->offset = hint->sp_offset;
1444 insn->cfi.type = hint->type;
1445 insn->cfi.end = hint->end;
1446 }
1447
1448 return 0;
1449}
1450
1451static int read_retpoline_hints(struct objtool_file *file)
1452{
1453 struct section *sec;
1454 struct instruction *insn;
1455 struct reloc *reloc;
1456
1457 sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe");
1458 if (!sec)
1459 return 0;
1460
1461 list_for_each_entry(reloc, &sec->reloc_list, list) {
1462 if (reloc->sym->type != STT_SECTION) {
1463 WARN("unexpected relocation symbol type in %s", sec->name);
1464 return -1;
1465 }
1466
1467 insn = find_insn(file, reloc->sym->sec, reloc->addend);
1468 if (!insn) {
1469 WARN("bad .discard.retpoline_safe entry");
1470 return -1;
1471 }
1472
1473 if (insn->type != INSN_JUMP_DYNAMIC &&
1474 insn->type != INSN_CALL_DYNAMIC) {
1475 WARN_FUNC("retpoline_safe hint not an indirect jump/call",
1476 insn->sec, insn->offset);
1477 return -1;
1478 }
1479
1480 insn->retpoline_safe = true;
1481 }
1482
1483 return 0;
1484}
1485
1486static int read_instr_hints(struct objtool_file *file)
1487{
1488 struct section *sec;
1489 struct instruction *insn;
1490 struct reloc *reloc;
1491
1492 sec = find_section_by_name(file->elf, ".rela.discard.instr_end");
1493 if (!sec)
1494 return 0;
1495
1496 list_for_each_entry(reloc, &sec->reloc_list, list) {
1497 if (reloc->sym->type != STT_SECTION) {
1498 WARN("unexpected relocation symbol type in %s", sec->name);
1499 return -1;
1500 }
1501
1502 insn = find_insn(file, reloc->sym->sec, reloc->addend);
1503 if (!insn) {
1504 WARN("bad .discard.instr_end entry");
1505 return -1;
1506 }
1507
1508 insn->instr--;
1509 }
1510
1511 sec = find_section_by_name(file->elf, ".rela.discard.instr_begin");
1512 if (!sec)
1513 return 0;
1514
1515 list_for_each_entry(reloc, &sec->reloc_list, list) {
1516 if (reloc->sym->type != STT_SECTION) {
1517 WARN("unexpected relocation symbol type in %s", sec->name);
1518 return -1;
1519 }
1520
1521 insn = find_insn(file, reloc->sym->sec, reloc->addend);
1522 if (!insn) {
1523 WARN("bad .discard.instr_begin entry");
1524 return -1;
1525 }
1526
1527 insn->instr++;
1528 }
1529
1530 return 0;
1531}
1532
1533static int read_intra_function_calls(struct objtool_file *file)
1534{
1535 struct instruction *insn;
1536 struct section *sec;
1537 struct reloc *reloc;
1538
1539 sec = find_section_by_name(file->elf, ".rela.discard.intra_function_calls");
1540 if (!sec)
1541 return 0;
1542
1543 list_for_each_entry(reloc, &sec->reloc_list, list) {
1544 unsigned long dest_off;
1545
1546 if (reloc->sym->type != STT_SECTION) {
1547 WARN("unexpected relocation symbol type in %s",
1548 sec->name);
1549 return -1;
1550 }
1551
1552 insn = find_insn(file, reloc->sym->sec, reloc->addend);
1553 if (!insn) {
1554 WARN("bad .discard.intra_function_call entry");
1555 return -1;
1556 }
1557
1558 if (insn->type != INSN_CALL) {
1559 WARN_FUNC("intra_function_call not a direct call",
1560 insn->sec, insn->offset);
1561 return -1;
1562 }
1563
1564
1565
1566
1567
1568
1569 insn->type = INSN_JUMP_UNCONDITIONAL;
1570
1571 dest_off = insn->offset + insn->len + insn->immediate;
1572 insn->jump_dest = find_insn(file, insn->sec, dest_off);
1573 if (!insn->jump_dest) {
1574 WARN_FUNC("can't find call dest at %s+0x%lx",
1575 insn->sec, insn->offset,
1576 insn->sec->name, dest_off);
1577 return -1;
1578 }
1579 }
1580
1581 return 0;
1582}
1583
1584static int read_static_call_tramps(struct objtool_file *file)
1585{
1586 struct section *sec;
1587 struct symbol *func;
1588
1589 for_each_sec(file, sec) {
1590 list_for_each_entry(func, &sec->symbol_list, list) {
1591 if (func->bind == STB_GLOBAL &&
1592 !strncmp(func->name, STATIC_CALL_TRAMP_PREFIX_STR,
1593 strlen(STATIC_CALL_TRAMP_PREFIX_STR)))
1594 func->static_call_tramp = true;
1595 }
1596 }
1597
1598 return 0;
1599}
1600
1601static void mark_rodata(struct objtool_file *file)
1602{
1603 struct section *sec;
1604 bool found = false;
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616 for_each_sec(file, sec) {
1617 if (!strncmp(sec->name, ".rodata", 7) &&
1618 !strstr(sec->name, ".str1.")) {
1619 sec->rodata = true;
1620 found = true;
1621 }
1622 }
1623
1624 file->rodata = found;
1625}
1626
1627static int decode_sections(struct objtool_file *file)
1628{
1629 int ret;
1630
1631 mark_rodata(file);
1632
1633 ret = decode_instructions(file);
1634 if (ret)
1635 return ret;
1636
1637 ret = add_dead_ends(file);
1638 if (ret)
1639 return ret;
1640
1641 add_ignores(file);
1642 add_uaccess_safe(file);
1643
1644 ret = add_ignore_alternatives(file);
1645 if (ret)
1646 return ret;
1647
1648 ret = read_static_call_tramps(file);
1649 if (ret)
1650 return ret;
1651
1652 ret = add_jump_destinations(file);
1653 if (ret)
1654 return ret;
1655
1656 ret = add_special_section_alts(file);
1657 if (ret)
1658 return ret;
1659
1660 ret = read_intra_function_calls(file);
1661 if (ret)
1662 return ret;
1663
1664 ret = add_call_destinations(file);
1665 if (ret)
1666 return ret;
1667
1668 ret = add_jump_table_alts(file);
1669 if (ret)
1670 return ret;
1671
1672 ret = read_unwind_hints(file);
1673 if (ret)
1674 return ret;
1675
1676 ret = read_retpoline_hints(file);
1677 if (ret)
1678 return ret;
1679
1680 ret = read_instr_hints(file);
1681 if (ret)
1682 return ret;
1683
1684 return 0;
1685}
1686
1687static bool is_fentry_call(struct instruction *insn)
1688{
1689 if (insn->type == INSN_CALL && insn->call_dest &&
1690 insn->call_dest->type == STT_NOTYPE &&
1691 !strcmp(insn->call_dest->name, "__fentry__"))
1692 return true;
1693
1694 return false;
1695}
1696
1697static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state)
1698{
1699 u8 ret_offset = insn->ret_offset;
1700 struct cfi_state *cfi = &state->cfi;
1701 int i;
1702
1703 if (cfi->cfa.base != initial_func_cfi.cfa.base || cfi->drap)
1704 return true;
1705
1706 if (cfi->cfa.offset != initial_func_cfi.cfa.offset + ret_offset)
1707 return true;
1708
1709 if (cfi->stack_size != initial_func_cfi.cfa.offset + ret_offset)
1710 return true;
1711
1712
1713
1714
1715
1716
1717 if (ret_offset)
1718 return false;
1719
1720 for (i = 0; i < CFI_NUM_REGS; i++) {
1721 if (cfi->regs[i].base != initial_func_cfi.regs[i].base ||
1722 cfi->regs[i].offset != initial_func_cfi.regs[i].offset)
1723 return true;
1724 }
1725
1726 return false;
1727}
1728
1729static bool has_valid_stack_frame(struct insn_state *state)
1730{
1731 struct cfi_state *cfi = &state->cfi;
1732
1733 if (cfi->cfa.base == CFI_BP && cfi->regs[CFI_BP].base == CFI_CFA &&
1734 cfi->regs[CFI_BP].offset == -16)
1735 return true;
1736
1737 if (cfi->drap && cfi->regs[CFI_BP].base == CFI_BP)
1738 return true;
1739
1740 return false;
1741}
1742
1743static int update_cfi_state_regs(struct instruction *insn,
1744 struct cfi_state *cfi,
1745 struct stack_op *op)
1746{
1747 struct cfi_reg *cfa = &cfi->cfa;
1748
1749 if (cfa->base != CFI_SP && cfa->base != CFI_SP_INDIRECT)
1750 return 0;
1751
1752
1753 if (op->dest.type == OP_DEST_PUSH || op->dest.type == OP_DEST_PUSHF)
1754 cfa->offset += 8;
1755
1756
1757 if (op->src.type == OP_SRC_POP || op->src.type == OP_SRC_POPF)
1758 cfa->offset -= 8;
1759
1760
1761 if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD &&
1762 op->dest.reg == CFI_SP && op->src.reg == CFI_SP)
1763 cfa->offset -= op->src.offset;
1764
1765 return 0;
1766}
1767
1768static void save_reg(struct cfi_state *cfi, unsigned char reg, int base, int offset)
1769{
1770 if (arch_callee_saved_reg(reg) &&
1771 cfi->regs[reg].base == CFI_UNDEFINED) {
1772 cfi->regs[reg].base = base;
1773 cfi->regs[reg].offset = offset;
1774 }
1775}
1776
1777static void restore_reg(struct cfi_state *cfi, unsigned char reg)
1778{
1779 cfi->regs[reg].base = initial_func_cfi.regs[reg].base;
1780 cfi->regs[reg].offset = initial_func_cfi.regs[reg].offset;
1781}
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
1837 struct stack_op *op)
1838{
1839 struct cfi_reg *cfa = &cfi->cfa;
1840 struct cfi_reg *regs = cfi->regs;
1841
1842
1843 if (cfa->base == CFI_UNDEFINED) {
1844 if (insn->func) {
1845 WARN_FUNC("undefined stack state", insn->sec, insn->offset);
1846 return -1;
1847 }
1848 return 0;
1849 }
1850
1851 if (cfi->type == UNWIND_HINT_TYPE_REGS ||
1852 cfi->type == UNWIND_HINT_TYPE_REGS_PARTIAL)
1853 return update_cfi_state_regs(insn, cfi, op);
1854
1855 switch (op->dest.type) {
1856
1857 case OP_DEST_REG:
1858 switch (op->src.type) {
1859
1860 case OP_SRC_REG:
1861 if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP &&
1862 cfa->base == CFI_SP &&
1863 regs[CFI_BP].base == CFI_CFA &&
1864 regs[CFI_BP].offset == -cfa->offset) {
1865
1866
1867 cfa->base = op->dest.reg;
1868 cfi->bp_scratch = false;
1869 }
1870
1871 else if (op->src.reg == CFI_SP &&
1872 op->dest.reg == CFI_BP && cfi->drap) {
1873
1874
1875 regs[CFI_BP].base = CFI_BP;
1876 regs[CFI_BP].offset = -cfi->stack_size;
1877 cfi->bp_scratch = false;
1878 }
1879
1880 else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892 cfi->vals[op->dest.reg].base = CFI_CFA;
1893 cfi->vals[op->dest.reg].offset = -cfi->stack_size;
1894 }
1895
1896 else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP &&
1897 cfa->base == CFI_BP) {
1898
1899
1900
1901
1902
1903
1904 cfi->stack_size = -cfi->regs[CFI_BP].offset;
1905 }
1906
1907 else if (op->dest.reg == cfa->base) {
1908
1909
1910 if (cfa->base == CFI_SP &&
1911 cfi->vals[op->src.reg].base == CFI_CFA) {
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921 cfa->offset = -cfi->vals[op->src.reg].offset;
1922 cfi->stack_size = cfa->offset;
1923
1924 } else {
1925 cfa->base = CFI_UNDEFINED;
1926 cfa->offset = 0;
1927 }
1928 }
1929
1930 break;
1931
1932 case OP_SRC_ADD:
1933 if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) {
1934
1935
1936 cfi->stack_size -= op->src.offset;
1937 if (cfa->base == CFI_SP)
1938 cfa->offset -= op->src.offset;
1939 break;
1940 }
1941
1942 if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) {
1943
1944
1945 cfi->stack_size = -(op->src.offset + regs[CFI_BP].offset);
1946 break;
1947 }
1948
1949 if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
1950
1951
1952 cfi->drap_reg = op->dest.reg;
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964 cfi->vals[op->dest.reg].base = CFI_CFA;
1965 cfi->vals[op->dest.reg].offset = \
1966 -cfi->stack_size + op->src.offset;
1967
1968 break;
1969 }
1970
1971 if (cfi->drap && op->dest.reg == CFI_SP &&
1972 op->src.reg == cfi->drap_reg) {
1973
1974
1975 cfa->base = CFI_SP;
1976 cfa->offset = cfi->stack_size = -op->src.offset;
1977 cfi->drap_reg = CFI_UNDEFINED;
1978 cfi->drap = false;
1979 break;
1980 }
1981
1982 if (op->dest.reg == cfi->cfa.base) {
1983 WARN_FUNC("unsupported stack register modification",
1984 insn->sec, insn->offset);
1985 return -1;
1986 }
1987
1988 break;
1989
1990 case OP_SRC_AND:
1991 if (op->dest.reg != CFI_SP ||
1992 (cfi->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) ||
1993 (cfi->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) {
1994 WARN_FUNC("unsupported stack pointer realignment",
1995 insn->sec, insn->offset);
1996 return -1;
1997 }
1998
1999 if (cfi->drap_reg != CFI_UNDEFINED) {
2000
2001 cfa->base = cfi->drap_reg;
2002 cfa->offset = cfi->stack_size = 0;
2003 cfi->drap = true;
2004 }
2005
2006
2007
2008
2009
2010
2011 break;
2012
2013 case OP_SRC_POP:
2014 case OP_SRC_POPF:
2015 if (!cfi->drap && op->dest.reg == cfa->base) {
2016
2017
2018 cfa->base = CFI_SP;
2019 }
2020
2021 if (cfi->drap && cfa->base == CFI_BP_INDIRECT &&
2022 op->dest.reg == cfi->drap_reg &&
2023 cfi->drap_offset == -cfi->stack_size) {
2024
2025
2026 cfa->base = cfi->drap_reg;
2027 cfa->offset = 0;
2028 cfi->drap_offset = -1;
2029
2030 } else if (regs[op->dest.reg].offset == -cfi->stack_size) {
2031
2032
2033 restore_reg(cfi, op->dest.reg);
2034 }
2035
2036 cfi->stack_size -= 8;
2037 if (cfa->base == CFI_SP)
2038 cfa->offset -= 8;
2039
2040 break;
2041
2042 case OP_SRC_REG_INDIRECT:
2043 if (cfi->drap && op->src.reg == CFI_BP &&
2044 op->src.offset == cfi->drap_offset) {
2045
2046
2047 cfa->base = cfi->drap_reg;
2048 cfa->offset = 0;
2049 cfi->drap_offset = -1;
2050 }
2051
2052 if (cfi->drap && op->src.reg == CFI_BP &&
2053 op->src.offset == regs[op->dest.reg].offset) {
2054
2055
2056 restore_reg(cfi, op->dest.reg);
2057
2058 } else if (op->src.reg == cfa->base &&
2059 op->src.offset == regs[op->dest.reg].offset + cfa->offset) {
2060
2061
2062
2063 restore_reg(cfi, op->dest.reg);
2064 }
2065
2066 break;
2067
2068 default:
2069 WARN_FUNC("unknown stack-related instruction",
2070 insn->sec, insn->offset);
2071 return -1;
2072 }
2073
2074 break;
2075
2076 case OP_DEST_PUSH:
2077 case OP_DEST_PUSHF:
2078 cfi->stack_size += 8;
2079 if (cfa->base == CFI_SP)
2080 cfa->offset += 8;
2081
2082 if (op->src.type != OP_SRC_REG)
2083 break;
2084
2085 if (cfi->drap) {
2086 if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) {
2087
2088
2089 cfa->base = CFI_BP_INDIRECT;
2090 cfa->offset = -cfi->stack_size;
2091
2092
2093 cfi->drap_offset = -cfi->stack_size;
2094
2095 } else if (op->src.reg == CFI_BP && cfa->base == cfi->drap_reg) {
2096
2097
2098 cfi->stack_size = 0;
2099
2100 } else {
2101
2102
2103 save_reg(cfi, op->src.reg, CFI_BP, -cfi->stack_size);
2104 }
2105
2106 } else {
2107
2108
2109 save_reg(cfi, op->src.reg, CFI_CFA, -cfi->stack_size);
2110 }
2111
2112
2113 if (!no_fp && insn->func && op->src.reg == CFI_BP &&
2114 cfa->base != CFI_BP)
2115 cfi->bp_scratch = true;
2116 break;
2117
2118 case OP_DEST_REG_INDIRECT:
2119
2120 if (cfi->drap) {
2121 if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) {
2122
2123
2124 cfa->base = CFI_BP_INDIRECT;
2125 cfa->offset = op->dest.offset;
2126
2127
2128 cfi->drap_offset = op->dest.offset;
2129 } else {
2130
2131
2132 save_reg(cfi, op->src.reg, CFI_BP, op->dest.offset);
2133 }
2134
2135 } else if (op->dest.reg == cfa->base) {
2136
2137
2138
2139 save_reg(cfi, op->src.reg, CFI_CFA,
2140 op->dest.offset - cfi->cfa.offset);
2141 }
2142
2143 break;
2144
2145 case OP_DEST_LEAVE:
2146 if ((!cfi->drap && cfa->base != CFI_BP) ||
2147 (cfi->drap && cfa->base != cfi->drap_reg)) {
2148 WARN_FUNC("leave instruction with modified stack frame",
2149 insn->sec, insn->offset);
2150 return -1;
2151 }
2152
2153
2154
2155 cfi->stack_size = -cfi->regs[CFI_BP].offset - 8;
2156 restore_reg(cfi, CFI_BP);
2157
2158 if (!cfi->drap) {
2159 cfa->base = CFI_SP;
2160 cfa->offset -= 8;
2161 }
2162
2163 break;
2164
2165 case OP_DEST_MEM:
2166 if (op->src.type != OP_SRC_POP && op->src.type != OP_SRC_POPF) {
2167 WARN_FUNC("unknown stack-related memory operation",
2168 insn->sec, insn->offset);
2169 return -1;
2170 }
2171
2172
2173 cfi->stack_size -= 8;
2174 if (cfa->base == CFI_SP)
2175 cfa->offset -= 8;
2176
2177 break;
2178
2179 default:
2180 WARN_FUNC("unknown stack-related instruction",
2181 insn->sec, insn->offset);
2182 return -1;
2183 }
2184
2185 return 0;
2186}
2187
2188static int handle_insn_ops(struct instruction *insn, struct insn_state *state)
2189{
2190 struct stack_op *op;
2191
2192 list_for_each_entry(op, &insn->stack_ops, list) {
2193 struct cfi_state old_cfi = state->cfi;
2194 int res;
2195
2196 res = update_cfi_state(insn, &state->cfi, op);
2197 if (res)
2198 return res;
2199
2200 if (insn->alt_group && memcmp(&state->cfi, &old_cfi, sizeof(struct cfi_state))) {
2201 WARN_FUNC("alternative modifies stack", insn->sec, insn->offset);
2202 return -1;
2203 }
2204
2205 if (op->dest.type == OP_DEST_PUSHF) {
2206 if (!state->uaccess_stack) {
2207 state->uaccess_stack = 1;
2208 } else if (state->uaccess_stack >> 31) {
2209 WARN_FUNC("PUSHF stack exhausted",
2210 insn->sec, insn->offset);
2211 return 1;
2212 }
2213 state->uaccess_stack <<= 1;
2214 state->uaccess_stack |= state->uaccess;
2215 }
2216
2217 if (op->src.type == OP_SRC_POPF) {
2218 if (state->uaccess_stack) {
2219 state->uaccess = state->uaccess_stack & 1;
2220 state->uaccess_stack >>= 1;
2221 if (state->uaccess_stack == 1)
2222 state->uaccess_stack = 0;
2223 }
2224 }
2225 }
2226
2227 return 0;
2228}
2229
2230static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2)
2231{
2232 struct cfi_state *cfi1 = &insn->cfi;
2233 int i;
2234
2235 if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) {
2236
2237 WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d",
2238 insn->sec, insn->offset,
2239 cfi1->cfa.base, cfi1->cfa.offset,
2240 cfi2->cfa.base, cfi2->cfa.offset);
2241
2242 } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) {
2243 for (i = 0; i < CFI_NUM_REGS; i++) {
2244 if (!memcmp(&cfi1->regs[i], &cfi2->regs[i],
2245 sizeof(struct cfi_reg)))
2246 continue;
2247
2248 WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d",
2249 insn->sec, insn->offset,
2250 i, cfi1->regs[i].base, cfi1->regs[i].offset,
2251 i, cfi2->regs[i].base, cfi2->regs[i].offset);
2252 break;
2253 }
2254
2255 } else if (cfi1->type != cfi2->type) {
2256
2257 WARN_FUNC("stack state mismatch: type1=%d type2=%d",
2258 insn->sec, insn->offset, cfi1->type, cfi2->type);
2259
2260 } else if (cfi1->drap != cfi2->drap ||
2261 (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) ||
2262 (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) {
2263
2264 WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)",
2265 insn->sec, insn->offset,
2266 cfi1->drap, cfi1->drap_reg, cfi1->drap_offset,
2267 cfi2->drap, cfi2->drap_reg, cfi2->drap_offset);
2268
2269 } else
2270 return true;
2271
2272 return false;
2273}
2274
2275static inline bool func_uaccess_safe(struct symbol *func)
2276{
2277 if (func)
2278 return func->uaccess_safe;
2279
2280 return false;
2281}
2282
2283static inline const char *call_dest_name(struct instruction *insn)
2284{
2285 if (insn->call_dest)
2286 return insn->call_dest->name;
2287
2288 return "{dynamic}";
2289}
2290
2291static inline bool noinstr_call_dest(struct symbol *func)
2292{
2293
2294
2295
2296
2297 if (!func)
2298 return false;
2299
2300
2301
2302
2303 if (func->sec->noinstr)
2304 return true;
2305
2306
2307
2308
2309
2310
2311 if (!strncmp(func->name, "__ubsan_handle_", 15))
2312 return true;
2313
2314 return false;
2315}
2316
2317static int validate_call(struct instruction *insn, struct insn_state *state)
2318{
2319 if (state->noinstr && state->instr <= 0 &&
2320 !noinstr_call_dest(insn->call_dest)) {
2321 WARN_FUNC("call to %s() leaves .noinstr.text section",
2322 insn->sec, insn->offset, call_dest_name(insn));
2323 return 1;
2324 }
2325
2326 if (state->uaccess && !func_uaccess_safe(insn->call_dest)) {
2327 WARN_FUNC("call to %s() with UACCESS enabled",
2328 insn->sec, insn->offset, call_dest_name(insn));
2329 return 1;
2330 }
2331
2332 if (state->df) {
2333 WARN_FUNC("call to %s() with DF set",
2334 insn->sec, insn->offset, call_dest_name(insn));
2335 return 1;
2336 }
2337
2338 return 0;
2339}
2340
2341static int validate_sibling_call(struct instruction *insn, struct insn_state *state)
2342{
2343 if (has_modified_stack_frame(insn, state)) {
2344 WARN_FUNC("sibling call from callable instruction with modified stack frame",
2345 insn->sec, insn->offset);
2346 return 1;
2347 }
2348
2349 return validate_call(insn, state);
2350}
2351
2352static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state)
2353{
2354 if (state->noinstr && state->instr > 0) {
2355 WARN_FUNC("return with instrumentation enabled",
2356 insn->sec, insn->offset);
2357 return 1;
2358 }
2359
2360 if (state->uaccess && !func_uaccess_safe(func)) {
2361 WARN_FUNC("return with UACCESS enabled",
2362 insn->sec, insn->offset);
2363 return 1;
2364 }
2365
2366 if (!state->uaccess && func_uaccess_safe(func)) {
2367 WARN_FUNC("return with UACCESS disabled from a UACCESS-safe function",
2368 insn->sec, insn->offset);
2369 return 1;
2370 }
2371
2372 if (state->df) {
2373 WARN_FUNC("return with DF set",
2374 insn->sec, insn->offset);
2375 return 1;
2376 }
2377
2378 if (func && has_modified_stack_frame(insn, state)) {
2379 WARN_FUNC("return with modified stack frame",
2380 insn->sec, insn->offset);
2381 return 1;
2382 }
2383
2384 if (state->cfi.bp_scratch) {
2385 WARN_FUNC("BP used as a scratch register",
2386 insn->sec, insn->offset);
2387 return 1;
2388 }
2389
2390 return 0;
2391}
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405static void fill_alternative_cfi(struct objtool_file *file, struct instruction *insn)
2406{
2407 struct instruction *first_insn = insn;
2408 int alt_group = insn->alt_group;
2409
2410 sec_for_each_insn_continue(file, insn) {
2411 if (insn->alt_group != alt_group)
2412 break;
2413 insn->cfi = first_insn->cfi;
2414 }
2415}
2416
2417
2418
2419
2420
2421
2422
2423static int validate_branch(struct objtool_file *file, struct symbol *func,
2424 struct instruction *insn, struct insn_state state)
2425{
2426 struct alternative *alt;
2427 struct instruction *next_insn;
2428 struct section *sec;
2429 u8 visited;
2430 int ret;
2431
2432 sec = insn->sec;
2433
2434 while (1) {
2435 next_insn = next_insn_same_sec(file, insn);
2436
2437 if (file->c_file && func && insn->func && func != insn->func->pfunc) {
2438 WARN("%s() falls through to next function %s()",
2439 func->name, insn->func->name);
2440 return 1;
2441 }
2442
2443 if (func && insn->ignore) {
2444 WARN_FUNC("BUG: why am I validating an ignored function?",
2445 sec, insn->offset);
2446 return 1;
2447 }
2448
2449 visited = 1 << state.uaccess;
2450 if (insn->visited) {
2451 if (!insn->hint && !insn_cfi_match(insn, &state.cfi))
2452 return 1;
2453
2454 if (insn->visited & visited)
2455 return 0;
2456 }
2457
2458 if (state.noinstr)
2459 state.instr += insn->instr;
2460
2461 if (insn->hint)
2462 state.cfi = insn->cfi;
2463 else
2464 insn->cfi = state.cfi;
2465
2466 insn->visited |= visited;
2467
2468 if (!insn->ignore_alts && !list_empty(&insn->alts)) {
2469 bool skip_orig = false;
2470
2471 list_for_each_entry(alt, &insn->alts, list) {
2472 if (alt->skip_orig)
2473 skip_orig = true;
2474
2475 ret = validate_branch(file, func, alt->insn, state);
2476 if (ret) {
2477 if (backtrace)
2478 BT_FUNC("(alt)", insn);
2479 return ret;
2480 }
2481 }
2482
2483 if (insn->alt_group)
2484 fill_alternative_cfi(file, insn);
2485
2486 if (skip_orig)
2487 return 0;
2488 }
2489
2490 if (handle_insn_ops(insn, &state))
2491 return 1;
2492
2493 switch (insn->type) {
2494
2495 case INSN_RETURN:
2496 return validate_return(func, insn, &state);
2497
2498 case INSN_CALL:
2499 case INSN_CALL_DYNAMIC:
2500 ret = validate_call(insn, &state);
2501 if (ret)
2502 return ret;
2503
2504 if (!no_fp && func && !is_fentry_call(insn) &&
2505 !has_valid_stack_frame(&state)) {
2506 WARN_FUNC("call without frame pointer save/setup",
2507 sec, insn->offset);
2508 return 1;
2509 }
2510
2511 if (dead_end_function(file, insn->call_dest))
2512 return 0;
2513
2514 if (insn->type == INSN_CALL && insn->call_dest->static_call_tramp) {
2515 list_add_tail(&insn->static_call_node,
2516 &file->static_call_list);
2517 }
2518
2519 break;
2520
2521 case INSN_JUMP_CONDITIONAL:
2522 case INSN_JUMP_UNCONDITIONAL:
2523 if (func && is_sibling_call(insn)) {
2524 ret = validate_sibling_call(insn, &state);
2525 if (ret)
2526 return ret;
2527
2528 } else if (insn->jump_dest) {
2529 ret = validate_branch(file, func,
2530 insn->jump_dest, state);
2531 if (ret) {
2532 if (backtrace)
2533 BT_FUNC("(branch)", insn);
2534 return ret;
2535 }
2536 }
2537
2538 if (insn->type == INSN_JUMP_UNCONDITIONAL)
2539 return 0;
2540
2541 break;
2542
2543 case INSN_JUMP_DYNAMIC:
2544 case INSN_JUMP_DYNAMIC_CONDITIONAL:
2545 if (func && is_sibling_call(insn)) {
2546 ret = validate_sibling_call(insn, &state);
2547 if (ret)
2548 return ret;
2549 }
2550
2551 if (insn->type == INSN_JUMP_DYNAMIC)
2552 return 0;
2553
2554 break;
2555
2556 case INSN_CONTEXT_SWITCH:
2557 if (func && (!next_insn || !next_insn->hint)) {
2558 WARN_FUNC("unsupported instruction in callable function",
2559 sec, insn->offset);
2560 return 1;
2561 }
2562 return 0;
2563
2564 case INSN_STAC:
2565 if (state.uaccess) {
2566 WARN_FUNC("recursive UACCESS enable", sec, insn->offset);
2567 return 1;
2568 }
2569
2570 state.uaccess = true;
2571 break;
2572
2573 case INSN_CLAC:
2574 if (!state.uaccess && func) {
2575 WARN_FUNC("redundant UACCESS disable", sec, insn->offset);
2576 return 1;
2577 }
2578
2579 if (func_uaccess_safe(func) && !state.uaccess_stack) {
2580 WARN_FUNC("UACCESS-safe disables UACCESS", sec, insn->offset);
2581 return 1;
2582 }
2583
2584 state.uaccess = false;
2585 break;
2586
2587 case INSN_STD:
2588 if (state.df)
2589 WARN_FUNC("recursive STD", sec, insn->offset);
2590
2591 state.df = true;
2592 break;
2593
2594 case INSN_CLD:
2595 if (!state.df && func)
2596 WARN_FUNC("redundant CLD", sec, insn->offset);
2597
2598 state.df = false;
2599 break;
2600
2601 default:
2602 break;
2603 }
2604
2605 if (insn->dead_end)
2606 return 0;
2607
2608 if (!next_insn) {
2609 if (state.cfi.cfa.base == CFI_UNDEFINED)
2610 return 0;
2611 WARN("%s: unexpected end of section", sec->name);
2612 return 1;
2613 }
2614
2615 insn = next_insn;
2616 }
2617
2618 return 0;
2619}
2620
2621static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
2622{
2623 struct instruction *insn;
2624 struct insn_state state;
2625 int ret, warnings = 0;
2626
2627 if (!file->hints)
2628 return 0;
2629
2630 init_insn_state(&state, sec);
2631
2632 if (sec) {
2633 insn = find_insn(file, sec, 0);
2634 if (!insn)
2635 return 0;
2636 } else {
2637 insn = list_first_entry(&file->insn_list, typeof(*insn), list);
2638 }
2639
2640 while (&insn->list != &file->insn_list && (!sec || insn->sec == sec)) {
2641 if (insn->hint && !insn->visited) {
2642 ret = validate_branch(file, insn->func, insn, state);
2643 if (ret && backtrace)
2644 BT_FUNC("<=== (hint)", insn);
2645 warnings += ret;
2646 }
2647
2648 insn = list_next_entry(insn, list);
2649 }
2650
2651 return warnings;
2652}
2653
2654static int validate_retpoline(struct objtool_file *file)
2655{
2656 struct instruction *insn;
2657 int warnings = 0;
2658
2659 for_each_insn(file, insn) {
2660 if (insn->type != INSN_JUMP_DYNAMIC &&
2661 insn->type != INSN_CALL_DYNAMIC)
2662 continue;
2663
2664 if (insn->retpoline_safe)
2665 continue;
2666
2667
2668
2669
2670
2671
2672
2673 if (!strcmp(insn->sec->name, ".init.text") && !module)
2674 continue;
2675
2676 WARN_FUNC("indirect %s found in RETPOLINE build",
2677 insn->sec, insn->offset,
2678 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
2679
2680 warnings++;
2681 }
2682
2683 return warnings;
2684}
2685
2686static bool is_kasan_insn(struct instruction *insn)
2687{
2688 return (insn->type == INSN_CALL &&
2689 !strcmp(insn->call_dest->name, "__asan_handle_no_return"));
2690}
2691
2692static bool is_ubsan_insn(struct instruction *insn)
2693{
2694 return (insn->type == INSN_CALL &&
2695 !strcmp(insn->call_dest->name,
2696 "__ubsan_handle_builtin_unreachable"));
2697}
2698
2699static bool ignore_unreachable_insn(struct objtool_file *file, struct instruction *insn)
2700{
2701 int i;
2702 struct instruction *prev_insn;
2703
2704 if (insn->ignore || insn->type == INSN_NOP)
2705 return true;
2706
2707
2708
2709
2710
2711
2712
2713
2714 if (!strcmp(insn->sec->name, ".fixup") ||
2715 !strcmp(insn->sec->name, ".altinstr_replacement") ||
2716 !strcmp(insn->sec->name, ".altinstr_aux"))
2717 return true;
2718
2719 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->offset == FAKE_JUMP_OFFSET)
2720 return true;
2721
2722 if (!insn->func)
2723 return false;
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733 prev_insn = list_prev_entry(insn, list);
2734 if ((prev_insn->dead_end || dead_end_function(file, prev_insn->call_dest)) &&
2735 (insn->type == INSN_BUG ||
2736 (insn->type == INSN_JUMP_UNCONDITIONAL &&
2737 insn->jump_dest && insn->jump_dest->type == INSN_BUG)))
2738 return true;
2739
2740
2741
2742
2743
2744
2745
2746 for (i = 0; i < 5; i++) {
2747
2748 if (is_kasan_insn(insn) || is_ubsan_insn(insn))
2749 return true;
2750
2751 if (insn->type == INSN_JUMP_UNCONDITIONAL) {
2752 if (insn->jump_dest &&
2753 insn->jump_dest->func == insn->func) {
2754 insn = insn->jump_dest;
2755 continue;
2756 }
2757
2758 break;
2759 }
2760
2761 if (insn->offset + insn->len >= insn->func->offset + insn->func->len)
2762 break;
2763
2764 insn = list_next_entry(insn, list);
2765 }
2766
2767 return false;
2768}
2769
2770static int validate_symbol(struct objtool_file *file, struct section *sec,
2771 struct symbol *sym, struct insn_state *state)
2772{
2773 struct instruction *insn;
2774 int ret;
2775
2776 if (!sym->len) {
2777 WARN("%s() is missing an ELF size annotation", sym->name);
2778 return 1;
2779 }
2780
2781 if (sym->pfunc != sym || sym->alias != sym)
2782 return 0;
2783
2784 insn = find_insn(file, sec, sym->offset);
2785 if (!insn || insn->ignore || insn->visited)
2786 return 0;
2787
2788 state->uaccess = sym->uaccess_safe;
2789
2790 ret = validate_branch(file, insn->func, insn, *state);
2791 if (ret && backtrace)
2792 BT_FUNC("<=== (sym)", insn);
2793 return ret;
2794}
2795
2796static int validate_section(struct objtool_file *file, struct section *sec)
2797{
2798 struct insn_state state;
2799 struct symbol *func;
2800 int warnings = 0;
2801
2802 list_for_each_entry(func, &sec->symbol_list, list) {
2803 if (func->type != STT_FUNC)
2804 continue;
2805
2806 init_insn_state(&state, sec);
2807 state.cfi.cfa = initial_func_cfi.cfa;
2808 memcpy(&state.cfi.regs, &initial_func_cfi.regs,
2809 CFI_NUM_REGS * sizeof(struct cfi_reg));
2810 state.cfi.stack_size = initial_func_cfi.cfa.offset;
2811
2812 warnings += validate_symbol(file, sec, func, &state);
2813 }
2814
2815 return warnings;
2816}
2817
2818static int validate_vmlinux_functions(struct objtool_file *file)
2819{
2820 struct section *sec;
2821 int warnings = 0;
2822
2823 sec = find_section_by_name(file->elf, ".noinstr.text");
2824 if (sec) {
2825 warnings += validate_section(file, sec);
2826 warnings += validate_unwind_hints(file, sec);
2827 }
2828
2829 sec = find_section_by_name(file->elf, ".entry.text");
2830 if (sec) {
2831 warnings += validate_section(file, sec);
2832 warnings += validate_unwind_hints(file, sec);
2833 }
2834
2835 return warnings;
2836}
2837
2838static int validate_functions(struct objtool_file *file)
2839{
2840 struct section *sec;
2841 int warnings = 0;
2842
2843 for_each_sec(file, sec) {
2844 if (!(sec->sh.sh_flags & SHF_EXECINSTR))
2845 continue;
2846
2847 warnings += validate_section(file, sec);
2848 }
2849
2850 return warnings;
2851}
2852
2853static int validate_reachable_instructions(struct objtool_file *file)
2854{
2855 struct instruction *insn;
2856
2857 if (file->ignore_unreachables)
2858 return 0;
2859
2860 for_each_insn(file, insn) {
2861 if (insn->visited || ignore_unreachable_insn(file, insn))
2862 continue;
2863
2864 WARN_FUNC("unreachable instruction", insn->sec, insn->offset);
2865 return 1;
2866 }
2867
2868 return 0;
2869}
2870
2871int check(struct objtool_file *file)
2872{
2873 int ret, warnings = 0;
2874
2875 arch_initial_func_cfi_state(&initial_func_cfi);
2876
2877 ret = decode_sections(file);
2878 if (ret < 0)
2879 goto out;
2880 warnings += ret;
2881
2882 if (list_empty(&file->insn_list))
2883 goto out;
2884
2885 if (vmlinux && !validate_dup) {
2886 ret = validate_vmlinux_functions(file);
2887 if (ret < 0)
2888 goto out;
2889
2890 warnings += ret;
2891 goto out;
2892 }
2893
2894 if (retpoline) {
2895 ret = validate_retpoline(file);
2896 if (ret < 0)
2897 return ret;
2898 warnings += ret;
2899 }
2900
2901 ret = validate_functions(file);
2902 if (ret < 0)
2903 goto out;
2904 warnings += ret;
2905
2906 ret = validate_unwind_hints(file, NULL);
2907 if (ret < 0)
2908 goto out;
2909 warnings += ret;
2910
2911 if (!warnings) {
2912 ret = validate_reachable_instructions(file);
2913 if (ret < 0)
2914 goto out;
2915 warnings += ret;
2916 }
2917
2918 ret = create_static_call_sections(file);
2919 if (ret < 0)
2920 goto out;
2921 warnings += ret;
2922
2923out:
2924 if (ret < 0) {
2925
2926
2927
2928
2929
2930 return ret;
2931 }
2932
2933 return 0;
2934}
2935