aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2017-11-03 08:58:54 -0400
committerIngo Molnar <mingo@kernel.org>2017-11-05 03:52:16 -0500
commiteda9cec4c9a12208a6f69fbe68f72a6311d50032 (patch)
tree36d9d40657db3ee47c3c38f9d255b6e763539628
parent675357362aeba19688440eb1aaa7991067f73b12 (diff)
x86/module: Detect and skip invalid relocations
There have been some cases where external tooling (e.g., kpatch-build) creates a corrupt relocation which targets the wrong address. This is a silent failure which can corrupt memory in unexpected places. On x86, the bytes of data being overwritten by relocations are always initialized to zero beforehand. Use that knowledge to add sanity checks to detect such cases before they corrupt memory. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: jeyu@kernel.org Cc: live-patching@vger.kernel.org Link: http://lkml.kernel.org/r/37450d6c6225e54db107fba447ce9e56e5f758e9.1509713553.git.jpoimboe@redhat.com [ Restructured the messages, as it's unclear whether the relocation or the target is corrupted. ] Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/kernel/module.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index 62e7d70aadd5..da0c160e5589 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -172,19 +172,27 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
172 case R_X86_64_NONE: 172 case R_X86_64_NONE:
173 break; 173 break;
174 case R_X86_64_64: 174 case R_X86_64_64:
175 if (*(u64 *)loc != 0)
176 goto invalid_relocation;
175 *(u64 *)loc = val; 177 *(u64 *)loc = val;
176 break; 178 break;
177 case R_X86_64_32: 179 case R_X86_64_32:
180 if (*(u32 *)loc != 0)
181 goto invalid_relocation;
178 *(u32 *)loc = val; 182 *(u32 *)loc = val;
179 if (val != *(u32 *)loc) 183 if (val != *(u32 *)loc)
180 goto overflow; 184 goto overflow;
181 break; 185 break;
182 case R_X86_64_32S: 186 case R_X86_64_32S:
187 if (*(s32 *)loc != 0)
188 goto invalid_relocation;
183 *(s32 *)loc = val; 189 *(s32 *)loc = val;
184 if ((s64)val != *(s32 *)loc) 190 if ((s64)val != *(s32 *)loc)
185 goto overflow; 191 goto overflow;
186 break; 192 break;
187 case R_X86_64_PC32: 193 case R_X86_64_PC32:
194 if (*(u32 *)loc != 0)
195 goto invalid_relocation;
188 val -= (u64)loc; 196 val -= (u64)loc;
189 *(u32 *)loc = val; 197 *(u32 *)loc = val;
190#if 0 198#if 0
@@ -200,6 +208,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
200 } 208 }
201 return 0; 209 return 0;
202 210
211invalid_relocation:
212 pr_err("x86/modules: Skipping invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
213 (int)ELF64_R_TYPE(rel[i].r_info), loc, val);
214 return -ENOEXEC;
215
203overflow: 216overflow:
204 pr_err("overflow in relocation type %d val %Lx\n", 217 pr_err("overflow in relocation type %d val %Lx\n",
205 (int)ELF64_R_TYPE(rel[i].r_info), val); 218 (int)ELF64_R_TYPE(rel[i].r_info), val);