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