rtld-elf - Allow dynamic (late) relocations to relro section
[dragonfly.git] / libexec / rtld-elf / x86_64 / reloc.c
1 /*-
2  * Copyright 1996, 1997, 1998, 1999 John D. Polstra.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27
28 /*
29  * Dynamic linker for ELF.
30  *
31  * John Polstra <jdp@polstra.com>.
32  */
33
34 #include <sys/param.h>
35 #include <sys/mman.h>
36 #include <sys/tls.h>
37
38 #include <machine/sysarch.h>
39 #include <machine/tls.h>
40
41 #include <dlfcn.h>
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50
51 #include "debug.h"
52 #include "rtld.h"
53
54 /*
55  * Process the special R_X86_64_COPY relocations in the main program.  These
56  * copy data from a shared object into a region in the main program's BSS
57  * segment.
58  *
59  * Returns 0 on success, -1 on failure.
60  */
61 int
62 do_copy_relocations(Obj_Entry *dstobj)
63 {
64     const Elf_Rela *relalim;
65     const Elf_Rela *rela;
66     int error = 0;
67
68     assert(dstobj->mainprog);   /* COPY relocations are invalid elsewhere */
69
70     if (dstobj->relro_protected)
71         mprotect(dstobj->relro_page, dstobj->relro_size, PROT_READ | PROT_WRITE);
72
73     relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + dstobj->relasize);
74     for (rela = dstobj->rela;  rela < relalim;  rela++) {
75         if (ELF_R_TYPE(rela->r_info) == R_X86_64_COPY) {
76             void *dstaddr;
77             const Elf_Sym *dstsym;
78             const char *name;
79             size_t size;
80             const void *srcaddr;
81             const Elf_Sym *srcsym;
82             const Obj_Entry *srcobj, *defobj;
83             SymLook req;
84             int res;
85
86             dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
87             dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
88             name = dstobj->strtab + dstsym->st_name;
89             size = dstsym->st_size;
90             symlook_init(&req, name);
91             req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
92             req.flags = SYMLOOK_EARLY;
93
94             for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next) {
95                 res = symlook_obj(&req, srcobj);
96                 if (res == 0) {
97                     srcsym = req.sym_out;
98                     defobj = req.defobj_out;
99                     break;
100                 }
101             }
102
103             if (srcobj == NULL) {
104                 _rtld_error("Undefined symbol \"%s\" referenced from COPY"
105                   " relocation in %s", name, dstobj->path);
106                 error = -1;
107                 break;
108             }
109
110             srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
111             memcpy(dstaddr, srcaddr, size);
112         }
113     }
114
115     if (dstobj->relro_protected)
116         mprotect(dstobj->relro_page, dstobj->relro_size, PROT_READ);
117
118     return error;
119 }
120
121 /* Initialize the special GOT entries. */
122 void
123 init_pltgot(Obj_Entry *obj)
124 {
125     if (obj->pltgot != NULL) {
126         obj->pltgot[1] = (Elf_Addr) obj;
127         obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
128     }
129 }
130
131 /* Process the non-PLT relocations. */
132 int
133 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
134     RtldLockState *lockstate)
135 {
136         const Elf_Rela *relalim;
137         const Elf_Rela *rela;
138         SymCache *cache;
139         const Elf_Sym *def;
140         const Obj_Entry *defobj;
141         Elf_Addr *where, symval;
142         Elf32_Addr *where32;
143         int r;
144
145         r = -1;
146         /*
147          * The dynamic loader may be called from a thread, we have
148          * limited amounts of stack available so we cannot use alloca().
149          */
150         if (obj != obj_rtld) {
151                 cache = calloc(obj->dynsymcount, sizeof(SymCache));
152                 /* No need to check for NULL here */
153         } else
154                 cache = NULL;
155
156         relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
157         for (rela = obj->rela;  rela < relalim;  rela++) {
158                 /*
159                  * First, resolve symbol for relocations which
160                  * reference symbols.
161                  */
162                 switch (ELF_R_TYPE(rela->r_info)) {
163                 case R_X86_64_64:
164                 case R_X86_64_PC32:
165                 case R_X86_64_GLOB_DAT:
166                 case R_X86_64_TPOFF64:
167                 case R_X86_64_TPOFF32:
168                 case R_X86_64_DTPMOD64:
169                 case R_X86_64_DTPOFF64:
170                 case R_X86_64_DTPOFF32:
171                         def = find_symdef(ELF_R_SYM(rela->r_info), obj,
172                             &defobj, flags, cache, lockstate);
173                         if (def == NULL)
174                                 goto done;
175                         /*
176                          * If symbol is IFUNC, only perform relocation
177                          * when caller allowed it by passing
178                          * SYMLOOK_IFUNC flag.  Skip the relocations
179                          * otherwise.
180                          *
181                          * Also error out in case IFUNC relocations
182                          * are specified for TLS, which cannot be
183                          * usefully interpreted.
184                          */
185                         if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
186                                 switch (ELF_R_TYPE(rela->r_info)) {
187                                 case R_X86_64_64:
188                                 case R_X86_64_PC32:
189                                 case R_X86_64_GLOB_DAT:
190                                         if ((flags & SYMLOOK_IFUNC) == 0) {
191                                                 obj->non_plt_gnu_ifunc = true;
192                                                 continue;
193                                         }
194                                         symval = (Elf_Addr)rtld_resolve_ifunc(
195                                             defobj, def);
196                                         break;
197                                 case R_X86_64_TPOFF64:
198                                 case R_X86_64_TPOFF32:
199                                 case R_X86_64_DTPMOD64:
200                                 case R_X86_64_DTPOFF64:
201                                 case R_X86_64_DTPOFF32:
202                                         _rtld_error("%s: IFUNC for TLS reloc",
203                                             obj->path);
204                                         goto done;
205                                 }
206                         } else {
207                                 if ((flags & SYMLOOK_IFUNC) != 0)
208                                         continue;
209                                 symval = (Elf_Addr)defobj->relocbase +
210                                     def->st_value;
211                         }
212                         break;
213                 default:
214                         if ((flags & SYMLOOK_IFUNC) != 0)
215                                 continue;
216                         break;
217                 }
218                 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
219                 where32 = (Elf32_Addr *)where;
220
221                 switch (ELF_R_TYPE(rela->r_info)) {
222                 case R_X86_64_NONE:
223                         break;
224                 case R_X86_64_64:
225                         *where = symval + rela->r_addend;
226                         break;
227                 case R_X86_64_PC32:
228                         /*
229                          * I don't think the dynamic linker should
230                          * ever see this type of relocation.  But the
231                          * binutils-2.6 tools sometimes generate it.
232                          */
233                         *where32 = (Elf32_Addr)(unsigned long)(symval +
234                             rela->r_addend - (Elf_Addr)where);
235                         break;
236                 /* missing: R_X86_64_GOT32 R_X86_64_PLT32 */
237                 case R_X86_64_COPY:
238                         /*
239                          * These are deferred until all other relocations have
240                          * been done.  All we do here is make sure that the COPY
241                          * relocation is not in a shared library.  They are allowed
242                          * only in executable files.
243                          */
244                         if (!obj->mainprog) {
245                                 _rtld_error("%s: Unexpected R_X86_64_COPY "
246                                     "relocation in shared library", obj->path);
247                                 goto done;
248                         }
249                         break;
250                 case R_X86_64_GLOB_DAT:
251                         *where = symval;
252                         break;
253                 case R_X86_64_TPOFF64:
254                         /*
255                          * We lazily allocate offsets for static TLS
256                          * as we see the first relocation that
257                          * references the TLS block. This allows us to
258                          * support (small amounts of) static TLS in
259                          * dynamically loaded modules. If we run out
260                          * of space, we generate an error.
261                          */
262                         if (!defobj->tls_done) {
263                                 if (!allocate_tls_offset((Obj_Entry*) defobj)) {
264                                         _rtld_error("%s: No space available "
265                                             "for static Thread Local Storage",
266                                             obj->path);
267                                         goto done;
268                                 }
269                         }
270                         *where = (Elf_Addr)(def->st_value - defobj->tlsoffset +
271                             rela->r_addend);
272                         break;
273                 case R_X86_64_TPOFF32:
274                         /*
275                          * We lazily allocate offsets for static TLS
276                          * as we see the first relocation that
277                          * references the TLS block. This allows us to
278                          * support (small amounts of) static TLS in
279                          * dynamically loaded modules. If we run out
280                          * of space, we generate an error.
281                          */
282                         if (!defobj->tls_done) {
283                                 if (!allocate_tls_offset((Obj_Entry*) defobj)) {
284                                         _rtld_error("%s: No space available "
285                                             "for static Thread Local Storage",
286                                             obj->path);
287                                         goto done;
288                                 }
289                         }
290                         *where32 = (Elf32_Addr)(def->st_value -
291                             defobj->tlsoffset + rela->r_addend);
292                         break;
293                 case R_X86_64_DTPMOD64:
294                         *where += (Elf_Addr)defobj->tlsindex;
295                         break;
296                 case R_X86_64_DTPOFF64:
297                         *where += (Elf_Addr)(def->st_value + rela->r_addend);
298                         break;
299                 case R_X86_64_DTPOFF32:
300                         *where32 += (Elf32_Addr)(def->st_value +
301                             rela->r_addend);
302                         break;
303                 case R_X86_64_RELATIVE:
304                         *where = (Elf_Addr)(obj->relocbase + rela->r_addend);
305                         break;
306                 /*
307                  * missing:
308                  * R_X86_64_GOTPCREL, R_X86_64_32, R_X86_64_32S, R_X86_64_16,
309                  * R_X86_64_PC16, R_X86_64_8, R_X86_64_PC8
310                  */
311                 default:
312                         _rtld_error("%s: Unsupported relocation type %u"
313                             " in non-PLT relocations\n", obj->path,
314                             (unsigned int)ELF_R_TYPE(rela->r_info));
315                         goto done;
316                 }
317         }
318         r = 0;
319 done:
320         free(cache);
321         return (r);
322 }
323
324 /* Process the PLT relocations. */
325 int
326 reloc_plt(Obj_Entry *obj)
327 {
328     const Elf_Rela *relalim;
329     const Elf_Rela *rela;
330
331     relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
332     for (rela = obj->pltrela;  rela < relalim;  rela++) {
333         Elf_Addr *where;
334
335         switch(ELF_R_TYPE(rela->r_info)) {
336         case R_X86_64_JMP_SLOT:
337           /* Relocate the GOT slot pointing into the PLT. */
338           where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
339           *where += (Elf_Addr)obj->relocbase;
340           break;
341
342         case R_X86_64_IRELATIVE:
343           obj->irelative = true;
344           break;
345
346         default:
347           _rtld_error("Unknown relocation type %x in PLT",
348             (unsigned int)ELF_R_TYPE(rela->r_info));
349           return (-1);
350         }
351     }
352     return 0;
353 }
354
355 /* Relocate the jump slots in an object. */
356 int
357 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
358 {
359     const Elf_Rela *relalim;
360     const Elf_Rela *rela;
361
362     if (obj->jmpslots_done)
363         return 0;
364     relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
365     for (rela = obj->pltrela;  rela < relalim;  rela++) {
366         Elf_Addr *where, target;
367         const Elf_Sym *def;
368         const Obj_Entry *defobj;
369
370         switch (ELF_R_TYPE(rela->r_info)) {
371         case R_X86_64_JMP_SLOT:
372           where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
373           def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
374                 SYMLOOK_IN_PLT | flags, NULL, lockstate);
375           if (def == NULL)
376               return (-1);
377           if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
378               obj->gnu_ifunc = true;
379               continue;
380           }
381           target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend);
382           reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela);
383           break;
384
385         case R_X86_64_IRELATIVE:
386           break;
387
388         default:
389           _rtld_error("Unknown relocation type %x in PLT",
390             (unsigned int)ELF_R_TYPE(rela->r_info));
391           return (-1);
392         }
393     }
394     obj->jmpslots_done = true;
395     return 0;
396 }
397
398 int
399 reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
400 {
401     const Elf_Rela *relalim;
402     const Elf_Rela *rela;
403
404     if (!obj->irelative)
405         return (0);
406     relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
407     for (rela = obj->pltrela;  rela < relalim;  rela++) {
408         Elf_Addr *where, target, *ptr;
409
410         switch (ELF_R_TYPE(rela->r_info)) {
411         case R_X86_64_JMP_SLOT:
412           break;
413
414         case R_X86_64_IRELATIVE:
415           ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
416           where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
417           lock_release(rtld_bind_lock, lockstate);
418           target = ((Elf_Addr (*)(void))ptr)();
419           wlock_acquire(rtld_bind_lock, lockstate);
420           *where = target;
421           break;
422         }
423     }
424     obj->irelative = false;
425     return (0);
426 }
427
428 int
429 reloc_gnu_ifunc(Obj_Entry *obj, int flags, RtldLockState *lockstate)
430 {
431     const Elf_Rela *relalim;
432     const Elf_Rela *rela;
433
434     if (!obj->gnu_ifunc)
435         return (0);
436     relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
437     for (rela = obj->pltrela;  rela < relalim;  rela++) {
438         Elf_Addr *where, target;
439         const Elf_Sym *def;
440         const Obj_Entry *defobj;
441
442         switch (ELF_R_TYPE(rela->r_info)) {
443         case R_X86_64_JMP_SLOT:
444           where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
445           def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
446                 SYMLOOK_IN_PLT | flags, NULL, lockstate);
447           if (def == NULL)
448               return (-1);
449           if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
450               continue;
451           lock_release(rtld_bind_lock, lockstate);
452           target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
453           wlock_acquire(rtld_bind_lock, lockstate);
454           reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela);
455           break;
456         }
457     }
458     obj->gnu_ifunc = false;
459     return (0);
460 }
461
462 void *__tls_get_addr(tls_index *ti)
463 {
464     struct tls_tcb *tcb;
465
466     tcb = tls_get_tcb();
467     return tls_get_addr_common((Elf_Addr **)&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
468 }
469
470 void *
471 __tls_get_addr_tcb(struct tls_tcb *tcb, tls_index *ti)
472 {
473     return tls_get_addr_common((Elf_Addr **)&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
474 }