aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2013-01-11 07:15:35 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-02-14 09:55:03 -0500
commit083e14c09b7ae0247b9944a386fdc32cd0719da1 (patch)
tree0ad777d2fbe57289c011130a51478a108237c55b /arch/s390/kernel
parent4d334fd155b53adfe78393e66850ff4bb0aa8406 (diff)
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>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/module.c140
1 files changed, 89 insertions, 51 deletions
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index 4610deafd953..06f17311628a 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -65,8 +65,7 @@ void module_free(struct module *mod, void *module_region)
65 vfree(module_region); 65 vfree(module_region);
66} 66}
67 67
68static void 68static void check_rela(Elf_Rela *rela, struct module *me)
69check_rela(Elf_Rela *rela, struct module *me)
70{ 69{
71 struct mod_arch_syminfo *info; 70 struct mod_arch_syminfo *info;
72 71
@@ -115,9 +114,8 @@ check_rela(Elf_Rela *rela, struct module *me)
115 * Account for GOT and PLT relocations. We can't add sections for 114 * Account for GOT and PLT relocations. We can't add sections for
116 * got and plt but we can increase the core module size. 115 * got and plt but we can increase the core module size.
117 */ 116 */
118int 117int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
119module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, 118 char *secstrings, struct module *me)
120 char *secstrings, struct module *me)
121{ 119{
122 Elf_Shdr *symtab; 120 Elf_Shdr *symtab;
123 Elf_Sym *symbols; 121 Elf_Sym *symbols;
@@ -179,13 +177,52 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
179 return 0; 177 return 0;
180} 178}
181 179
182static int 180static int apply_rela_bits(Elf_Addr loc, Elf_Addr val,
183apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, 181 int sign, int bits, int shift)
184 struct module *me) 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
219static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
220 const char *strtab, struct module *me)
185{ 221{
186 struct mod_arch_syminfo *info; 222 struct mod_arch_syminfo *info;
187 Elf_Addr loc, val; 223 Elf_Addr loc, val;
188 int r_type, r_sym; 224 int r_type, r_sym;
225 int rc;
189 226
190 /* This is where to make the change */ 227 /* This is where to make the change */
191 loc = base + rela->r_offset; 228 loc = base + rela->r_offset;
@@ -205,20 +242,17 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
205 case R_390_64: /* Direct 64 bit. */ 242 case R_390_64: /* Direct 64 bit. */
206 val += rela->r_addend; 243 val += rela->r_addend;
207 if (r_type == R_390_8) 244 if (r_type == R_390_8)
208 *(unsigned char *) loc = val; 245 rc = apply_rela_bits(loc, val, 0, 8, 0);
209 else if (r_type == R_390_12) 246 else if (r_type == R_390_12)
210 *(unsigned short *) loc = (val & 0xfff) | 247 rc = apply_rela_bits(loc, val, 0, 12, 0);
211 (*(unsigned short *) loc & 0xf000);
212 else if (r_type == R_390_16) 248 else if (r_type == R_390_16)
213 *(unsigned short *) loc = val; 249 rc = apply_rela_bits(loc, val, 0, 16, 0);
214 else if (r_type == R_390_20) 250 else if (r_type == R_390_20)
215 *(unsigned int *) loc = 251 rc = apply_rela_bits(loc, val, 1, 20, 0);
216 (*(unsigned int *) loc & 0xf00000ff) |
217 (val & 0xfff) << 16 | (val & 0xff000) >> 4;
218 else if (r_type == R_390_32) 252 else if (r_type == R_390_32)
219 *(unsigned int *) loc = val; 253 rc = apply_rela_bits(loc, val, 0, 32, 0);
220 else if (r_type == R_390_64) 254 else if (r_type == R_390_64)
221 *(unsigned long *) loc = val; 255 rc = apply_rela_bits(loc, val, 0, 64, 0);
222 break; 256 break;
223 case R_390_PC16: /* PC relative 16 bit. */ 257 case R_390_PC16: /* PC relative 16 bit. */
224 case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */ 258 case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */
@@ -227,15 +261,15 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
227 case R_390_PC64: /* PC relative 64 bit. */ 261 case R_390_PC64: /* PC relative 64 bit. */
228 val += rela->r_addend - loc; 262 val += rela->r_addend - loc;
229 if (r_type == R_390_PC16) 263 if (r_type == R_390_PC16)
230 *(unsigned short *) loc = val; 264 rc = apply_rela_bits(loc, val, 1, 16, 0);
231 else if (r_type == R_390_PC16DBL) 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 else if (r_type == R_390_PC32DBL) 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 else if (r_type == R_390_PC32) 269 else if (r_type == R_390_PC32)
236 *(unsigned int *) loc = val; 270 rc = apply_rela_bits(loc, val, 1, 32, 0);
237 else if (r_type == R_390_PC64) 271 else if (r_type == R_390_PC64)
238 *(unsigned long *) loc = val; 272 rc = apply_rela_bits(loc, val, 1, 64, 0);
239 break; 273 break;
240 case R_390_GOT12: /* 12 bit GOT offset. */ 274 case R_390_GOT12: /* 12 bit GOT offset. */
241 case R_390_GOT16: /* 16 bit GOT offset. */ 275 case R_390_GOT16: /* 16 bit GOT offset. */
@@ -260,26 +294,24 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
260 val = info->got_offset + rela->r_addend; 294 val = info->got_offset + rela->r_addend;
261 if (r_type == R_390_GOT12 || 295 if (r_type == R_390_GOT12 ||
262 r_type == R_390_GOTPLT12) 296 r_type == R_390_GOTPLT12)
263 *(unsigned short *) loc = (val & 0xfff) | 297 rc = apply_rela_bits(loc, val, 0, 12, 0);
264 (*(unsigned short *) loc & 0xf000);
265 else if (r_type == R_390_GOT16 || 298 else if (r_type == R_390_GOT16 ||
266 r_type == R_390_GOTPLT16) 299 r_type == R_390_GOTPLT16)
267 *(unsigned short *) loc = val; 300 rc = apply_rela_bits(loc, val, 0, 16, 0);
268 else if (r_type == R_390_GOT20 || 301 else if (r_type == R_390_GOT20 ||
269 r_type == R_390_GOTPLT20) 302 r_type == R_390_GOTPLT20)
270 *(unsigned int *) loc = 303 rc = apply_rela_bits(loc, val, 1, 20, 0);
271 (*(unsigned int *) loc & 0xf00000ff) |
272 (val & 0xfff) << 16 | (val & 0xff000) >> 4;
273 else if (r_type == R_390_GOT32 || 304 else if (r_type == R_390_GOT32 ||
274 r_type == R_390_GOTPLT32) 305 r_type == R_390_GOTPLT32)
275 *(unsigned int *) loc = val; 306 rc = apply_rela_bits(loc, val, 0, 32, 0);
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;
280 else if (r_type == R_390_GOT64 || 307 else if (r_type == R_390_GOT64 ||
281 r_type == R_390_GOTPLT64) 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 break; 315 break;
284 case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */ 316 case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
285 case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */ 317 case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
@@ -321,17 +353,17 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
321 val += rela->r_addend - loc; 353 val += rela->r_addend - loc;
322 } 354 }
323 if (r_type == R_390_PLT16DBL) 355 if (r_type == R_390_PLT16DBL)
324 *(unsigned short *) loc = val >> 1; 356 rc = apply_rela_bits(loc, val, 1, 16, 1);
325 else if (r_type == R_390_PLTOFF16) 357 else if (r_type == R_390_PLTOFF16)
326 *(unsigned short *) loc = val; 358 rc = apply_rela_bits(loc, val, 0, 16, 0);
327 else if (r_type == R_390_PLT32DBL) 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 else if (r_type == R_390_PLT32 || 361 else if (r_type == R_390_PLT32 ||
330 r_type == R_390_PLTOFF32) 362 r_type == R_390_PLTOFF32)
331 *(unsigned int *) loc = val; 363 rc = apply_rela_bits(loc, val, 0, 32, 0);
332 else if (r_type == R_390_PLT64 || 364 else if (r_type == R_390_PLT64 ||
333 r_type == R_390_PLTOFF64) 365 r_type == R_390_PLTOFF64)
334 *(unsigned long *) loc = val; 366 rc = apply_rela_bits(loc, val, 0, 64, 0);
335 break; 367 break;
336 case R_390_GOTOFF16: /* 16 bit offset to GOT. */ 368 case R_390_GOTOFF16: /* 16 bit offset to GOT. */
337 case R_390_GOTOFF32: /* 32 bit offset to GOT. */ 369 case R_390_GOTOFF32: /* 32 bit offset to GOT. */
@@ -339,20 +371,20 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
339 val = val + rela->r_addend - 371 val = val + rela->r_addend -
340 ((Elf_Addr) me->module_core + me->arch.got_offset); 372 ((Elf_Addr) me->module_core + me->arch.got_offset);
341 if (r_type == R_390_GOTOFF16) 373 if (r_type == R_390_GOTOFF16)
342 *(unsigned short *) loc = val; 374 rc = apply_rela_bits(loc, val, 0, 16, 0);
343 else if (r_type == R_390_GOTOFF32) 375 else if (r_type == R_390_GOTOFF32)
344 *(unsigned int *) loc = val; 376 rc = apply_rela_bits(loc, val, 0, 32, 0);
345 else if (r_type == R_390_GOTOFF64) 377 else if (r_type == R_390_GOTOFF64)
346 *(unsigned long *) loc = val; 378 rc = apply_rela_bits(loc, val, 0, 64, 0);
347 break; 379 break;
348 case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */ 380 case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
349 case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */ 381 case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
350 val = (Elf_Addr) me->module_core + me->arch.got_offset + 382 val = (Elf_Addr) me->module_core + me->arch.got_offset +
351 rela->r_addend - loc; 383 rela->r_addend - loc;
352 if (r_type == R_390_GOTPC) 384 if (r_type == R_390_GOTPC)
353 *(unsigned int *) loc = val; 385 rc = apply_rela_bits(loc, val, 1, 32, 0);
354 else if (r_type == R_390_GOTPCDBL) 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 break; 388 break;
357 case R_390_COPY: 389 case R_390_COPY:
358 case R_390_GLOB_DAT: /* Create GOT entry. */ 390 case R_390_GLOB_DAT: /* Create GOT entry. */
@@ -360,19 +392,25 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
360 case R_390_RELATIVE: /* Adjust by program base. */ 392 case R_390_RELATIVE: /* Adjust by program base. */
361 /* Only needed if we want to support loading of 393 /* Only needed if we want to support loading of
362 modules linked with -shared. */ 394 modules linked with -shared. */
363 break; 395 return -ENOEXEC;
364 default: 396 default:
365 printk(KERN_ERR "module %s: Unknown relocation: %u\n", 397 printk(KERN_ERR "module %s: unknown relocation: %u\n",
366 me->name, r_type); 398 me->name, r_type);
367 return -ENOEXEC; 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 return 0; 408 return 0;
370} 409}
371 410
372int 411int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
373apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, 412 unsigned int symindex, unsigned int relsec,
374 unsigned int symindex, unsigned int relsec, 413 struct module *me)
375 struct module *me)
376{ 414{
377 Elf_Addr base; 415 Elf_Addr base;
378 Elf_Sym *symtab; 416 Elf_Sym *symtab;
@@ -388,7 +426,7 @@ apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
388 n = sechdrs[relsec].sh_size / sizeof(Elf_Rela); 426 n = sechdrs[relsec].sh_size / sizeof(Elf_Rela);
389 427
390 for (i = 0; i < n; i++, rela++) { 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 if (rc) 430 if (rc)
393 return rc; 431 return rc;
394 } 432 }