1 | /* Audit common functions. |
2 | Copyright (C) 2021-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 <assert.h> |
20 | #include <link.h> |
21 | #include <ldsodefs.h> |
22 | #include <dl-machine.h> |
23 | #include <dl-runtime.h> |
24 | #include <dl-fixup-attribute.h> |
25 | #include <sys/param.h> |
26 | |
27 | void |
28 | _dl_audit_activity_map (struct link_map *l, int action) |
29 | { |
30 | struct audit_ifaces *afct = GLRO(dl_audit); |
31 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
32 | { |
33 | if (afct->activity != NULL) |
34 | afct->activity (&link_map_audit_state (l, cnt)->cookie, action); |
35 | afct = afct->next; |
36 | } |
37 | } |
38 | |
39 | void |
40 | _dl_audit_activity_nsid (Lmid_t nsid, int action) |
41 | { |
42 | /* If head is NULL, the namespace has become empty, and the audit interface |
43 | does not give us a way to signal LA_ACT_CONSISTENT for it because the |
44 | first loaded module is used to identify the namespace. */ |
45 | struct link_map *head = GL(dl_ns)[nsid]._ns_loaded; |
46 | if (__glibc_likely (GLRO(dl_naudit) == 0) |
47 | || head == NULL || head->l_auditing) |
48 | return; |
49 | |
50 | _dl_audit_activity_map (head, action); |
51 | } |
52 | |
53 | const char * |
54 | _dl_audit_objsearch (const char *name, struct link_map *l, unsigned int code) |
55 | { |
56 | if (l == NULL || l->l_auditing || code == 0) |
57 | return name; |
58 | |
59 | struct audit_ifaces *afct = GLRO(dl_audit); |
60 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
61 | { |
62 | if (afct->objsearch != NULL) |
63 | { |
64 | struct auditstate *state = link_map_audit_state (l, cnt); |
65 | name = afct->objsearch (name, &state->cookie, code); |
66 | if (name == NULL) |
67 | return NULL; |
68 | } |
69 | afct = afct->next; |
70 | } |
71 | |
72 | return name; |
73 | } |
74 | |
75 | void |
76 | _dl_audit_objopen (struct link_map *l, Lmid_t nsid) |
77 | { |
78 | if (__glibc_likely (GLRO(dl_naudit) == 0)) |
79 | return; |
80 | |
81 | struct audit_ifaces *afct = GLRO(dl_audit); |
82 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
83 | { |
84 | if (afct->objopen != NULL) |
85 | { |
86 | struct auditstate *state = link_map_audit_state (l, cnt); |
87 | state->bindflags = afct->objopen (l, nsid, &state->cookie); |
88 | l->l_audit_any_plt |= state->bindflags != 0; |
89 | } |
90 | |
91 | afct = afct->next; |
92 | } |
93 | } |
94 | |
95 | void |
96 | _dl_audit_objclose (struct link_map *l) |
97 | { |
98 | if (__glibc_likely (GLRO(dl_naudit) == 0) |
99 | || GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing) |
100 | return; |
101 | |
102 | struct audit_ifaces *afct = GLRO(dl_audit); |
103 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
104 | { |
105 | if (afct->objclose != NULL) |
106 | { |
107 | struct auditstate *state= link_map_audit_state (l, cnt); |
108 | /* Return value is ignored. */ |
109 | afct->objclose (&state->cookie); |
110 | } |
111 | |
112 | afct = afct->next; |
113 | } |
114 | } |
115 | |
116 | void |
117 | _dl_audit_preinit (struct link_map *l) |
118 | { |
119 | if (__glibc_likely (GLRO(dl_naudit) == 0)) |
120 | return; |
121 | |
122 | struct audit_ifaces *afct = GLRO(dl_audit); |
123 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
124 | { |
125 | if (afct->preinit != NULL) |
126 | afct->preinit (&link_map_audit_state (l, cnt)->cookie); |
127 | afct = afct->next; |
128 | } |
129 | } |
130 | |
131 | void |
132 | _dl_audit_symbind_alt (struct link_map *l, const ElfW(Sym) *ref, void **value, |
133 | lookup_t result) |
134 | { |
135 | if ((l->l_audit_any_plt | result->l_audit_any_plt) == 0) |
136 | return; |
137 | |
138 | const char *strtab = (const char *) D_PTR (result, l_info[DT_STRTAB]); |
139 | /* Compute index of the symbol entry in the symbol table of the DSO with |
140 | the definition. */ |
141 | unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result, l_info[DT_SYMTAB])); |
142 | |
143 | unsigned int altvalue = 0; |
144 | /* Synthesize a symbol record where the st_value field is the result. */ |
145 | ElfW(Sym) sym = *ref; |
146 | sym.st_value = (ElfW(Addr)) *value; |
147 | |
148 | struct audit_ifaces *afct = GLRO(dl_audit); |
149 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
150 | { |
151 | struct auditstate *match_audit = link_map_audit_state (l, cnt); |
152 | struct auditstate *result_audit = link_map_audit_state (result, cnt); |
153 | if (afct->symbind != NULL |
154 | && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0 |
155 | || ((result_audit->bindflags & LA_FLG_BINDTO) |
156 | != 0))) |
157 | { |
158 | unsigned int flags = altvalue | LA_SYMB_DLSYM; |
159 | uintptr_t new_value = afct->symbind (&sym, ndx, |
160 | &match_audit->cookie, |
161 | &result_audit->cookie, |
162 | &flags, strtab + ref->st_name); |
163 | if (new_value != (uintptr_t) sym.st_value) |
164 | { |
165 | altvalue = LA_SYMB_ALTVALUE; |
166 | sym.st_value = new_value; |
167 | } |
168 | |
169 | afct = afct->next; |
170 | } |
171 | |
172 | *value = (void *) sym.st_value; |
173 | } |
174 | } |
175 | rtld_hidden_def (_dl_audit_symbind_alt) |
176 | |
177 | void |
178 | _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, |
179 | const void *reloc, const ElfW(Sym) *defsym, |
180 | DL_FIXUP_VALUE_TYPE *value, lookup_t result, bool lazy) |
181 | { |
182 | bool for_jmp_slot = reloc_result == NULL; |
183 | |
184 | /* Compute index of the symbol entry in the symbol table of the DSO |
185 | with the definition. */ |
186 | unsigned int boundndx = defsym - (ElfW(Sym) *) D_PTR (result, |
187 | l_info[DT_SYMTAB]); |
188 | if (!for_jmp_slot) |
189 | { |
190 | reloc_result->bound = result; |
191 | reloc_result->boundndx = boundndx; |
192 | } |
193 | |
194 | if ((l->l_audit_any_plt | result->l_audit_any_plt) == 0) |
195 | { |
196 | /* Set all bits since this symbol binding is not interesting. */ |
197 | if (!for_jmp_slot) |
198 | reloc_result->enterexit = (1u << DL_NNS) - 1; |
199 | return; |
200 | } |
201 | |
202 | /* Synthesize a symbol record where the st_value field is the result. */ |
203 | ElfW(Sym) sym = *defsym; |
204 | sym.st_value = DL_FIXUP_VALUE_ADDR (*value); |
205 | |
206 | /* Keep track whether there is any interest in tracing the call in the lower |
207 | two bits. */ |
208 | assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8); |
209 | assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3); |
210 | uint32_t enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT; |
211 | |
212 | const char *strtab2 = (const void *) D_PTR (result, l_info[DT_STRTAB]); |
213 | |
214 | unsigned int flags = 0; |
215 | struct audit_ifaces *afct = GLRO(dl_audit); |
216 | uintptr_t new_value = (uintptr_t) sym.st_value; |
217 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
218 | { |
219 | /* XXX Check whether both DSOs must request action or only one */ |
220 | struct auditstate *l_state = link_map_audit_state (l, cnt); |
221 | struct auditstate *result_state = link_map_audit_state (result, cnt); |
222 | if ((l_state->bindflags & LA_FLG_BINDFROM) != 0 |
223 | && (result_state->bindflags & LA_FLG_BINDTO) != 0) |
224 | { |
225 | if (afct->symbind != NULL) |
226 | { |
227 | flags |= for_jmp_slot ? LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT |
228 | : 0; |
229 | new_value = afct->symbind (&sym, boundndx, |
230 | &l_state->cookie, |
231 | &result_state->cookie, &flags, |
232 | strtab2 + defsym->st_name); |
233 | if (new_value != (uintptr_t) sym.st_value) |
234 | { |
235 | flags |= LA_SYMB_ALTVALUE; |
236 | sym.st_value = for_jmp_slot |
237 | ? DL_FIXUP_BINDNOW_ADDR_VALUE (new_value) : new_value; |
238 | } |
239 | } |
240 | |
241 | /* Remember the results for every audit library and store a summary |
242 | in the first two bits. */ |
243 | enterexit &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT); |
244 | enterexit |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) |
245 | << ((cnt + 1) * 2)); |
246 | } |
247 | else |
248 | /* If the bind flags say this auditor is not interested, set the bits |
249 | manually. */ |
250 | enterexit |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) |
251 | << ((cnt + 1) * 2)); |
252 | afct = afct->next; |
253 | } |
254 | |
255 | if (!for_jmp_slot) |
256 | { |
257 | reloc_result->enterexit = enterexit; |
258 | reloc_result->flags = flags; |
259 | } |
260 | |
261 | if (flags & LA_SYMB_ALTVALUE) |
262 | DL_FIXUP_BINDNOW_RELOC (l, reloc, value, new_value, sym.st_value, lazy); |
263 | } |
264 | |
265 | void |
266 | _dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result, |
267 | DL_FIXUP_VALUE_TYPE *value, void *regs, long int *framesize) |
268 | { |
269 | /* Don't do anything if no auditor wants to intercept this call. */ |
270 | if (GLRO(dl_naudit) == 0 |
271 | || (reloc_result->enterexit & LA_SYMB_NOPLTENTER)) |
272 | return; |
273 | |
274 | /* Sanity check: DL_FIXUP_VALUE_CODE_ADDR (value) should have been |
275 | initialized earlier in this function or in another thread. */ |
276 | assert (DL_FIXUP_VALUE_CODE_ADDR (*value) != 0); |
277 | ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound, |
278 | l_info[DT_SYMTAB]) |
279 | + reloc_result->boundndx); |
280 | |
281 | /* Set up the sym parameter. */ |
282 | ElfW(Sym) sym = *defsym; |
283 | sym.st_value = DL_FIXUP_VALUE_ADDR (*value); |
284 | |
285 | /* Get the symbol name. */ |
286 | const char *strtab = (const void *) D_PTR (reloc_result->bound, |
287 | l_info[DT_STRTAB]); |
288 | const char *symname = strtab + sym.st_name; |
289 | |
290 | /* Keep track of overwritten addresses. */ |
291 | unsigned int flags = reloc_result->flags; |
292 | |
293 | struct audit_ifaces *afct = GLRO(dl_audit); |
294 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
295 | { |
296 | if (afct->ARCH_LA_PLTENTER != NULL |
297 | && (reloc_result->enterexit |
298 | & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0) |
299 | { |
300 | long int new_framesize = -1; |
301 | struct auditstate *l_state = link_map_audit_state (l, cnt); |
302 | struct auditstate *bound_state |
303 | = link_map_audit_state (reloc_result->bound, cnt); |
304 | uintptr_t new_value |
305 | = afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx, |
306 | &l_state->cookie, &bound_state->cookie, |
307 | regs, &flags, symname, &new_framesize); |
308 | if (new_value != (uintptr_t) sym.st_value) |
309 | { |
310 | flags |= LA_SYMB_ALTVALUE; |
311 | sym.st_value = new_value; |
312 | } |
313 | |
314 | /* Remember the results for every audit library and store a summary |
315 | in the first two bits. */ |
316 | reloc_result->enterexit |= ((flags & (LA_SYMB_NOPLTENTER |
317 | | LA_SYMB_NOPLTEXIT)) |
318 | << (2 * (cnt + 1))); |
319 | |
320 | if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT |
321 | << (2 * (cnt + 1)))) |
322 | == 0 && new_framesize != -1 && *framesize != -2) |
323 | { |
324 | /* If this is the first call providing information, use it. */ |
325 | if (*framesize == -1) |
326 | *framesize = new_framesize; |
327 | /* If two pltenter calls provide conflicting information, use |
328 | the larger value. */ |
329 | else if (new_framesize != *framesize) |
330 | *framesize = MAX (new_framesize, *framesize); |
331 | } |
332 | } |
333 | |
334 | afct = afct->next; |
335 | } |
336 | |
337 | *value = DL_FIXUP_ADDR_VALUE (sym.st_value); |
338 | } |
339 | |
340 | void |
341 | DL_ARCH_FIXUP_ATTRIBUTE |
342 | _dl_audit_pltexit (struct link_map *l, ElfW(Word) reloc_arg, |
343 | const void *inregs, void *outregs) |
344 | { |
345 | const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]); |
346 | |
347 | /* This is the address in the array where we store the result of previous |
348 | relocations. */ |
349 | // XXX Maybe the bound information must be stored on the stack since |
350 | // XXX with bind_not a new value could have been stored in the meantime. |
351 | struct reloc_result *reloc_result = |
352 | &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))]; |
353 | ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound, |
354 | l_info[DT_SYMTAB]) |
355 | + reloc_result->boundndx); |
356 | |
357 | /* Set up the sym parameter. */ |
358 | ElfW(Sym) sym = *defsym; |
359 | sym.st_value = DL_FIXUP_VALUE_ADDR (reloc_result->addr); |
360 | |
361 | /* Get the symbol name. */ |
362 | const char *strtab = (const void *) D_PTR (reloc_result->bound, |
363 | l_info[DT_STRTAB]); |
364 | const char *symname = strtab + sym.st_name; |
365 | |
366 | struct audit_ifaces *afct = GLRO(dl_audit); |
367 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
368 | { |
369 | if (afct->ARCH_LA_PLTEXIT != NULL |
370 | && (reloc_result->enterexit |
371 | & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0) |
372 | { |
373 | struct auditstate *l_state = link_map_audit_state (l, cnt); |
374 | struct auditstate *bound_state |
375 | = link_map_audit_state (reloc_result->bound, cnt); |
376 | afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx, |
377 | &l_state->cookie, &bound_state->cookie, |
378 | inregs, outregs, symname); |
379 | } |
380 | |
381 | afct = afct->next; |
382 | } |
383 | } |
384 | |