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