]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - 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
CommitLineData
9ff8ff93
GKH
1From 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 Mon Sep 17 00:00:00 2001
2From: Josh Poimboeuf <jpoimboe@redhat.com>
3Date: Mon, 14 May 2018 08:53:24 -0500
4Subject: objtool: Detect RIP-relative switch table references
5
6From: Josh Poimboeuf <jpoimboe@redhat.com>
7
8commit 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 upstream.
9
10Typically a switch table can be found by detecting a .rodata access
11followed 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
19Randy Dunlap reported a case (seen with GCC 4.8) where the .rodata
20access 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
27In this case the relocation addend needs to be adjusted accordingly in
28order to find the location of the switch table.
29
30The fix is for case 3 (as described in the comments), but also make the
31existing case 1 & 2 checks more precise by only adjusting the addend for
32R_X86_64_PC32 relocations.
33
34This 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
39Reported-by: Randy Dunlap <rdunlap@infradead.org>
40Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
41Cc: Linus Torvalds <torvalds@linux-foundation.org>
42Cc: Peter Zijlstra <peterz@infradead.org>
43Cc: Thomas Gleixner <tglx@linutronix.de>
44Link: http://lkml.kernel.org/r/b6098294fd67afb69af8c47c9883d7a68bf0f8ea.1526305958.git.jpoimboe@redhat.com
45Signed-off-by: Ingo Molnar <mingo@kernel.org>
46Signed-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;