Commit 083e14c09b7ae0247b9944a386fdc32cd0719da1
1 parent
4d334fd155
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
s390/modules: add relocation overflow checking
Given enough debug options some modules can grow large enough that the GOT table gets bigger than 4K. On s390 the modules are compiled with -fpic which limits the GOT to 4K. The end result is a module that is loaded but won't work. Add a sanity check to apply_rela and return with an error if a relocation error is detected for a module. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Showing 1 changed file with 89 additions and 51 deletions Side-by-side Diff
arch/s390/kernel/module.c
... | ... | @@ -65,8 +65,7 @@ |
65 | 65 | vfree(module_region); |
66 | 66 | } |
67 | 67 | |
68 | -static void | |
69 | -check_rela(Elf_Rela *rela, struct module *me) | |
68 | +static void check_rela(Elf_Rela *rela, struct module *me) | |
70 | 69 | { |
71 | 70 | struct mod_arch_syminfo *info; |
72 | 71 | |
... | ... | @@ -115,9 +114,8 @@ |
115 | 114 | * Account for GOT and PLT relocations. We can't add sections for |
116 | 115 | * got and plt but we can increase the core module size. |
117 | 116 | */ |
118 | -int | |
119 | -module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, | |
120 | - char *secstrings, struct module *me) | |
117 | +int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, | |
118 | + char *secstrings, struct module *me) | |
121 | 119 | { |
122 | 120 | Elf_Shdr *symtab; |
123 | 121 | Elf_Sym *symbols; |
124 | 122 | |
125 | 123 | |
... | ... | @@ -179,13 +177,52 @@ |
179 | 177 | return 0; |
180 | 178 | } |
181 | 179 | |
182 | -static int | |
183 | -apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, | |
184 | - struct module *me) | |
180 | +static int apply_rela_bits(Elf_Addr loc, Elf_Addr val, | |
181 | + int sign, int bits, int shift) | |
185 | 182 | { |
183 | + unsigned long umax; | |
184 | + long min, max; | |
185 | + | |
186 | + if (val & ((1UL << shift) - 1)) | |
187 | + return -ENOEXEC; | |
188 | + if (sign) { | |
189 | + val = (Elf_Addr)(((long) val) >> shift); | |
190 | + min = -(1L << (bits - 1)); | |
191 | + max = (1L << (bits - 1)) - 1; | |
192 | + if ((long) val < min || (long) val > max) | |
193 | + return -ENOEXEC; | |
194 | + } else { | |
195 | + val >>= shift; | |
196 | + umax = ((1UL << (bits - 1)) << 1) - 1; | |
197 | + if ((unsigned long) val > umax) | |
198 | + return -ENOEXEC; | |
199 | + } | |
200 | + | |
201 | + if (bits == 8) | |
202 | + *(unsigned char *) loc = val; | |
203 | + else if (bits == 12) | |
204 | + *(unsigned short *) loc = (val & 0xfff) | | |
205 | + (*(unsigned short *) loc & 0xf000); | |
206 | + else if (bits == 16) | |
207 | + *(unsigned short *) loc = val; | |
208 | + else if (bits == 20) | |
209 | + *(unsigned int *) loc = (val & 0xfff) << 16 | | |
210 | + (val & 0xff000) >> 4 | | |
211 | + (*(unsigned int *) loc & 0xf00000ff); | |
212 | + else if (bits == 32) | |
213 | + *(unsigned int *) loc = val; | |
214 | + else if (bits == 64) | |
215 | + *(unsigned long *) loc = val; | |
216 | + return 0; | |
217 | +} | |
218 | + | |
219 | +static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, | |
220 | + const char *strtab, struct module *me) | |
221 | +{ | |
186 | 222 | struct mod_arch_syminfo *info; |
187 | 223 | Elf_Addr loc, val; |
188 | 224 | int r_type, r_sym; |
225 | + int rc; | |
189 | 226 | |
190 | 227 | /* This is where to make the change */ |
191 | 228 | loc = base + rela->r_offset; |
192 | 229 | |
193 | 230 | |
194 | 231 | |
195 | 232 | |
196 | 233 | |
... | ... | @@ -205,20 +242,17 @@ |
205 | 242 | case R_390_64: /* Direct 64 bit. */ |
206 | 243 | val += rela->r_addend; |
207 | 244 | if (r_type == R_390_8) |
208 | - *(unsigned char *) loc = val; | |
245 | + rc = apply_rela_bits(loc, val, 0, 8, 0); | |
209 | 246 | else if (r_type == R_390_12) |
210 | - *(unsigned short *) loc = (val & 0xfff) | | |
211 | - (*(unsigned short *) loc & 0xf000); | |
247 | + rc = apply_rela_bits(loc, val, 0, 12, 0); | |
212 | 248 | else if (r_type == R_390_16) |
213 | - *(unsigned short *) loc = val; | |
249 | + rc = apply_rela_bits(loc, val, 0, 16, 0); | |
214 | 250 | else if (r_type == R_390_20) |
215 | - *(unsigned int *) loc = | |
216 | - (*(unsigned int *) loc & 0xf00000ff) | | |
217 | - (val & 0xfff) << 16 | (val & 0xff000) >> 4; | |
251 | + rc = apply_rela_bits(loc, val, 1, 20, 0); | |
218 | 252 | else if (r_type == R_390_32) |
219 | - *(unsigned int *) loc = val; | |
253 | + rc = apply_rela_bits(loc, val, 0, 32, 0); | |
220 | 254 | else if (r_type == R_390_64) |
221 | - *(unsigned long *) loc = val; | |
255 | + rc = apply_rela_bits(loc, val, 0, 64, 0); | |
222 | 256 | break; |
223 | 257 | case R_390_PC16: /* PC relative 16 bit. */ |
224 | 258 | case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */ |
225 | 259 | |
226 | 260 | |
227 | 261 | |
228 | 262 | |
... | ... | @@ -227,15 +261,15 @@ |
227 | 261 | case R_390_PC64: /* PC relative 64 bit. */ |
228 | 262 | val += rela->r_addend - loc; |
229 | 263 | if (r_type == R_390_PC16) |
230 | - *(unsigned short *) loc = val; | |
264 | + rc = apply_rela_bits(loc, val, 1, 16, 0); | |
231 | 265 | else if (r_type == R_390_PC16DBL) |
232 | - *(unsigned short *) loc = val >> 1; | |
266 | + rc = apply_rela_bits(loc, val, 1, 16, 1); | |
233 | 267 | else if (r_type == R_390_PC32DBL) |
234 | - *(unsigned int *) loc = val >> 1; | |
268 | + rc = apply_rela_bits(loc, val, 1, 32, 1); | |
235 | 269 | else if (r_type == R_390_PC32) |
236 | - *(unsigned int *) loc = val; | |
270 | + rc = apply_rela_bits(loc, val, 1, 32, 0); | |
237 | 271 | else if (r_type == R_390_PC64) |
238 | - *(unsigned long *) loc = val; | |
272 | + rc = apply_rela_bits(loc, val, 1, 64, 0); | |
239 | 273 | break; |
240 | 274 | case R_390_GOT12: /* 12 bit GOT offset. */ |
241 | 275 | case R_390_GOT16: /* 16 bit GOT offset. */ |
242 | 276 | |
243 | 277 | |
244 | 278 | |
245 | 279 | |
... | ... | @@ -260,26 +294,24 @@ |
260 | 294 | val = info->got_offset + rela->r_addend; |
261 | 295 | if (r_type == R_390_GOT12 || |
262 | 296 | r_type == R_390_GOTPLT12) |
263 | - *(unsigned short *) loc = (val & 0xfff) | | |
264 | - (*(unsigned short *) loc & 0xf000); | |
297 | + rc = apply_rela_bits(loc, val, 0, 12, 0); | |
265 | 298 | else if (r_type == R_390_GOT16 || |
266 | 299 | r_type == R_390_GOTPLT16) |
267 | - *(unsigned short *) loc = val; | |
300 | + rc = apply_rela_bits(loc, val, 0, 16, 0); | |
268 | 301 | else if (r_type == R_390_GOT20 || |
269 | 302 | r_type == R_390_GOTPLT20) |
270 | - *(unsigned int *) loc = | |
271 | - (*(unsigned int *) loc & 0xf00000ff) | | |
272 | - (val & 0xfff) << 16 | (val & 0xff000) >> 4; | |
303 | + rc = apply_rela_bits(loc, val, 1, 20, 0); | |
273 | 304 | else if (r_type == R_390_GOT32 || |
274 | 305 | r_type == R_390_GOTPLT32) |
275 | - *(unsigned int *) loc = val; | |
276 | - else if (r_type == R_390_GOTENT || | |
277 | - r_type == R_390_GOTPLTENT) | |
278 | - *(unsigned int *) loc = | |
279 | - (val + (Elf_Addr) me->module_core - loc) >> 1; | |
306 | + rc = apply_rela_bits(loc, val, 0, 32, 0); | |
280 | 307 | else if (r_type == R_390_GOT64 || |
281 | 308 | r_type == R_390_GOTPLT64) |
282 | - *(unsigned long *) loc = val; | |
309 | + rc = apply_rela_bits(loc, val, 0, 64, 0); | |
310 | + else if (r_type == R_390_GOTENT || | |
311 | + r_type == R_390_GOTPLTENT) { | |
312 | + val += (Elf_Addr) me->module_core - loc; | |
313 | + rc = apply_rela_bits(loc, val, 1, 32, 1); | |
314 | + } | |
283 | 315 | break; |
284 | 316 | case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */ |
285 | 317 | case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */ |
286 | 318 | |
287 | 319 | |
288 | 320 | |
289 | 321 | |
... | ... | @@ -321,17 +353,17 @@ |
321 | 353 | val += rela->r_addend - loc; |
322 | 354 | } |
323 | 355 | if (r_type == R_390_PLT16DBL) |
324 | - *(unsigned short *) loc = val >> 1; | |
356 | + rc = apply_rela_bits(loc, val, 1, 16, 1); | |
325 | 357 | else if (r_type == R_390_PLTOFF16) |
326 | - *(unsigned short *) loc = val; | |
358 | + rc = apply_rela_bits(loc, val, 0, 16, 0); | |
327 | 359 | else if (r_type == R_390_PLT32DBL) |
328 | - *(unsigned int *) loc = val >> 1; | |
360 | + rc = apply_rela_bits(loc, val, 1, 32, 1); | |
329 | 361 | else if (r_type == R_390_PLT32 || |
330 | 362 | r_type == R_390_PLTOFF32) |
331 | - *(unsigned int *) loc = val; | |
363 | + rc = apply_rela_bits(loc, val, 0, 32, 0); | |
332 | 364 | else if (r_type == R_390_PLT64 || |
333 | 365 | r_type == R_390_PLTOFF64) |
334 | - *(unsigned long *) loc = val; | |
366 | + rc = apply_rela_bits(loc, val, 0, 64, 0); | |
335 | 367 | break; |
336 | 368 | case R_390_GOTOFF16: /* 16 bit offset to GOT. */ |
337 | 369 | case R_390_GOTOFF32: /* 32 bit offset to GOT. */ |
338 | 370 | |
339 | 371 | |
340 | 372 | |
341 | 373 | |
... | ... | @@ -339,20 +371,20 @@ |
339 | 371 | val = val + rela->r_addend - |
340 | 372 | ((Elf_Addr) me->module_core + me->arch.got_offset); |
341 | 373 | if (r_type == R_390_GOTOFF16) |
342 | - *(unsigned short *) loc = val; | |
374 | + rc = apply_rela_bits(loc, val, 0, 16, 0); | |
343 | 375 | else if (r_type == R_390_GOTOFF32) |
344 | - *(unsigned int *) loc = val; | |
376 | + rc = apply_rela_bits(loc, val, 0, 32, 0); | |
345 | 377 | else if (r_type == R_390_GOTOFF64) |
346 | - *(unsigned long *) loc = val; | |
378 | + rc = apply_rela_bits(loc, val, 0, 64, 0); | |
347 | 379 | break; |
348 | 380 | case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */ |
349 | 381 | case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */ |
350 | 382 | val = (Elf_Addr) me->module_core + me->arch.got_offset + |
351 | 383 | rela->r_addend - loc; |
352 | 384 | if (r_type == R_390_GOTPC) |
353 | - *(unsigned int *) loc = val; | |
385 | + rc = apply_rela_bits(loc, val, 1, 32, 0); | |
354 | 386 | else if (r_type == R_390_GOTPCDBL) |
355 | - *(unsigned int *) loc = val >> 1; | |
387 | + rc = apply_rela_bits(loc, val, 1, 32, 1); | |
356 | 388 | break; |
357 | 389 | case R_390_COPY: |
358 | 390 | case R_390_GLOB_DAT: /* Create GOT entry. */ |
359 | 391 | |
360 | 392 | |
361 | 393 | |
... | ... | @@ -360,19 +392,25 @@ |
360 | 392 | case R_390_RELATIVE: /* Adjust by program base. */ |
361 | 393 | /* Only needed if we want to support loading of |
362 | 394 | modules linked with -shared. */ |
363 | - break; | |
395 | + return -ENOEXEC; | |
364 | 396 | default: |
365 | - printk(KERN_ERR "module %s: Unknown relocation: %u\n", | |
397 | + printk(KERN_ERR "module %s: unknown relocation: %u\n", | |
366 | 398 | me->name, r_type); |
367 | 399 | return -ENOEXEC; |
368 | 400 | } |
401 | + if (rc) { | |
402 | + printk(KERN_ERR "module %s: relocation error for symbol %s " | |
403 | + "(r_type %i, value 0x%lx)\n", | |
404 | + me->name, strtab + symtab[r_sym].st_name, | |
405 | + r_type, (unsigned long) val); | |
406 | + return rc; | |
407 | + } | |
369 | 408 | return 0; |
370 | 409 | } |
371 | 410 | |
372 | -int | |
373 | -apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, | |
374 | - unsigned int symindex, unsigned int relsec, | |
375 | - struct module *me) | |
411 | +int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, | |
412 | + unsigned int symindex, unsigned int relsec, | |
413 | + struct module *me) | |
376 | 414 | { |
377 | 415 | Elf_Addr base; |
378 | 416 | Elf_Sym *symtab; |
... | ... | @@ -388,7 +426,7 @@ |
388 | 426 | n = sechdrs[relsec].sh_size / sizeof(Elf_Rela); |
389 | 427 | |
390 | 428 | for (i = 0; i < n; i++, rela++) { |
391 | - rc = apply_rela(rela, base, symtab, me); | |
429 | + rc = apply_rela(rela, base, symtab, strtab, me); | |
392 | 430 | if (rc) |
393 | 431 | return rc; |
394 | 432 | } |