rtld: properly handle root directory in load path (bug 30435)
[platform/upstream/glibc.git] / elf / do-rel.h
1 /* Do relocations for ELF dynamic linking.
2    Copyright (C) 1995-2023 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18
19 #include <ldsodefs.h>
20
21 /* This file may be included twice, to define both
22    `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.  */
23
24 #ifdef DO_RELA
25 # define elf_dynamic_do_Rel             elf_dynamic_do_Rela
26 # define Rel                            Rela
27 # define elf_machine_rel                elf_machine_rela
28 # define elf_machine_rel_relative       elf_machine_rela_relative
29 #endif
30
31 #ifndef DO_ELF_MACHINE_REL_RELATIVE
32 # define DO_ELF_MACHINE_REL_RELATIVE(map, l_addr, relative) \
33   elf_machine_rel_relative (l_addr, relative,                                 \
34                             (void *) (l_addr + relative->r_offset))
35 #endif
36
37 /* Perform the relocations in MAP on the running program image as specified
38    by RELTAG, SZTAG.  If LAZY is nonzero, this is the first pass on PLT
39    relocations; they should be set up to call _dl_runtime_resolve, rather
40    than fully resolved now.  */
41
42 static inline void __attribute__ ((always_inline))
43 elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
44                     ElfW(Addr) reladdr, ElfW(Addr) relsize,
45                     __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative,
46                     int lazy, int skip_ifunc)
47 {
48   const ElfW(Rel) *relative = (const void *) reladdr;
49   const ElfW(Rel) *r = relative + nrelative;
50   const ElfW(Rel) *end = (const void *) (reladdr + relsize);
51   ElfW(Addr) l_addr = map->l_addr;
52   const ElfW(Sym) *const symtab
53       = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
54
55 #ifdef RTLD_BOOTSTRAP
56   for (; relative < r; ++relative)
57     DO_ELF_MACHINE_REL_RELATIVE (map, l_addr, relative);
58
59   const ElfW (Half) *const version
60       = (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
61   for (; r < end; ++r)
62     {
63       ElfW (Half) ndx = version[ELFW (R_SYM) (r->r_info)] & 0x7fff;
64       const ElfW (Sym) *sym = &symtab[ELFW (R_SYM) (r->r_info)];
65       void *const r_addr_arg = (void *) (l_addr + r->r_offset);
66       const struct r_found_version *rversion = &map->l_versions[ndx];
67
68       elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, skip_ifunc);
69     }
70 #else /* !RTLD_BOOTSTRAP */
71 # if defined ELF_MACHINE_IRELATIVE
72   const ElfW(Rel) *r2 = NULL;
73   const ElfW(Rel) *end2 = NULL;
74 # endif
75
76 #if !defined DO_RELA || !defined ELF_MACHINE_PLT_REL
77   /* We never bind lazily during ld.so bootstrap.  Unfortunately gcc is
78      not clever enough to see through all the function calls to realize
79      that.  */
80   if (lazy)
81     {
82       /* Doing lazy PLT relocations; they need very little info.  */
83       for (; r < end; ++r)
84 # ifdef ELF_MACHINE_IRELATIVE
85         if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
86           {
87             if (r2 == NULL)
88               r2 = r;
89             end2 = r;
90           }
91         else
92 # endif
93           elf_machine_lazy_rel (map, scope, l_addr, r, skip_ifunc);
94
95 # ifdef ELF_MACHINE_IRELATIVE
96       if (r2 != NULL)
97         for (; r2 <= end2; ++r2)
98           if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
99             elf_machine_lazy_rel (map, scope, l_addr, r2, skip_ifunc);
100 # endif
101     }
102   else
103 #endif
104     {
105       /* This is defined in rtld.c, but nowhere in the static libc.a; make
106          the reference weak so static programs can still link.  This
107          declaration cannot be done when compiling rtld.c (i.e. #ifdef
108          RTLD_BOOTSTRAP) because rtld.c contains the common defn for
109          _dl_rtld_map, which is incompatible with a weak decl in the same
110          file.  */
111 # ifndef SHARED
112       weak_extern (GL(dl_rtld_map));
113 # endif
114       if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
115 # if !defined DO_RELA || defined ELF_MACHINE_REL_RELATIVE
116         /* Rela platforms get the offset from r_addend and this must
117            be copied in the relocation address.  Therefore we can skip
118            the relative relocations only if this is for rel
119            relocations or rela relocations if they are computed as
120            memory_loc += l_addr...  */
121         if (l_addr != 0)
122 # endif
123           for (; relative < r; ++relative)
124             DO_ELF_MACHINE_REL_RELATIVE (map, l_addr, relative);
125
126       if (map->l_info[VERSYMIDX (DT_VERSYM)])
127         {
128           const ElfW(Half) *const version =
129             (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
130
131           for (; r < end; ++r)
132             {
133               ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
134               const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
135               void *const r_addr_arg = (void *) (l_addr + r->r_offset);
136               const struct r_found_version *rversion = &map->l_versions[ndx];
137 #if defined ELF_MACHINE_IRELATIVE
138               if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
139                 {
140                   if (r2 == NULL)
141                     r2 = r;
142                   end2 = r;
143                   continue;
144                 }
145 #endif
146
147               elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg,
148                                skip_ifunc);
149 #if defined SHARED
150               if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT
151                   && GLRO(dl_naudit) > 0)
152                 {
153                   struct link_map *sym_map
154                     = RESOLVE_MAP (map, scope, &sym, rversion,
155                                    ELF_MACHINE_JMP_SLOT);
156                   if (sym != NULL)
157                     _dl_audit_symbind (map, NULL, sym, r_addr_arg, sym_map);
158                 }
159 #endif
160             }
161
162 #if defined ELF_MACHINE_IRELATIVE
163           if (r2 != NULL)
164             for (; r2 <= end2; ++r2)
165               if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
166                 {
167                   ElfW(Half) ndx
168                     = version[ELFW(R_SYM) (r2->r_info)] & 0x7fff;
169                   elf_machine_rel (map, scope, r2,
170                                    &symtab[ELFW(R_SYM) (r2->r_info)],
171                                    &map->l_versions[ndx],
172                                    (void *) (l_addr + r2->r_offset),
173                                    skip_ifunc);
174                 }
175 #endif
176         }
177       else
178         {
179           for (; r < end; ++r)
180             {
181               const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
182               void *const r_addr_arg = (void *) (l_addr + r->r_offset);
183 # ifdef ELF_MACHINE_IRELATIVE
184               if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
185                 {
186                   if (r2 == NULL)
187                     r2 = r;
188                   end2 = r;
189                   continue;
190                 }
191 # endif
192               elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg,
193                                skip_ifunc);
194 # if defined SHARED
195               if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT
196                   && GLRO(dl_naudit) > 0)
197                 {
198                   struct link_map *sym_map
199                     = RESOLVE_MAP (map, scope, &sym,
200                                    (struct r_found_version *) NULL,
201                                    ELF_MACHINE_JMP_SLOT);
202                   if (sym != NULL)
203                     _dl_audit_symbind (map, NULL , sym,r_addr_arg, sym_map);
204                 }
205 # endif
206             }
207
208 # ifdef ELF_MACHINE_IRELATIVE
209           if (r2 != NULL)
210             for (; r2 <= end2; ++r2)
211               if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
212                 elf_machine_rel (map, scope, r2, &symtab[ELFW(R_SYM) (r2->r_info)],
213                                  NULL, (void *) (l_addr + r2->r_offset),
214                                  skip_ifunc);
215 # endif
216         }
217     }
218 #endif /* !RTLD_BOOTSTRAP */
219 }
220
221 #undef elf_dynamic_do_Rel
222 #undef Rel
223 #undef elf_machine_rel
224 #undef elf_machine_rel_relative
225 #undef DO_ELF_MACHINE_REL_RELATIVE
226 #undef DO_RELA