]>
Commit | Line | Data |
---|---|---|
aee6e90f | 1 | /* Audit common functions. |
6d7e8eda | 2 | Copyright (C) 2021-2023 Free Software Foundation, Inc. |
aee6e90f AZ |
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 | ||
cda4f265 | 19 | #include <assert.h> |
eff687e8 | 20 | #include <link.h> |
aee6e90f | 21 | #include <ldsodefs.h> |
eff687e8 | 22 | #include <dl-machine.h> |
8c0664e2 AZ |
23 | #include <dl-runtime.h> |
24 | #include <dl-fixup-attribute.h> | |
62c888b3 | 25 | #include <sys/param.h> |
aee6e90f | 26 | |
3dac3959 AZ |
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 | ||
c91008d3 AZ |
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 | ||
aee6e90f AZ |
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 | } | |
311c9ee5 AZ |
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 | } | |
cda4f265 | 115 | |
0b98a874 AZ |
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 | ||
cda4f265 AZ |
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 ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value, | |
180 | lookup_t result) | |
181 | { | |
32612615 AZ |
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 | } | |
cda4f265 AZ |
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. */ | |
32612615 AZ |
197 | if (!for_jmp_slot) |
198 | reloc_result->enterexit = (1u << DL_NNS) - 1; | |
cda4f265 AZ |
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); | |
32612615 | 210 | uint32_t enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT; |
cda4f265 AZ |
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); | |
32612615 | 216 | uintptr_t new_value = (uintptr_t) sym.st_value; |
cda4f265 AZ |
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 | { | |
32612615 AZ |
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); | |
cda4f265 AZ |
233 | if (new_value != (uintptr_t) sym.st_value) |
234 | { | |
235 | flags |= LA_SYMB_ALTVALUE; | |
32612615 AZ |
236 | sym.st_value = for_jmp_slot |
237 | ? DL_FIXUP_BINDNOW_ADDR_VALUE (new_value) : new_value; | |
cda4f265 AZ |
238 | } |
239 | } | |
240 | ||
241 | /* Remember the results for every audit library and store a summary | |
242 | in the first two bits. */ | |
32612615 AZ |
243 | enterexit &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT); |
244 | enterexit |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) | |
245 | << ((cnt + 1) * 2)); | |
cda4f265 AZ |
246 | } |
247 | else | |
248 | /* If the bind flags say this auditor is not interested, set the bits | |
249 | manually. */ | |
32612615 AZ |
250 | enterexit |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) |
251 | << ((cnt + 1) * 2)); | |
cda4f265 AZ |
252 | afct = afct->next; |
253 | } | |
254 | ||
32612615 AZ |
255 | if (!for_jmp_slot) |
256 | { | |
257 | reloc_result->enterexit = enterexit; | |
258 | reloc_result->flags = flags; | |
259 | } | |
260 | ||
9e94f574 AZ |
261 | if (flags & LA_SYMB_ALTVALUE) |
262 | DL_FIXUP_BINDNOW_RELOC (value, new_value, sym.st_value); | |
cda4f265 | 263 | } |
eff687e8 AZ |
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 | } | |
8c0664e2 AZ |
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 | } |