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