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, &note_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