1 /*
2 ** relinject.c for libelfsh
3 **
4 ** Original SPARC relocation function by thegrugq
5 **
6 ** Started on Fri Mar 28 14:55:37 2003 mayhem
7 ** Last update Thu Aug 21 03:33:53 2003 mayhem
8 */
9 #include "libelfsh.h"
10
11
12
13 /* Perform relocation on entry for INTEL architecture */
elfsh_relocate_i386(elfshsect_t * new,Elf32_Rel * cur,u_long * dword,u_long addr)14 static int elfsh_relocate_i386(elfshsect_t *new,
15 Elf32_Rel *cur,
16 u_long *dword,
17 u_long addr)
18 {
19 switch (elfsh_get_reltype(cur))
20 {
21
22 /* Absolute reference */
23 case R_386_32:
24 *dword = addr;
25 break;
26
27 /* Relative reference */
28 case R_386_PC32:
29 *dword = addr - (new->shdr->sh_addr + cur->r_offset + sizeof(u_long));
30 break;
31
32 default:
33 ELFSH_SETERROR("[libelfsh:relocate_etrel_section] "
34 "Unsupported relocation type\n", -1);
35 }
36 return (0);
37 }
38
39
40
41 /* Perform relocation on entry for SPARC architecture */
elfsh_relocate_sparc(elfshsect_t * new,Elf32_Rela * cur,u_long * dword,u_long addr)42 static int elfsh_relocate_sparc(elfshsect_t * new,
43 Elf32_Rela * cur,
44 u_long * dword,
45 u_long addr)
46 {
47 int retval;
48 u_long result;
49
50 #define ADD (cur->r_addend)
51 #define BAS (elfsh_get_object_baseaddr(new->parent))
52 #define GOT 0 /* GOT isn't available ... */
53 #define PLT 0 /* PLT isn't available ... */
54 #define PLA (new->shdr->sh_addr + cur->r_offset)
55 #define SYM (addr)
56
57 #define VERIFY8(x) (((x) & (0xFFFFFFFF << 8)) ? 1 : 0)
58 #define VERIFY13(x) (((x) & (0xFFFFFFFF << 13)) ? 1 : 0)
59 #define VERIFY16(x) (((x) & (0xFFFFFFFF << 16)) ? 1 : 0)
60 #define VERIFY22(x) (((x) & (0xFFFFFFFF << 22)) ? 1 : 0)
61 #define VERIFY30(x) (((x) & (0xFFFFFFFF << 30)) ? 1 : 0)
62 #define VERIFY32(x) (((x) & (0xFFFFFFFF << 0)) ? 1 : 0)
63
64 #define TRUNCATE8(x) ((x) & ~(0xFFFFFFFF << 8))
65 #define TRUNCATE13(x) ((x) & ~(0xFFFFFFFF << 13))
66 #define TRUNCATE16(x) ((x) & ~(0xFFFFFFFF << 16))
67 #define TRUNCATE22(x) ((x) & ~(0xFFFFFFFF << 22))
68 #define TRUNCATE30(x) ((x) & ~(0xFFFFFFFF << 30))
69 #define TRUNCATE32(x) (x) /* XXX just assume its 32bit */
70
71 retval = result = 0;
72 switch (elfsh_get_reltype((Elf32_Rel *)cur))
73 {
74 case R_SPARC_NONE:
75 break;
76 case R_SPARC_8:
77 result = SYM + ADD;
78 if (VERIFY8(result))
79 ; // XXX error condition.
80 break;
81 case R_SPARC_16:
82 result = SYM + ADD;
83 if (VERIFY16(result))
84 ; // XXX error condition
85 break;
86 case R_SPARC_32:
87 result = SYM + ADD;
88 if (VERIFY32(result))
89 ; // XXX error condition
90 break;
91 case R_SPARC_DISP8:
92 result = SYM + ADD - PLA;
93 if (VERIFY8(result))
94 ; // XXX error condition
95 break;
96 case R_SPARC_DISP16:
97 result = SYM + ADD - PLA;
98 if (VERIFY16(result))
99 ; // XXX error condition
100 break;
101 case R_SPARC_DISP32:
102 result = SYM + ADD - PLA;
103 if (VERIFY32(result))
104 ; // XXX error condition
105 break;
106 case R_SPARC_WDISP30:
107 result = (SYM + ADD - PLA) >> 2;
108 if (VERIFY30(result))
109 ; // XXX error condition
110 break;
111 case R_SPARC_WDISP22:
112 result = (SYM + ADD - PLA) >> 10;
113 if (VERIFY22(result))
114 ; // XXX error condition
115 break;
116 case R_SPARC_HI22:
117 result = TRUNCATE22(((SYM + ADD) >> 10));
118 break;
119 case R_SPARC_22:
120 result = SYM + ADD;
121 if (VERIFY22(result))
122 ; // XXX error condition
123 break;
124 case R_SPARC_13:
125 result = SYM + ADD;
126 if (VERIFY13(result))
127 ; // XXX error condition
128 break;
129 case R_SPARC_LO10:
130 result = TRUNCATE13(((SYM + ADD) & 0x3FF));
131 break;
132 case R_SPARC_GOT10:
133 case R_SPARC_GOT13:
134 case R_SPARC_GOT22:
135 // unsupported
136 retval = -1;
137 break;
138 case R_SPARC_PC10:
139 result = TRUNCATE13(((SYM + ADD - PLA) & 0x3FF));
140 break;
141 case R_SPARC_PC22:
142 result = (SYM + ADD - PLA) >> 10;
143 if (VERIFY22(result))
144 ; // XXX error condition
145 break;
146 case R_SPARC_WPLT30:
147 // unsupported
148 retval = -1;
149 break;
150 case R_SPARC_COPY:
151 break;
152 case R_SPARC_GLOB_DAT:
153 result = SYM + ADD;
154 if (VERIFY32(result))
155 ; // XXX error condition
156 break;
157 case R_SPARC_JMP_SLOT:
158 retval = -1;
159 break;
160 case R_SPARC_RELATIVE:
161 result = BAS + ADD;
162 if (VERIFY32(result))
163 ; // XXX error condition
164 break;
165 case R_SPARC_UA32:
166 result = SYM + ADD;
167 if (VERIFY32(result))
168 ; // XXX error condition
169 break;
170 default:
171 ELFSH_SETERROR("[libelfsh:relocate_sparc] Unsupported architecture\n",
172 -1);
173 break;
174 }
175
176 #undef ADD
177 #undef BAS
178 #undef GOT
179 #undef PLT
180 #undef PLA
181 #undef SYM
182 *dword += result;
183 return (retval);
184 }
185
186
187
188
189 /* Perform relocation on entry */
elfsh_relocate_entry(elfshsect_t * new,void * reloc,u_long * dword,u_long addr)190 static int elfsh_relocate_entry(elfshsect_t *new,
191 void *reloc,
192 u_long *dword,
193 u_long addr)
194 {
195 int retval;
196
197 switch (elfsh_get_arch(new->parent->hdr))
198 {
199 case EM_386:
200 /* XXX: case EM_486: */
201 retval = elfsh_relocate_i386(new, (Elf32_Rel *) reloc, dword, addr);
202 break;
203 case EM_SPARC:
204 case EM_SPARC32PLUS:
205 retval = elfsh_relocate_sparc(new, (Elf32_Rela *) reloc, dword, addr);
206 break;
207 case EM_SPARCV9: /* can't support just yet.. */
208 default:
209 ELFSH_SETERROR("[libelfsh:relocate_entry] Unsupported architecture\n",
210 -1);
211 break;
212 }
213 return retval;
214 }
215
216
217
218 /* Relocate the just injected section */
elfsh_relocate_etrel_section(elfshsect_t * new,elfshsect_t * reltab)219 static int elfsh_relocate_etrel_section(elfshsect_t *new,
220 elfshsect_t *reltab)
221 {
222 Elf32_Rel *cur;
223 u_int index;
224 Elf32_Sym *sym;
225 u_int size;
226 long *dword;
227 long addr;
228 char *name;
229 char tmpname[BUFSIZ];
230 elfshsect_t *sect;
231
232
233
234 #if __DEBUG_RELADD__
235 printf("[DEBUG_RELADD] Using reloc table from %s [%s] data at %p \n",
236 reltab->parent->name, reltab->name, reltab->data);
237 #endif
238
239 /* Loop on the relocation table entries */
240 size = (reltab->shdr->sh_type == SHT_RELA ?
241 sizeof(Elf32_Rela) : sizeof(Elf32_Rel));
242 size = reltab->shdr->sh_size / size;
243
244 for (index = 0; index < size; index++)
245 {
246
247 /* Get symbol value in ET_REL */
248 cur = (reltab->shdr->sh_type == SHT_RELA ?
249 (void *) (((Elf32_Rela *) reltab->data) + index):
250 (void *) (((Elf32_Rel *) reltab->data) + index));
251 sym = elfsh_get_symbol_from_reloc(reltab->parent, cur);
252 name = elfsh_get_symname_from_reloc(reltab->parent, cur);
253 if (sym == NULL || name == NULL)
254 return (-1);
255
256 /* Grab a pointer on the dword that need to be relocated */
257 dword = (long *) ((char *) new->data + cur->r_offset);
258
259 /*
260 ** If symbol type is NOTYPE, we use ET_EXEC symtab, else if
261 ** symbol link is COMMON, we use ET_REL symbol inserted in ET_EXEC
262 ** during BSS sizescan in bss.c:elfsh_find_bsslen()
263 */
264 if (elfsh_get_symbol_type(sym) == STT_NOTYPE ||
265 elfsh_get_symbol_link(sym) == SHN_COMMON)
266 {
267
268 sym = elfsh_get_metasym_by_name(new->parent, name);
269 if (sym == NULL)
270 ELFSH_SETERROR("[libelfsh:relocate_etrel_section] "
271 "Cant find requested symbol in ET_EXEC\n", -1);
272 addr = sym->st_value;
273
274 #if __DEBUG_RELADD__
275 printf("[DEBUG_RELADD] Relocate using existing symbol %-20s [%08X]\n",
276 name, (u_int) addr);
277 #endif
278
279 }
280
281
282 /* Compute addr giving the injected section's vaddr in ET_EXEC */
283 else
284 {
285
286 /* Find target section in ET_REL */
287 sect = elfsh_get_section_by_index(reltab->parent, sym->st_shndx,
288 NULL, NULL);
289 if (sect == NULL)
290 ELFSH_SETERROR("[libelfsh:relocate_etrel_section] "
291 "Cant find extracted section in ET_REL\n", -1);
292
293 /* Find corresponding inserted section in ET_EXEC */
294 snprintf(tmpname, sizeof(tmpname), "%s%s", reltab->parent->name, sect->name);
295 sect = elfsh_get_section_by_name(new->parent, tmpname, NULL, NULL, NULL);
296 if (sect == NULL)
297 ELFSH_SETERROR("[libelfsh:relocate_etrel_section] "
298 "Cant find inserted section in ET_EXEC\n", -1);
299
300 /* Compute pointer value */
301 addr = sect->shdr->sh_addr;
302 addr += (elfsh_get_symbol_type(sym) == STT_SECTION &&
303 !FILE_IS_SPARC(sect->parent) ? *dword : sym->st_value);
304
305
306 #if __DEBUG_RELADD__
307 printf("[DEBUG_RELADD] Relocate using section %-20s base [-> %08X] \n",
308 sect->name, (unsigned int) addr);
309 #endif
310
311
312 }
313
314
315 /* Perform relocation */
316 if (elfsh_relocate_entry(new, cur, dword, addr) < 0)
317 return (-1);
318
319 }
320 return (0);
321 }
322
323
324
325 /* Inject a section from ET_REL object into ET_EXEC */
elfsh_inject_etrel_section(elfshobj_t * file,elfshsect_t * sect)326 static int elfsh_inject_etrel_section(elfshobj_t *file, elfshsect_t *sect)
327 {
328 Elf32_Shdr hdr;
329 elfshsect_t *new;
330 char *newname;
331 char writable;
332 int mode;
333 char *data;
334
335 /* else create a new section */
336 hdr = elfsh_create_shdr(0, sect->shdr->sh_type, sect->shdr->sh_flags,
337 0, 0, sect->shdr->sh_size, 0, 0, 0, 0);
338 XALLOC(newname, strlen(sect->parent->name) + strlen(sect->name) + 2, -1);
339 sprintf(newname, "%s%s", sect->parent->name, sect->name);
340 new = elfsh_create_section(newname);
341
342 /* Copy the data */
343 XALLOC(data, sect->shdr->sh_size, -1);
344 memcpy(data, sect->data, sect->shdr->sh_size);
345
346 /* Inject new section by top or after bss depending on its type */
347 writable = elfsh_get_section_writableflag(sect->shdr);
348
349 /* FreeBSD is incompatible with pre-interp injection */
350 #if defined __FreeBSD__ || defined __DragonFly__
351 mode = ELFSH_DATA_INJECTION;
352 #else
353 mode = (writable ? ELFSH_DATA_INJECTION : ELFSH_CODE_INJECTION);
354 #endif
355
356 if (elfsh_insert_mapped_section(file, new, hdr, data, mode) < 0)
357 goto bad;
358 new = elfsh_get_section_by_name(file, newname, NULL, NULL, NULL);
359 if (new == NULL)
360 goto bad;
361
362 return (0);
363 bad:
364 free(newname);
365 return (-1);
366 }
367
368
369
370 /* Inject a ET_REL object into a ET_EXEC object */
elfsh_inject_etrel(elfshobj_t * file,elfshobj_t * rel)371 int elfsh_inject_etrel(elfshobj_t *file, elfshobj_t *rel)
372 {
373 elfshsect_t *sect;
374 elfshsect_t *reltab;
375 char sctname[BUFSIZ];
376 Elf32_Sym newsym;
377 u_int symnbr;
378 u_int index;
379 static Elf32_Sym *sym;
380 u_char type;
381 elfshsect_t *bss;
382 elfshzone_t *zone;
383 int bss_size;
384
385
386 /* Sanity checks */
387 if (file == NULL || file->hdr == NULL || rel == NULL || rel->hdr == NULL)
388 ELFSH_SETERROR("[libelfsh:inject_etrel] Invalid NULL parameter\n", -1);
389 if (file->hdr->e_type != ET_EXEC || rel->hdr->e_type != ET_REL)
390 ELFSH_SETERROR("[libelfsh:inject_etrel] Bad object types\n", -1);
391
392 /* First fuzion BSS */
393 bss = elfsh_fixup_bss(file);
394 if (bss == NULL)
395 return (-1);
396 bss_size = elfsh_find_bsslen(file, rel);
397 if (bss_size < 0)
398 return (-1);
399 zone = elfsh_create_bsszone(rel->name, bss->shdr->sh_size, bss_size);
400 if (zone == NULL)
401 return (-1);
402 if (elfsh_add_bsszone(bss, zone) < 0)
403 return (-1);
404
405
406 /* First pass : find and inject all allocatable sections */
407 for (index = 0; index < rel->hdr->e_shnum; index++)
408 {
409
410 /* Get the current section */
411 sect = elfsh_get_section_by_index(rel, index, NULL, NULL);
412 if (sect == NULL)
413 ELFSH_SETERROR("[libelfsh:inject_etrel] Cant read section in ET_REL\n", -1);
414
415 /* Check if the current section need to be mapped */
416 if (elfsh_get_section_allocflag(sect->shdr) &&
417 sect->shdr->sh_size &&
418 sect->shdr->sh_type == SHT_PROGBITS &&
419 elfsh_inject_etrel_section(file, sect) < 0)
420 return (-1);
421 }
422
423 /* Do a copy of the procedure linkage table for eventual redirection */
424 if (elfsh_copy_plt(file) < 0)
425 return (-1);
426
427 #if __DEBUG_RELADD__
428 printf("[DEBUG_RELADD] Entering intermediate symbol injection loop\n");
429 #endif
430
431
432 /* Intermediate pass : Inject ET_REL symbol table into host file */
433 sym = elfsh_get_symtab(rel, &symnbr);
434 for (index = 0; index < symnbr; index++)
435 {
436
437 type = elfsh_get_symbol_type(sym + index);
438
439 /* Avoid non-injectable symbols */
440 if (type != STT_FUNC && type != STT_OBJECT)
441 continue;
442 if (sym[index].st_shndx >= rel->hdr->e_shnum)
443 continue;
444
445 /* Find target section in ET_REL */
446 sect = elfsh_get_section_by_index(rel, sym[index].st_shndx, NULL, NULL);
447 if (sect == NULL)
448 ELFSH_SETERROR("[libelfsh:inject_etrel] "
449 "Cant find extracted section in ET_REL\n", -1);
450
451 /* Filter symbols using source section */
452 /* XXX: not sure it is necessary */
453 if (sect->shdr->sh_type != SHT_PROGBITS || !sect->shdr->sh_size ||
454 !elfsh_get_section_allocflag(sect->shdr))
455 continue;
456
457 /* Find corresponding inserted section in ET_EXEC */
458 snprintf(sctname, sizeof(sctname), "%s%s", rel->name, sect->name);
459 sect = elfsh_get_section_by_name(file, sctname, NULL, NULL, NULL);
460 if (sect == NULL)
461 ELFSH_SETERROR("[libelfsh:inject_etrel] "
462 "Cant find inserted section in ET_EXEC\n", -1);
463
464 #if __DEBUG_RELADD__
465 printf("[DEBUG_RELADD] Injected ET_REL symbol %-20s [%08X] \n",
466 elfsh_get_symbol_name(rel, sym + index),
467 (u_int) (sect->shdr->sh_addr + sym[index].st_value));
468 #endif
469
470 /* Add symbol in host file */
471 newsym = elfsh_create_symbol(sect->shdr->sh_addr + sym[index].st_value,
472 sym[index].st_size,
473 elfsh_get_symbol_type(sym + index),
474 elfsh_get_symbol_bind(sym + index),
475 0, sect->index);
476 if (elfsh_insert_symbol(file->secthash[ELFSH_SECTION_SYMTAB], &newsym,
477 elfsh_get_symbol_name(rel, sym + index)) < 0)
478 return (-1);
479 }
480
481 /* Resynchronize sorted instances of symbol table */
482 if (elfsh_sync_sorted_symtab(file->secthash[ELFSH_SECTION_SYMTAB]) < 0)
483 return (-1);
484
485
486 #if __DEBUG_RELADD__
487 printf("[DEBUG_RELADD] Entering final relocation loop\n");
488 #endif
489
490
491 /* Last pass : relocate each inserted section */
492 for (index = 0; index < rel->hdr->e_shnum; index++)
493 {
494 sect = elfsh_get_section_by_index(rel, index, NULL, NULL);
495 if (sect == NULL)
496 ELFSH_SETERROR("[libelfsh:inject_etrel] Cant get section in ET_REL\n", -1);
497
498 /* Check if the section is mapped */
499 if (elfsh_get_section_allocflag(sect->shdr) && sect->shdr->sh_size &&
500 sect->shdr->sh_type == SHT_PROGBITS)
501 {
502
503 /* Find the associate relocation section */
504 snprintf(sctname, sizeof(sctname), "%s%s",
505 (IS_REL(sect) ? ".rel" : ".rela"), sect->name);
506 reltab = elfsh_get_section_by_name(rel, sctname, NULL, NULL, NULL);
507 if (reltab == NULL)
508 continue;
509
510 /* Find the injected instance of this allocatable section in the ET_EXEC */
511 snprintf(sctname, sizeof(sctname), "%s%s", sect->parent->name, sect->name);
512 sect = elfsh_get_section_by_name(file, sctname, NULL, NULL, NULL);
513 if (sect == NULL)
514 ELFSH_SETERROR("[libelfsh:inject_etrel] Cant get section in ET_EXEC\n", -1);
515 if (elfsh_relocate_etrel_section(sect, reltab) < 0)
516 return (-1);
517 }
518 }
519
520 /* Everything ran OK */
521 return (0);
522 }
523
524