]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/elf-util.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / shared / elf-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #if HAVE_ELFUTILS
4
5 #include <dwarf.h>
6 #include <elfutils/libdwelf.h>
7 #include <elfutils/libdwfl.h>
8 #include <libelf.h>
9 #include <sys/prctl.h>
10 #include <sys/resource.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13
14 #include "alloc-util.h"
15 #include "dlfcn-util.h"
16 #include "elf-util.h"
17 #include "errno-util.h"
18 #include "fileio.h"
19 #include "fd-util.h"
20 #include "format-util.h"
21 #include "hexdecoct.h"
22 #include "io-util.h"
23 #include "macro.h"
24 #include "process-util.h"
25 #include "rlimit-util.h"
26 #include "string-util.h"
27 #include "util.h"
28
29 #define FRAMES_MAX 64
30 #define THREADS_MAX 64
31 #define ELF_PACKAGE_METADATA_ID 0xcafe1a7e
32
33 static void *dw_dl = NULL;
34 static void *elf_dl = NULL;
35
36 /* libdw symbols */
37 Dwarf_Attribute *(*sym_dwarf_attr_integrate)(Dwarf_Die *, unsigned int, Dwarf_Attribute *);
38 const char *(*sym_dwarf_diename)(Dwarf_Die *);
39 const char *(*sym_dwarf_formstring)(Dwarf_Attribute *);
40 int (*sym_dwarf_getscopes)(Dwarf_Die *, Dwarf_Addr, Dwarf_Die **);
41 int (*sym_dwarf_getscopes_die)(Dwarf_Die *, Dwarf_Die **);
42 Elf *(*sym_dwelf_elf_begin)(int);
43 #if HAVE_DWELF_ELF_E_MACHINE_STRING
44 const char *(*sym_dwelf_elf_e_machine_string)(int);
45 #endif
46 ssize_t (*sym_dwelf_elf_gnu_build_id)(Elf *, const void **);
47 int (*sym_dwarf_tag)(Dwarf_Die *);
48 Dwfl_Module *(*sym_dwfl_addrmodule)(Dwfl *, Dwarf_Addr);
49 Dwfl *(*sym_dwfl_begin)(const Dwfl_Callbacks *);
50 int (*sym_dwfl_build_id_find_elf)(Dwfl_Module *, void **, const char *, Dwarf_Addr, char **, Elf **);
51 int (*sym_dwfl_core_file_attach)(Dwfl *, Elf *);
52 int (*sym_dwfl_core_file_report)(Dwfl *, Elf *, const char *);
53 void (*sym_dwfl_end)(Dwfl *);
54 const char *(*sym_dwfl_errmsg)(int);
55 int (*sym_dwfl_errno)(void);
56 bool (*sym_dwfl_frame_pc)(Dwfl_Frame *, Dwarf_Addr *, bool *);
57 ptrdiff_t (*sym_dwfl_getmodules)(Dwfl *, int (*)(Dwfl_Module *, void **, const char *, Dwarf_Addr, void *), void *, ptrdiff_t);
58 int (*sym_dwfl_getthreads)(Dwfl *, int (*)(Dwfl_Thread *, void *), void *);
59 Dwarf_Die *(*sym_dwfl_module_addrdie)(Dwfl_Module *, Dwarf_Addr, Dwarf_Addr *);
60 const char *(*sym_dwfl_module_addrname)(Dwfl_Module *, GElf_Addr);
61 int (*sym_dwfl_module_build_id)(Dwfl_Module *, const unsigned char **, GElf_Addr *);
62 Elf *(*sym_dwfl_module_getelf)(Dwfl_Module *, GElf_Addr *);
63 const char *(*sym_dwfl_module_info)(Dwfl_Module *, void ***, Dwarf_Addr *, Dwarf_Addr *, Dwarf_Addr *, Dwarf_Addr *, const char **, const char **);
64 int (*sym_dwfl_offline_section_address)(Dwfl_Module *, void **, const char *, Dwarf_Addr, const char *, GElf_Word, const GElf_Shdr *, Dwarf_Addr *);
65 int (*sym_dwfl_report_end)(Dwfl *, int (*)(Dwfl_Module *, void *, const char *, Dwarf_Addr, void *), void *);
66 int (*sym_dwfl_standard_find_debuginfo)(Dwfl_Module *, void **, const char *, Dwarf_Addr, const char *, const char *, GElf_Word, char **);
67 int (*sym_dwfl_thread_getframes)(Dwfl_Thread *, int (*)(Dwfl_Frame *, void *), void *);
68 pid_t (*sym_dwfl_thread_tid)(Dwfl_Thread *);
69
70 /* libelf symbols */
71 Elf *(*sym_elf_begin)(int, Elf_Cmd, Elf *);
72 int (*sym_elf_end)(Elf *);
73 Elf_Data *(*sym_elf_getdata_rawchunk)(Elf *, int64_t, size_t, Elf_Type);
74 GElf_Ehdr *(*sym_gelf_getehdr)(Elf *, GElf_Ehdr *);
75 int (*sym_elf_getphdrnum)(Elf *, size_t *);
76 const char *(*sym_elf_errmsg)(int);
77 int (*sym_elf_errno)(void);
78 Elf *(*sym_elf_memory)(char *, size_t);
79 unsigned int (*sym_elf_version)(unsigned int);
80 GElf_Phdr *(*sym_gelf_getphdr)(Elf *, int, GElf_Phdr *);
81 size_t (*sym_gelf_getnote)(Elf_Data *, size_t, GElf_Nhdr *, size_t *, size_t *);
82
83 int dlopen_dw(void) {
84 int r;
85
86 r = dlopen_many_sym_or_warn(
87 &dw_dl, "libdw.so.1", LOG_DEBUG,
88 DLSYM_ARG(dwarf_getscopes),
89 DLSYM_ARG(dwarf_getscopes_die),
90 DLSYM_ARG(dwarf_tag),
91 DLSYM_ARG(dwarf_attr_integrate),
92 DLSYM_ARG(dwarf_formstring),
93 DLSYM_ARG(dwarf_diename),
94 DLSYM_ARG(dwelf_elf_gnu_build_id),
95 DLSYM_ARG(dwelf_elf_begin),
96 #if HAVE_DWELF_ELF_E_MACHINE_STRING
97 DLSYM_ARG(dwelf_elf_e_machine_string),
98 #endif
99 DLSYM_ARG(dwfl_addrmodule),
100 DLSYM_ARG(dwfl_frame_pc),
101 DLSYM_ARG(dwfl_module_addrdie),
102 DLSYM_ARG(dwfl_module_addrname),
103 DLSYM_ARG(dwfl_module_info),
104 DLSYM_ARG(dwfl_module_build_id),
105 DLSYM_ARG(dwfl_module_getelf),
106 DLSYM_ARG(dwfl_begin),
107 DLSYM_ARG(dwfl_core_file_report),
108 DLSYM_ARG(dwfl_report_end),
109 DLSYM_ARG(dwfl_getmodules),
110 DLSYM_ARG(dwfl_core_file_attach),
111 DLSYM_ARG(dwfl_end),
112 DLSYM_ARG(dwfl_errmsg),
113 DLSYM_ARG(dwfl_errno),
114 DLSYM_ARG(dwfl_build_id_find_elf),
115 DLSYM_ARG(dwfl_standard_find_debuginfo),
116 DLSYM_ARG(dwfl_thread_tid),
117 DLSYM_ARG(dwfl_thread_getframes),
118 DLSYM_ARG(dwfl_getthreads),
119 DLSYM_ARG(dwfl_offline_section_address));
120 if (r <= 0)
121 return r;
122
123 return 1;
124 }
125
126 int dlopen_elf(void) {
127 int r;
128
129 r = dlopen_many_sym_or_warn(
130 &elf_dl, "libelf.so.1", LOG_DEBUG,
131 DLSYM_ARG(elf_begin),
132 DLSYM_ARG(elf_end),
133 DLSYM_ARG(elf_getphdrnum),
134 DLSYM_ARG(elf_getdata_rawchunk),
135 DLSYM_ARG(elf_errmsg),
136 DLSYM_ARG(elf_errno),
137 DLSYM_ARG(elf_memory),
138 DLSYM_ARG(elf_version),
139 DLSYM_ARG(gelf_getehdr),
140 DLSYM_ARG(gelf_getphdr),
141 DLSYM_ARG(gelf_getnote));
142 if (r <= 0)
143 return r;
144
145 return 1;
146 }
147
148 typedef struct StackContext {
149 FILE *f;
150 Dwfl *dwfl;
151 Elf *elf;
152 unsigned n_thread;
153 unsigned n_frame;
154 JsonVariant **package_metadata;
155 Set **modules;
156 } StackContext;
157
158 static StackContext* stack_context_destroy(StackContext *c) {
159 if (!c)
160 return NULL;
161
162 c->f = safe_fclose(c->f);
163
164 if (c->dwfl) {
165 sym_dwfl_end(c->dwfl);
166 c->dwfl = NULL;
167 }
168
169 if (c->elf) {
170 sym_elf_end(c->elf);
171 c->elf = NULL;
172 }
173
174 return NULL;
175 }
176
177 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(Elf *, sym_elf_end, NULL);
178
179 static int frame_callback(Dwfl_Frame *frame, void *userdata) {
180 StackContext *c = ASSERT_PTR(userdata);
181 Dwarf_Addr pc, pc_adjusted;
182 const char *fname = NULL, *symbol = NULL;
183 Dwfl_Module *module;
184 bool is_activation;
185 uint64_t module_offset = 0;
186
187 assert(frame);
188
189 if (c->n_frame >= FRAMES_MAX)
190 return DWARF_CB_ABORT;
191
192 if (!sym_dwfl_frame_pc(frame, &pc, &is_activation))
193 return DWARF_CB_ABORT;
194
195 pc_adjusted = pc - (is_activation ? 0 : 1);
196
197 module = sym_dwfl_addrmodule(c->dwfl, pc_adjusted);
198 if (module) {
199 Dwarf_Addr start, bias = 0;
200 Dwarf_Die *cudie;
201
202 cudie = sym_dwfl_module_addrdie(module, pc_adjusted, &bias);
203 if (cudie) {
204 _cleanup_free_ Dwarf_Die *scopes = NULL;
205 int n;
206
207 n = sym_dwarf_getscopes(cudie, pc_adjusted - bias, &scopes);
208 if (n > 0)
209 for (Dwarf_Die *s = scopes; s && s < scopes + n; s++) {
210 Dwarf_Attribute *a, space;
211
212 if (!IN_SET(sym_dwarf_tag(s), DW_TAG_subprogram, DW_TAG_inlined_subroutine, DW_TAG_entry_point))
213 continue;
214
215 a = sym_dwarf_attr_integrate(s, DW_AT_MIPS_linkage_name, &space);
216 if (!a)
217 a = sym_dwarf_attr_integrate(s, DW_AT_linkage_name, &space);
218 if (a)
219 symbol = sym_dwarf_formstring(a);
220 if (!symbol)
221 symbol = sym_dwarf_diename(s);
222
223 if (symbol)
224 break;
225 }
226 }
227
228 if (!symbol)
229 symbol = sym_dwfl_module_addrname(module, pc_adjusted);
230
231 fname = sym_dwfl_module_info(module, NULL, &start, NULL, NULL, NULL, NULL, NULL);
232 module_offset = pc - start;
233 }
234
235 if (c->f)
236 fprintf(c->f, "#%-2u 0x%016" PRIx64 " %s (%s + 0x%" PRIx64 ")\n", c->n_frame, (uint64_t) pc, strna(symbol), strna(fname), module_offset);
237 c->n_frame++;
238
239 return DWARF_CB_OK;
240 }
241
242 static int thread_callback(Dwfl_Thread *thread, void *userdata) {
243 StackContext *c = ASSERT_PTR(userdata);
244 pid_t tid;
245
246 assert(thread);
247
248 if (c->n_thread >= THREADS_MAX)
249 return DWARF_CB_ABORT;
250
251 if (c->n_thread != 0 && c->f)
252 fputc('\n', c->f);
253
254 c->n_frame = 0;
255
256 if (c->f) {
257 tid = sym_dwfl_thread_tid(thread);
258 fprintf(c->f, "Stack trace of thread " PID_FMT ":\n", tid);
259 }
260
261 if (sym_dwfl_thread_getframes(thread, frame_callback, c) < 0)
262 return DWARF_CB_ABORT;
263
264 c->n_thread++;
265
266 return DWARF_CB_OK;
267 }
268
269 static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *elf, bool *ret_interpreter_found, StackContext *c) {
270 bool interpreter_found = false;
271 size_t n_program_headers;
272 int r;
273
274 assert(name);
275 assert(elf);
276 assert(c);
277
278 /* When iterating over PT_LOAD we will visit modules more than once */
279 if (set_contains(*c->modules, name))
280 return 0;
281
282 r = sym_elf_getphdrnum(elf, &n_program_headers);
283 if (r < 0) /* Not the handle we are looking for - that's ok, skip it */
284 return 0;
285
286 /* Iterate over all program headers in that ELF object. These will have been copied by
287 * the kernel verbatim when the core file is generated. */
288 for (size_t i = 0; i < n_program_headers; ++i) {
289 GElf_Phdr mem, *program_header;
290 GElf_Nhdr note_header;
291 Elf_Data *data;
292
293 /* Package metadata is in PT_NOTE headers. */
294 program_header = sym_gelf_getphdr(elf, i, &mem);
295 if (!program_header || (program_header->p_type != PT_NOTE && program_header->p_type != PT_INTERP))
296 continue;
297
298 if (program_header->p_type == PT_INTERP) {
299 interpreter_found = true;
300 continue;
301 }
302
303 /* Fortunately there is an iterator we can use to walk over the
304 * elements of a PT_NOTE program header. We are interested in the
305 * note with type. */
306 data = sym_elf_getdata_rawchunk(elf,
307 program_header->p_offset,
308 program_header->p_filesz,
309 ELF_T_NHDR);
310 if (!data)
311 continue;
312
313 for (size_t note_offset = 0, name_offset, desc_offset;
314 note_offset < data->d_size &&
315 (note_offset = sym_gelf_getnote(data, note_offset, &note_header, &name_offset, &desc_offset)) > 0;) {
316
317 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
318 const char *note_name = (const char *)data->d_buf + name_offset;
319 const char *payload = (const char *)data->d_buf + desc_offset;
320
321 if (note_header.n_namesz == 0 || note_header.n_descsz == 0)
322 continue;
323
324 /* Package metadata might have different owners, but the
325 * magic ID is always the same. */
326 if (note_header.n_type != ELF_PACKAGE_METADATA_ID)
327 continue;
328
329 r = json_parse(payload, 0, &v, NULL, NULL);
330 if (r < 0)
331 return log_error_errno(r, "json_parse on %s failed: %m", payload);
332
333 /* First pretty-print to the buffer, so that the metadata goes as
334 * plaintext in the journal. */
335 if (c->f) {
336 fprintf(c->f, "Metadata for module %s owned by %s found: ",
337 name, note_name);
338 json_variant_dump(v, JSON_FORMAT_NEWLINE|JSON_FORMAT_PRETTY, c->f, NULL);
339 fputc('\n', c->f);
340 }
341
342 /* Secondly, if we have a build-id, merge it in the same JSON object
343 * so that it appears all nicely together in the logs/metadata. */
344 if (id_json) {
345 r = json_variant_merge(&v, id_json);
346 if (r < 0)
347 return log_error_errno(r, "json_variant_merge of package meta with buildid failed: %m");
348 }
349
350 /* Then we build a new object using the module name as the key, and merge it
351 * with the previous parses, so that in the end it all fits together in a single
352 * JSON blob. */
353 r = json_build(&w, JSON_BUILD_OBJECT(JSON_BUILD_PAIR(name, JSON_BUILD_VARIANT(v))));
354 if (r < 0)
355 return log_error_errno(r, "Failed to build JSON object: %m");
356
357 r = json_variant_merge(c->package_metadata, w);
358 if (r < 0)
359 return log_error_errno(r, "json_variant_merge of package meta with buildid failed: %m");
360
361 /* Finally stash the name, so we avoid double visits. */
362 r = set_put_strdup(c->modules, name);
363 if (r < 0)
364 return log_error_errno(r, "set_put_strdup failed: %m");
365
366 if (ret_interpreter_found)
367 *ret_interpreter_found = interpreter_found;
368
369 return 1;
370 }
371 }
372
373 if (ret_interpreter_found)
374 *ret_interpreter_found = interpreter_found;
375
376 /* Didn't find package metadata for this module - that's ok, just go to the next. */
377 return 0;
378 }
379
380 /* Get the build-id out of an ELF object or a dwarf core module. */
381 static int parse_buildid(Dwfl_Module *mod, Elf *elf, const char *name, StackContext *c, JsonVariant **ret_id_json) {
382 _cleanup_(json_variant_unrefp) JsonVariant *id_json = NULL;
383 const unsigned char *id;
384 GElf_Addr id_vaddr;
385 ssize_t id_len;
386 int r;
387
388 assert(mod || elf);
389 assert(name);
390 assert(c);
391
392 if (mod)
393 id_len = sym_dwfl_module_build_id(mod, &id, &id_vaddr);
394 else
395 id_len = sym_dwelf_elf_gnu_build_id(elf, (const void **)&id);
396 if (id_len <= 0) {
397 /* If we don't find a build-id, note it in the journal message, and try
398 * anyway to find the package metadata. It's unlikely to have the latter
399 * without the former, but there's no hard rule. */
400 if (c->f)
401 fprintf(c->f, "Module %s without build-id.\n", name);
402 } else {
403 /* We will later parse package metadata json and pass it to our caller. Prepare the
404 * build-id in json format too, so that it can be appended and parsed cleanly. It
405 * will then be added as metadata to the journal message with the stack trace. */
406 r = json_build(&id_json, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("buildId", JSON_BUILD_HEX(id, id_len))));
407 if (r < 0)
408 return log_error_errno(r, "json_build on build-id failed: %m");
409
410 if (c->f) {
411 JsonVariant *build_id = json_variant_by_key(id_json, "buildId");
412 assert(build_id);
413 fprintf(c->f, "Module %s with build-id %s\n", name, json_variant_string(build_id));
414 }
415 }
416
417 if (ret_id_json)
418 *ret_id_json = TAKE_PTR(id_json);
419
420 return 0;
421 }
422
423 static int module_callback(Dwfl_Module *mod, void **userdata, const char *name, Dwarf_Addr start, void *arg) {
424 _cleanup_(json_variant_unrefp) JsonVariant *id_json = NULL;
425 StackContext *c = ASSERT_PTR(arg);
426 size_t n_program_headers;
427 GElf_Addr bias;
428 int r;
429 Elf *elf;
430
431 assert(mod);
432
433 if (!name)
434 name = "(unnamed)"; /* For logging purposes */
435
436 /* We are iterating on each "module", which is what dwfl calls ELF objects contained in the
437 * core file, and extracting the build-id first and then the package metadata.
438 * We proceed in a best-effort fashion - not all ELF objects might contain both or either.
439 * The build-id is easy, as libdwfl parses it during the sym_dwfl_core_file_report() call and
440 * stores it separately in an internal library struct. */
441 r = parse_buildid(mod, NULL, name, c, &id_json);
442 if (r < 0)
443 return DWARF_CB_ABORT;
444
445 /* The .note.package metadata is more difficult. From the module, we need to get a reference
446 * to the ELF object first. We might be lucky and just get it from elfutils. */
447 elf = sym_dwfl_module_getelf(mod, &bias);
448 if (elf) {
449 r = parse_package_metadata(name, id_json, elf, NULL, c);
450 if (r < 0)
451 return DWARF_CB_ABORT;
452 if (r > 0)
453 return DWARF_CB_OK;
454 } else
455 elf = c->elf;
456
457 /* We did not get the ELF object, or it's just a reference to the core. That is likely
458 * because we didn't get direct access to the executable, and the version of elfutils does
459 * not yet support parsing it out of the core file directly.
460 * So fallback to manual extraction - get the PT_LOAD section from the core,
461 * and if it's the right one we can interpret it as an Elf object, and parse
462 * its notes manually. */
463
464 r = sym_elf_getphdrnum(elf, &n_program_headers);
465 if (r < 0) {
466 log_warning("Could not parse number of program headers from core file: %s",
467 sym_elf_errmsg(-1)); /* -1 retrieves the most recent error */
468 return DWARF_CB_OK;
469 }
470
471 for (size_t i = 0; i < n_program_headers; ++i) {
472 GElf_Phdr mem, *program_header;
473 Elf_Data *data;
474
475 /* The core file stores the ELF files in the PT_LOAD segment. */
476 program_header = sym_gelf_getphdr(elf, i, &mem);
477 if (!program_header || program_header->p_type != PT_LOAD)
478 continue;
479
480 /* Now get a usable Elf reference, and parse the notes from it. */
481 data = sym_elf_getdata_rawchunk(elf,
482 program_header->p_offset,
483 program_header->p_filesz,
484 ELF_T_NHDR);
485 if (!data)
486 continue;
487
488 _cleanup_(sym_elf_endp) Elf *memelf = sym_elf_memory(data->d_buf, data->d_size);
489 if (!memelf)
490 continue;
491 r = parse_package_metadata(name, id_json, memelf, NULL, c);
492 if (r < 0)
493 return DWARF_CB_ABORT;
494 if (r > 0)
495 break;
496 }
497
498 return DWARF_CB_OK;
499 }
500
501 static int parse_core(int fd, const char *executable, char **ret, JsonVariant **ret_package_metadata) {
502
503 const Dwfl_Callbacks callbacks = {
504 .find_elf = sym_dwfl_build_id_find_elf,
505 .section_address = sym_dwfl_offline_section_address,
506 .find_debuginfo = sym_dwfl_standard_find_debuginfo,
507 };
508
509 _cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL;
510 _cleanup_(set_freep) Set *modules = NULL;
511 _cleanup_free_ char *buf = NULL; /* buf should be freed last, c.f closed first (via stack_context_destroy) */
512 _cleanup_(stack_context_destroy) StackContext c = {
513 .package_metadata = &package_metadata,
514 .modules = &modules,
515 };
516 size_t sz = 0;
517 int r;
518
519 assert(fd >= 0);
520
521 if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
522 return log_warning_errno(errno, "Failed to seek to beginning of the core file: %m");
523
524 if (ret) {
525 c.f = open_memstream_unlocked(&buf, &sz);
526 if (!c.f)
527 return log_oom();
528 }
529
530 sym_elf_version(EV_CURRENT);
531
532 c.elf = sym_elf_begin(fd, ELF_C_READ_MMAP, NULL);
533 if (!c.elf)
534 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, elf_begin() failed: %s", sym_elf_errmsg(sym_elf_errno()));
535
536 c.dwfl = sym_dwfl_begin(&callbacks);
537 if (!c.dwfl)
538 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_begin() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
539
540 if (sym_dwfl_core_file_report(c.dwfl, c.elf, executable) < 0)
541 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_core_file_report() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
542
543 if (sym_dwfl_report_end(c.dwfl, NULL, NULL) != 0)
544 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_report_end() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
545
546 if (sym_dwfl_getmodules(c.dwfl, &module_callback, &c, 0) < 0)
547 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_getmodules() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
548
549 if (sym_dwfl_core_file_attach(c.dwfl, c.elf) < 0)
550 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_core_file_attach() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
551
552 if (sym_dwfl_getthreads(c.dwfl, thread_callback, &c) < 0)
553 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_getthreads() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
554
555 if (ret) {
556 r = fflush_and_check(c.f);
557 if (r < 0)
558 return log_warning_errno(r, "Could not parse core file, flushing file buffer failed: %m");
559
560 c.f = safe_fclose(c.f);
561 *ret = TAKE_PTR(buf);
562 }
563 if (ret_package_metadata)
564 *ret_package_metadata = TAKE_PTR(package_metadata);
565
566 return 0;
567 }
568
569 static int parse_elf(int fd, const char *executable, char **ret, JsonVariant **ret_package_metadata) {
570 _cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL, *elf_metadata = NULL;
571 _cleanup_(set_freep) Set *modules = NULL;
572 _cleanup_free_ char *buf = NULL; /* buf should be freed last, c.f closed first (via stack_context_destroy) */
573 _cleanup_(stack_context_destroy) StackContext c = {
574 .package_metadata = &package_metadata,
575 .modules = &modules,
576 };
577 const char *elf_type;
578 GElf_Ehdr elf_header;
579 size_t sz = 0;
580 int r;
581
582 assert(fd >= 0);
583
584 if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
585 return log_warning_errno(errno, "Failed to seek to beginning of the ELF file: %m");
586
587 if (ret) {
588 c.f = open_memstream_unlocked(&buf, &sz);
589 if (!c.f)
590 return log_oom();
591 }
592
593 sym_elf_version(EV_CURRENT);
594
595 c.elf = sym_elf_begin(fd, ELF_C_READ_MMAP, NULL);
596 if (!c.elf)
597 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse ELF file, elf_begin() failed: %s", sym_elf_errmsg(sym_elf_errno()));
598
599 if (!sym_gelf_getehdr(c.elf, &elf_header))
600 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse ELF file, gelf_getehdr() failed: %s", sym_elf_errmsg(sym_elf_errno()));
601
602 if (elf_header.e_type == ET_CORE) {
603 _cleanup_free_ char *out = NULL;
604
605 r = parse_core(fd, executable, ret ? &out : NULL, &package_metadata);
606 if (r < 0)
607 return log_warning_errno(r, "Failed to inspect core file: %m");
608
609 if (out)
610 fprintf(c.f, "%s", out);
611
612 elf_type = "coredump";
613 } else {
614 _cleanup_(json_variant_unrefp) JsonVariant *id_json = NULL;
615 const char *e = executable ?: "(unnamed)";
616 bool interpreter_found = false;
617
618 r = parse_buildid(NULL, c.elf, e, &c, &id_json);
619 if (r < 0)
620 return log_warning_errno(r, "Failed to parse build-id of ELF file: %m");
621
622 r = parse_package_metadata(e, id_json, c.elf, &interpreter_found, &c);
623 if (r < 0)
624 return log_warning_errno(r, "Failed to parse package metadata of ELF file: %m");
625
626 /* If we found a build-id and nothing else, return at least that. */
627 if (!package_metadata && id_json) {
628 r = json_build(&package_metadata, JSON_BUILD_OBJECT(JSON_BUILD_PAIR(e, JSON_BUILD_VARIANT(id_json))));
629 if (r < 0)
630 return log_warning_errno(r, "Failed to build JSON object: %m");
631 }
632
633 if (interpreter_found)
634 elf_type = "executable";
635 else
636 elf_type = "library";
637 }
638
639 /* Note that e_type is always DYN for both executables and libraries, so we can't tell them apart from the header,
640 * but we will search for the PT_INTERP section when parsing the metadata. */
641 r = json_build(&elf_metadata, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("elfType", JSON_BUILD_STRING(elf_type))));
642 if (r < 0)
643 return log_warning_errno(r, "Failed to build JSON object: %m");
644
645 #if HAVE_DWELF_ELF_E_MACHINE_STRING
646 const char *elf_architecture = sym_dwelf_elf_e_machine_string(elf_header.e_machine);
647 if (elf_architecture) {
648 _cleanup_(json_variant_unrefp) JsonVariant *json_architecture = NULL;
649
650 r = json_build(&json_architecture,
651 JSON_BUILD_OBJECT(JSON_BUILD_PAIR("elfArchitecture", JSON_BUILD_STRING(elf_architecture))));
652 if (r < 0)
653 return log_warning_errno(r, "Failed to build JSON object: %m");
654
655 r = json_variant_merge(&elf_metadata, json_architecture);
656 if (r < 0)
657 return log_warning_errno(r, "Failed to merge JSON objects: %m");
658
659 if (ret)
660 fprintf(c.f, "ELF object binary architecture: %s\n", elf_architecture);
661 }
662 #endif
663
664 /* We always at least have the ELF type, so merge that (and possibly the arch). */
665 r = json_variant_merge(&elf_metadata, package_metadata);
666 if (r < 0)
667 return log_warning_errno(r, "Failed to merge JSON objects: %m");
668
669 if (ret) {
670 r = fflush_and_check(c.f);
671 if (r < 0)
672 return log_warning_errno(r, "Could not parse ELF file, flushing file buffer failed: %m");
673
674 c.f = safe_fclose(c.f);
675 *ret = TAKE_PTR(buf);
676 }
677 if (ret_package_metadata)
678 *ret_package_metadata = TAKE_PTR(elf_metadata);
679
680 return 0;
681 }
682
683 int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, char **ret, JsonVariant **ret_package_metadata) {
684 _cleanup_close_pair_ int error_pipe[2] = { -1, -1 }, return_pipe[2] = { -1, -1 }, json_pipe[2] = { -1, -1 };
685 _cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL;
686 _cleanup_free_ char *buf = NULL;
687 int r;
688
689 assert(fd >= 0);
690
691 r = dlopen_dw();
692 if (r < 0)
693 return r;
694
695 r = dlopen_elf();
696 if (r < 0)
697 return r;
698
699 r = RET_NERRNO(pipe2(error_pipe, O_CLOEXEC|O_NONBLOCK));
700 if (r < 0)
701 return r;
702
703 if (ret) {
704 r = RET_NERRNO(pipe2(return_pipe, O_CLOEXEC));
705 if (r < 0)
706 return r;
707 }
708
709 if (ret_package_metadata) {
710 r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC));
711 if (r < 0)
712 return r;
713 }
714
715 /* Parsing possibly malformed data is crash-happy, so fork. In case we crash,
716 * the core file will not be lost, and the messages will still be attached to
717 * the journal. Reading the elf object might be slow, but it still has an upper
718 * bound since the core files have an upper size limit. It's also not doing any
719 * system call or interacting with the system in any way, besides reading from
720 * the file descriptor and writing into these four pipes. */
721 r = safe_fork_full("(sd-parse-elf)",
722 (int[]){ fd, error_pipe[1], return_pipe[1], json_pipe[1] },
723 4,
724 FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS|FORK_WAIT|FORK_REOPEN_LOG,
725 NULL);
726 if (r < 0) {
727 if (r == -EPROTO) { /* We should have the errno from the child, but don't clobber original error */
728 int e, k;
729
730 k = read(error_pipe[0], &e, sizeof(e));
731 if (k < 0 && errno != EAGAIN) /* Pipe is non-blocking, EAGAIN means there's nothing */
732 return -errno;
733 if (k == sizeof(e))
734 return e; /* propagate error sent to us from child */
735 if (k != 0)
736 return -EIO;
737 }
738
739 return r;
740 }
741 if (r == 0) {
742 /* We want to avoid loops, given this can be called from systemd-coredump */
743 if (fork_disable_dump) {
744 r = RET_NERRNO(prctl(PR_SET_DUMPABLE, 0));
745 if (r < 0)
746 goto child_fail;
747 }
748
749 r = parse_elf(fd, executable, ret ? &buf : NULL, ret_package_metadata ? &package_metadata : NULL);
750 if (r < 0)
751 goto child_fail;
752
753 if (buf) {
754 r = loop_write(return_pipe[1], buf, strlen(buf), false);
755 if (r < 0)
756 goto child_fail;
757
758 return_pipe[1] = safe_close(return_pipe[1]);
759 }
760
761 if (package_metadata) {
762 _cleanup_fclose_ FILE *json_out = NULL;
763
764 json_out = take_fdopen(&json_pipe[1], "w");
765 if (!json_out) {
766 r = -errno;
767 goto child_fail;
768 }
769
770 json_variant_dump(package_metadata, JSON_FORMAT_FLUSH, json_out, NULL);
771 }
772
773 _exit(EXIT_SUCCESS);
774
775 child_fail:
776 (void) write(error_pipe[1], &r, sizeof(r));
777 _exit(EXIT_FAILURE);
778 }
779
780 error_pipe[1] = safe_close(error_pipe[1]);
781 return_pipe[1] = safe_close(return_pipe[1]);
782 json_pipe[1] = safe_close(json_pipe[1]);
783
784 if (ret) {
785 _cleanup_fclose_ FILE *in = NULL;
786
787 in = take_fdopen(&return_pipe[0], "r");
788 if (!in)
789 return -errno;
790
791 r = read_full_stream(in, &buf, NULL);
792 if (r < 0)
793 return r;
794 }
795
796 if (ret_package_metadata) {
797 _cleanup_fclose_ FILE *json_in = NULL;
798
799 json_in = take_fdopen(&json_pipe[0], "r");
800 if (!json_in)
801 return -errno;
802
803 r = json_parse_file(json_in, NULL, 0, &package_metadata, NULL, NULL);
804 if (r < 0 && r != -EINVAL) /* EINVAL: json was empty, so we got nothing, but that's ok */
805 return r;
806 }
807
808 if (ret)
809 *ret = TAKE_PTR(buf);
810 if (ret_package_metadata)
811 *ret_package_metadata = TAKE_PTR(package_metadata);
812
813 return 0;
814 }
815
816 #endif