]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.14.48/objtool-detect-rip-relative-switch-table-references.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.14.48 / objtool-detect-rip-relative-switch-table-references.patch
1 From 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 Mon Sep 17 00:00:00 2001
2 From: Josh Poimboeuf <jpoimboe@redhat.com>
3 Date: Mon, 14 May 2018 08:53:24 -0500
4 Subject: objtool: Detect RIP-relative switch table references
5
6 From: Josh Poimboeuf <jpoimboe@redhat.com>
7
8 commit 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 upstream.
9
10 Typically a switch table can be found by detecting a .rodata access
11 followed an indirect jump:
12
13 1969: 4a 8b 0c e5 00 00 00 mov 0x0(,%r12,8),%rcx
14 1970: 00
15 196d: R_X86_64_32S .rodata+0x438
16 1971: e9 00 00 00 00 jmpq 1976 <dispc_runtime_suspend+0xb6a>
17 1972: R_X86_64_PC32 __x86_indirect_thunk_rcx-0x4
18
19 Randy Dunlap reported a case (seen with GCC 4.8) where the .rodata
20 access uses RIP-relative addressing:
21
22 19bd: 48 8b 3d 00 00 00 00 mov 0x0(%rip),%rdi # 19c4 <dispc_runtime_suspend+0xbb8>
23 19c0: R_X86_64_PC32 .rodata+0x45c
24 19c4: e9 00 00 00 00 jmpq 19c9 <dispc_runtime_suspend+0xbbd>
25 19c5: R_X86_64_PC32 __x86_indirect_thunk_rdi-0x4
26
27 In this case the relocation addend needs to be adjusted accordingly in
28 order to find the location of the switch table.
29
30 The fix is for case 3 (as described in the comments), but also make the
31 existing case 1 & 2 checks more precise by only adjusting the addend for
32 R_X86_64_PC32 relocations.
33
34 This fixes the following warnings:
35
36 drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_suspend()+0xbb8: sibling call from callable instruction with modified stack frame
37 drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_resume()+0xcc5: sibling call from callable instruction with modified stack frame
38
39 Reported-by: Randy Dunlap <rdunlap@infradead.org>
40 Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
41 Cc: Linus Torvalds <torvalds@linux-foundation.org>
42 Cc: Peter Zijlstra <peterz@infradead.org>
43 Cc: Thomas Gleixner <tglx@linutronix.de>
44 Link: http://lkml.kernel.org/r/b6098294fd67afb69af8c47c9883d7a68bf0f8ea.1526305958.git.jpoimboe@redhat.com
45 Signed-off-by: Ingo Molnar <mingo@kernel.org>
46 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
47
48 ---
49 tools/objtool/check.c | 33 ++++++++++++++++++---------------
50 1 file changed, 18 insertions(+), 15 deletions(-)
51
52 --- a/tools/objtool/check.c
53 +++ b/tools/objtool/check.c
54 @@ -898,24 +898,24 @@ static struct rela *find_switch_table(st
55 {
56 struct rela *text_rela, *rodata_rela;
57 struct instruction *orig_insn = insn;
58 + unsigned long table_offset;
59
60 + /* case 1 & 2 */
61 text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
62 if (text_rela && text_rela->sym == file->rodata->sym &&
63 !find_symbol_containing(file->rodata, text_rela->addend)) {
64
65 - /* case 1 */
66 - rodata_rela = find_rela_by_dest(file->rodata,
67 - text_rela->addend);
68 - if (rodata_rela)
69 - return rodata_rela;
70 + table_offset = text_rela->addend;
71 + if (text_rela->type == R_X86_64_PC32) {
72 + /* case 2 */
73 + table_offset += 4;
74 + file->ignore_unreachables = true;
75 + }
76
77 - /* case 2 */
78 - rodata_rela = find_rela_by_dest(file->rodata,
79 - text_rela->addend + 4);
80 + rodata_rela = find_rela_by_dest(file->rodata, table_offset);
81 if (!rodata_rela)
82 return NULL;
83
84 - file->ignore_unreachables = true;
85 return rodata_rela;
86 }
87
88 @@ -949,18 +949,21 @@ static struct rela *find_switch_table(st
89 if (!text_rela || text_rela->sym != file->rodata->sym)
90 continue;
91
92 + table_offset = text_rela->addend;
93 + if (text_rela->type == R_X86_64_PC32)
94 + table_offset += 4;
95 +
96 /*
97 * Make sure the .rodata address isn't associated with a
98 * symbol. gcc jump tables are anonymous data.
99 */
100 - if (find_symbol_containing(file->rodata, text_rela->addend))
101 + if (find_symbol_containing(file->rodata, table_offset))
102 continue;
103
104 - rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend);
105 - if (!rodata_rela)
106 - continue;
107 -
108 - return rodata_rela;
109 + /* mov [rodata addr], %reg */
110 + rodata_rela = find_rela_by_dest(file->rodata, table_offset);
111 + if (rodata_rela)
112 + return rodata_rela;
113 }
114
115 return NULL;