]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/coredump/coredump.c
dhcp6: fix uninitialized variable in returning from client_parse_message() (#8187)
[thirdparty/systemd.git] / src / coredump / coredump.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1+ */
2/***
3 This file is part of systemd.
4
5 Copyright 2012 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <errno.h>
22#include <stdio.h>
23#include <stdio_ext.h>
24#include <sys/prctl.h>
25#include <sys/xattr.h>
26#include <unistd.h>
27
28#if HAVE_ELFUTILS
29#include <dwarf.h>
30#include <elfutils/libdwfl.h>
31#endif
32
33#include "sd-daemon.h"
34#include "sd-journal.h"
35#include "sd-login.h"
36#include "sd-messages.h"
37
38#include "acl-util.h"
39#include "alloc-util.h"
40#include "capability-util.h"
41#include "cgroup-util.h"
42#include "compress.h"
43#include "conf-parser.h"
44#include "copy.h"
45#include "coredump-vacuum.h"
46#include "dirent-util.h"
47#include "escape.h"
48#include "fd-util.h"
49#include "fileio.h"
50#include "fs-util.h"
51#include "io-util.h"
52#include "journal-importer.h"
53#include "log.h"
54#include "macro.h"
55#include "missing.h"
56#include "mkdir.h"
57#include "parse-util.h"
58#include "process-util.h"
59#include "signal-util.h"
60#include "socket-util.h"
61#include "special.h"
62#include "stacktrace.h"
63#include "string-table.h"
64#include "string-util.h"
65#include "strv.h"
66#include "user-util.h"
67#include "util.h"
68
69/* The maximum size up to which we process coredumps */
70#define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU))
71
72/* The maximum size up to which we leave the coredump around on disk */
73#define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
74
75/* The maximum size up to which we store the coredump in the journal */
76#define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
77
78/* Make sure to not make this larger than the maximum journal entry
79 * size. See DATA_SIZE_MAX in journald-native.c. */
80assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
81
82enum {
83 /* We use this as array indexes for a couple of special fields we use for
84 * naming coredump files, and attaching xattrs, and for indexing argv[].
85
86 * Our pattern for man:systectl(1) kernel.core_pattern is such that the
87 * kernel passes fields until CONTEXT_RLIMIT as arguments in argv[]. After
88 * that it gets complicated: the kernel passes "comm" as one or more fields
89 * starting at index CONTEXT_COMM (in other words, full "comm" is under index
90 * CONTEXT_COMM when it does not contain spaces, which is the common
91 * case). This mapping is not reversible, so we prefer to retrieve "comm"
92 * from /proc. We only fall back to argv[CONTEXT_COMM...] when that fails.
93 *
94 * In the internal context[] array, fields before CONTEXT_COMM are the
95 * strings from argv[], so they should not be freed. The strings at indices
96 * CONTEXT_COMM and higher are allocated by us and should be freed at the
97 * end.
98 */
99 CONTEXT_PID,
100 CONTEXT_UID,
101 CONTEXT_GID,
102 CONTEXT_SIGNAL,
103 CONTEXT_TIMESTAMP,
104 CONTEXT_RLIMIT,
105 CONTEXT_COMM,
106 CONTEXT_EXE,
107 CONTEXT_UNIT,
108 _CONTEXT_MAX
109};
110
111typedef enum CoredumpStorage {
112 COREDUMP_STORAGE_NONE,
113 COREDUMP_STORAGE_EXTERNAL,
114 COREDUMP_STORAGE_JOURNAL,
115 _COREDUMP_STORAGE_MAX,
116 _COREDUMP_STORAGE_INVALID = -1
117} CoredumpStorage;
118
119static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
120 [COREDUMP_STORAGE_NONE] = "none",
121 [COREDUMP_STORAGE_EXTERNAL] = "external",
122 [COREDUMP_STORAGE_JOURNAL] = "journal",
123};
124
125DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
126static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
127
128static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
129static bool arg_compress = true;
130static uint64_t arg_process_size_max = PROCESS_SIZE_MAX;
131static uint64_t arg_external_size_max = EXTERNAL_SIZE_MAX;
132static uint64_t arg_journal_size_max = JOURNAL_SIZE_MAX;
133static uint64_t arg_keep_free = (uint64_t) -1;
134static uint64_t arg_max_use = (uint64_t) -1;
135
136static int parse_config(void) {
137 static const ConfigTableItem items[] = {
138 { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
139 { "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
140 { "Coredump", "ProcessSizeMax", config_parse_iec_uint64, 0, &arg_process_size_max },
141 { "Coredump", "ExternalSizeMax", config_parse_iec_uint64, 0, &arg_external_size_max },
142 { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
143 { "Coredump", "KeepFree", config_parse_iec_uint64, 0, &arg_keep_free },
144 { "Coredump", "MaxUse", config_parse_iec_uint64, 0, &arg_max_use },
145 {}
146 };
147
148 return config_parse_many_nulstr(PKGSYSCONFDIR "/coredump.conf",
149 CONF_PATHS_NULSTR("systemd/coredump.conf.d"),
150 "Coredump\0",
151 config_item_table_lookup, items,
152 CONFIG_PARSE_WARN, NULL);
153}
154
155static inline uint64_t storage_size_max(void) {
156 return arg_storage == COREDUMP_STORAGE_EXTERNAL ? arg_external_size_max : arg_journal_size_max;
157}
158
159static int fix_acl(int fd, uid_t uid) {
160
161#if HAVE_ACL
162 _cleanup_(acl_freep) acl_t acl = NULL;
163 acl_entry_t entry;
164 acl_permset_t permset;
165 int r;
166
167 assert(fd >= 0);
168
169 if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
170 return 0;
171
172 /* Make sure normal users can read (but not write or delete)
173 * their own coredumps */
174
175 acl = acl_get_fd(fd);
176 if (!acl)
177 return log_error_errno(errno, "Failed to get ACL: %m");
178
179 if (acl_create_entry(&acl, &entry) < 0 ||
180 acl_set_tag_type(entry, ACL_USER) < 0 ||
181 acl_set_qualifier(entry, &uid) < 0)
182 return log_error_errno(errno, "Failed to patch ACL: %m");
183
184 if (acl_get_permset(entry, &permset) < 0 ||
185 acl_add_perm(permset, ACL_READ) < 0)
186 return log_warning_errno(errno, "Failed to patch ACL: %m");
187
188 r = calc_acl_mask_if_needed(&acl);
189 if (r < 0)
190 return log_warning_errno(r, "Failed to patch ACL: %m");
191
192 if (acl_set_fd(fd, acl) < 0)
193 return log_error_errno(errno, "Failed to apply ACL: %m");
194#endif
195
196 return 0;
197}
198
199static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
200
201 static const char * const xattrs[_CONTEXT_MAX] = {
202 [CONTEXT_PID] = "user.coredump.pid",
203 [CONTEXT_UID] = "user.coredump.uid",
204 [CONTEXT_GID] = "user.coredump.gid",
205 [CONTEXT_SIGNAL] = "user.coredump.signal",
206 [CONTEXT_TIMESTAMP] = "user.coredump.timestamp",
207 [CONTEXT_RLIMIT] = "user.coredump.rlimit",
208 [CONTEXT_COMM] = "user.coredump.comm",
209 [CONTEXT_EXE] = "user.coredump.exe",
210 };
211
212 int r = 0;
213 unsigned i;
214
215 assert(fd >= 0);
216
217 /* Attach some metadata to coredumps via extended
218 * attributes. Just because we can. */
219
220 for (i = 0; i < _CONTEXT_MAX; i++) {
221 int k;
222
223 if (isempty(context[i]) || !xattrs[i])
224 continue;
225
226 k = fsetxattr(fd, xattrs[i], context[i], strlen(context[i]), XATTR_CREATE);
227 if (k < 0 && r == 0)
228 r = -errno;
229 }
230
231 return r;
232}
233
234#define filename_escape(s) xescape((s), "./ ")
235
236static inline const char *coredump_tmpfile_name(const char *s) {
237 return s ? s : "(unnamed temporary file)";
238}
239
240static int fix_permissions(
241 int fd,
242 const char *filename,
243 const char *target,
244 const char *context[_CONTEXT_MAX],
245 uid_t uid) {
246
247 int r;
248
249 assert(fd >= 0);
250 assert(target);
251 assert(context);
252
253 /* Ignore errors on these */
254 (void) fchmod(fd, 0640);
255 (void) fix_acl(fd, uid);
256 (void) fix_xattr(fd, context);
257
258 if (fsync(fd) < 0)
259 return log_error_errno(errno, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename));
260
261 r = link_tmpfile(fd, filename, target);
262 if (r < 0)
263 return log_error_errno(r, "Failed to move coredump %s into place: %m", target);
264
265 return 0;
266}
267
268static int maybe_remove_external_coredump(const char *filename, uint64_t size) {
269
270 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
271
272 if (arg_storage == COREDUMP_STORAGE_EXTERNAL &&
273 size <= arg_external_size_max)
274 return 0;
275
276 if (!filename)
277 return 1;
278
279 if (unlink(filename) < 0 && errno != ENOENT)
280 return log_error_errno(errno, "Failed to unlink %s: %m", filename);
281
282 return 1;
283}
284
285static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
286 _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
287 sd_id128_t boot = {};
288 int r;
289
290 assert(context);
291
292 c = filename_escape(context[CONTEXT_COMM]);
293 if (!c)
294 return -ENOMEM;
295
296 u = filename_escape(context[CONTEXT_UID]);
297 if (!u)
298 return -ENOMEM;
299
300 r = sd_id128_get_boot(&boot);
301 if (r < 0)
302 return r;
303
304 p = filename_escape(context[CONTEXT_PID]);
305 if (!p)
306 return -ENOMEM;
307
308 t = filename_escape(context[CONTEXT_TIMESTAMP]);
309 if (!t)
310 return -ENOMEM;
311
312 if (asprintf(ret,
313 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
314 c,
315 u,
316 SD_ID128_FORMAT_VAL(boot),
317 p,
318 t) < 0)
319 return -ENOMEM;
320
321 return 0;
322}
323
324static int save_external_coredump(
325 const char *context[_CONTEXT_MAX],
326 int input_fd,
327 char **ret_filename,
328 int *ret_node_fd,
329 int *ret_data_fd,
330 uint64_t *ret_size,
331 bool *ret_truncated) {
332
333 _cleanup_free_ char *fn = NULL, *tmp = NULL;
334 _cleanup_close_ int fd = -1;
335 uint64_t rlimit, max_size;
336 struct stat st;
337 uid_t uid;
338 int r;
339
340 assert(context);
341 assert(ret_filename);
342 assert(ret_node_fd);
343 assert(ret_data_fd);
344 assert(ret_size);
345
346 r = parse_uid(context[CONTEXT_UID], &uid);
347 if (r < 0)
348 return log_error_errno(r, "Failed to parse UID: %m");
349
350 r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit);
351 if (r < 0)
352 return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]);
353 if (rlimit < page_size()) {
354 /* Is coredumping disabled? Then don't bother saving/processing the coredump.
355 * Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses
356 * ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */
357 log_info("Resource limits disable core dumping for process %s (%s).",
358 context[CONTEXT_PID], context[CONTEXT_COMM]);
359 return -EBADSLT;
360 }
361
362 /* Never store more than the process configured, or than we actually shall keep or process */
363 max_size = MIN(rlimit, MAX(arg_process_size_max, storage_size_max()));
364
365 r = make_filename(context, &fn);
366 if (r < 0)
367 return log_error_errno(r, "Failed to determine coredump file name: %m");
368
369 mkdir_p_label("/var/lib/systemd/coredump", 0755);
370
371 fd = open_tmpfile_linkable(fn, O_RDWR|O_CLOEXEC, &tmp);
372 if (fd < 0)
373 return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn);
374
375 r = copy_bytes(input_fd, fd, max_size, 0);
376 if (r < 0) {
377 log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]);
378 goto fail;
379 }
380 *ret_truncated = r == 1;
381 if (*ret_truncated)
382 log_struct(LOG_INFO,
383 LOG_MESSAGE("Core file was truncated to %zu bytes.", max_size),
384 "SIZE_LIMIT=%zu", max_size,
385 "MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR,
386 NULL);
387
388 if (fstat(fd, &st) < 0) {
389 log_error_errno(errno, "Failed to fstat core file %s: %m", coredump_tmpfile_name(tmp));
390 goto fail;
391 }
392
393 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
394 log_error_errno(errno, "Failed to seek on %s: %m", coredump_tmpfile_name(tmp));
395 goto fail;
396 }
397
398#if HAVE_XZ || HAVE_LZ4
399 /* If we will remove the coredump anyway, do not compress. */
400 if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) {
401
402 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
403 _cleanup_close_ int fd_compressed = -1;
404
405 fn_compressed = strappend(fn, COMPRESSED_EXT);
406 if (!fn_compressed) {
407 log_oom();
408 goto uncompressed;
409 }
410
411 fd_compressed = open_tmpfile_linkable(fn_compressed, O_RDWR|O_CLOEXEC, &tmp_compressed);
412 if (fd_compressed < 0) {
413 log_error_errno(fd_compressed, "Failed to create temporary file for coredump %s: %m", fn_compressed);
414 goto uncompressed;
415 }
416
417 r = compress_stream(fd, fd_compressed, -1);
418 if (r < 0) {
419 log_error_errno(r, "Failed to compress %s: %m", coredump_tmpfile_name(tmp_compressed));
420 goto fail_compressed;
421 }
422
423 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid);
424 if (r < 0)
425 goto fail_compressed;
426
427 /* OK, this worked, we can get rid of the uncompressed version now */
428 if (tmp)
429 unlink_noerrno(tmp);
430
431 *ret_filename = fn_compressed; /* compressed */
432 *ret_node_fd = fd_compressed; /* compressed */
433 *ret_data_fd = fd; /* uncompressed */
434 *ret_size = (uint64_t) st.st_size; /* uncompressed */
435
436 fn_compressed = NULL;
437 fd = fd_compressed = -1;
438
439 return 0;
440
441 fail_compressed:
442 if (tmp_compressed)
443 (void) unlink(tmp_compressed);
444 }
445
446uncompressed:
447#endif
448
449 r = fix_permissions(fd, tmp, fn, context, uid);
450 if (r < 0)
451 goto fail;
452
453 *ret_filename = fn;
454 *ret_data_fd = fd;
455 *ret_node_fd = -1;
456 *ret_size = (uint64_t) st.st_size;
457
458 fn = NULL;
459 fd = -1;
460
461 return 0;
462
463fail:
464 if (tmp)
465 (void) unlink(tmp);
466 return r;
467}
468
469static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
470 _cleanup_free_ char *field = NULL;
471 ssize_t n;
472
473 assert(fd >= 0);
474 assert(ret);
475 assert(ret_size);
476
477 if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
478 return log_warning_errno(errno, "Failed to seek: %m");
479
480 field = malloc(9 + size);
481 if (!field) {
482 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
483 return -ENOMEM;
484 }
485
486 memcpy(field, "COREDUMP=", 9);
487
488 n = read(fd, field + 9, size);
489 if (n < 0)
490 return log_error_errno((int) n, "Failed to read core data: %m");
491 if ((size_t) n < size) {
492 log_error("Core data too short.");
493 return -EIO;
494 }
495
496 *ret = field;
497 *ret_size = size + 9;
498
499 field = NULL;
500
501 return 0;
502}
503
504/* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
505 * 0:/dev/pts/23
506 * pos: 0
507 * flags: 0100002
508 *
509 * 1:/dev/pts/23
510 * pos: 0
511 * flags: 0100002
512 *
513 * 2:/dev/pts/23
514 * pos: 0
515 * flags: 0100002
516 * EOF
517 */
518static int compose_open_fds(pid_t pid, char **open_fds) {
519 _cleanup_closedir_ DIR *proc_fd_dir = NULL;
520 _cleanup_close_ int proc_fdinfo_fd = -1;
521 _cleanup_free_ char *buffer = NULL;
522 _cleanup_fclose_ FILE *stream = NULL;
523 const char *fddelim = "", *path;
524 struct dirent *dent = NULL;
525 size_t size = 0;
526 int r = 0;
527
528 assert(pid >= 0);
529 assert(open_fds != NULL);
530
531 path = procfs_file_alloca(pid, "fd");
532 proc_fd_dir = opendir(path);
533 if (!proc_fd_dir)
534 return -errno;
535
536 proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo", O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
537 if (proc_fdinfo_fd < 0)
538 return -errno;
539
540 stream = open_memstream(&buffer, &size);
541 if (!stream)
542 return -ENOMEM;
543
544 (void) __fsetlocking(stream, FSETLOCKING_BYCALLER);
545
546 FOREACH_DIRENT(dent, proc_fd_dir, return -errno) {
547 _cleanup_fclose_ FILE *fdinfo = NULL;
548 _cleanup_free_ char *fdname = NULL;
549 char line[LINE_MAX];
550 int fd;
551
552 r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
553 if (r < 0)
554 return r;
555
556 fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
557 fddelim = "\n";
558
559 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
560 fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
561 if (fd < 0)
562 continue;
563
564 fdinfo = fdopen(fd, "re");
565 if (!fdinfo) {
566 safe_close(fd);
567 continue;
568 }
569
570 FOREACH_LINE(line, fdinfo, break) {
571 fputs(line, stream);
572 if (!endswith(line, "\n"))
573 fputc('\n', stream);
574 }
575 }
576
577 errno = 0;
578 stream = safe_fclose(stream);
579
580 if (errno > 0)
581 return -errno;
582
583 *open_fds = buffer;
584 buffer = NULL;
585
586 return 0;
587}
588
589static int get_process_ns(pid_t pid, const char *namespace, ino_t *ns) {
590 const char *p;
591 struct stat stbuf;
592 _cleanup_close_ int proc_ns_dir_fd;
593
594 p = procfs_file_alloca(pid, "ns");
595
596 proc_ns_dir_fd = open(p, O_DIRECTORY | O_CLOEXEC | O_RDONLY);
597 if (proc_ns_dir_fd < 0)
598 return -errno;
599
600 if (fstatat(proc_ns_dir_fd, namespace, &stbuf, /* flags */0) < 0)
601 return -errno;
602
603 *ns = stbuf.st_ino;
604 return 0;
605}
606
607static int get_mount_namespace_leader(pid_t pid, pid_t *container_pid) {
608 pid_t cpid = pid, ppid = 0;
609 ino_t proc_mntns;
610 int r = 0;
611
612 r = get_process_ns(pid, "mnt", &proc_mntns);
613 if (r < 0)
614 return r;
615
616 for (;;) {
617 ino_t parent_mntns;
618
619 r = get_process_ppid(cpid, &ppid);
620 if (r < 0)
621 return r;
622
623 r = get_process_ns(ppid, "mnt", &parent_mntns);
624 if (r < 0)
625 return r;
626
627 if (proc_mntns != parent_mntns)
628 break;
629
630 if (ppid == 1)
631 return -ENOENT;
632
633 cpid = ppid;
634 }
635
636 *container_pid = ppid;
637 return 0;
638}
639
640/* Returns 1 if the parent was found.
641 * Returns 0 if there is not a process we can call the pid's
642 * container parent (the pid's process isn't 'containerized').
643 * Returns a negative number on errors.
644 */
645static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) {
646 int r = 0;
647 pid_t container_pid;
648 const char *proc_root_path;
649 struct stat root_stat, proc_root_stat;
650
651 /* To compare inodes of / and /proc/[pid]/root */
652 if (stat("/", &root_stat) < 0)
653 return -errno;
654
655 proc_root_path = procfs_file_alloca(pid, "root");
656 if (stat(proc_root_path, &proc_root_stat) < 0)
657 return -errno;
658
659 /* The process uses system root. */
660 if (proc_root_stat.st_ino == root_stat.st_ino) {
661 *cmdline = NULL;
662 return 0;
663 }
664
665 r = get_mount_namespace_leader(pid, &container_pid);
666 if (r < 0)
667 return r;
668
669 r = get_process_cmdline(container_pid, 0, false, cmdline);
670 if (r < 0)
671 return r;
672
673 return 1;
674}
675
676static int change_uid_gid(const char *context[]) {
677 uid_t uid;
678 gid_t gid;
679 int r;
680
681 r = parse_uid(context[CONTEXT_UID], &uid);
682 if (r < 0)
683 return r;
684
685 if (uid <= SYSTEM_UID_MAX) {
686 const char *user = "systemd-coredump";
687
688 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
689 if (r < 0) {
690 log_warning_errno(r, "Cannot resolve %s user. Proceeding to dump core as root: %m", user);
691 uid = gid = 0;
692 }
693 } else {
694 r = parse_gid(context[CONTEXT_GID], &gid);
695 if (r < 0)
696 return r;
697 }
698
699 return drop_privileges(uid, gid, 0);
700}
701
702static bool is_journald_crash(const char *context[_CONTEXT_MAX]) {
703 assert(context);
704
705 return streq_ptr(context[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE);
706}
707
708static bool is_pid1_crash(const char *context[_CONTEXT_MAX]) {
709 assert(context);
710
711 return streq_ptr(context[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) ||
712 streq_ptr(context[CONTEXT_PID], "1");
713}
714
715#define SUBMIT_COREDUMP_FIELDS 4
716
717static int submit_coredump(
718 const char *context[_CONTEXT_MAX],
719 struct iovec *iovec,
720 size_t n_iovec_allocated,
721 size_t n_iovec,
722 int input_fd) {
723
724 _cleanup_close_ int coredump_fd = -1, coredump_node_fd = -1;
725 _cleanup_free_ char *core_message = NULL, *filename = NULL, *coredump_data = NULL;
726 uint64_t coredump_size = UINT64_MAX;
727 bool truncated = false, journald_crash;
728 int r;
729
730 assert(context);
731 assert(iovec);
732 assert(n_iovec_allocated >= n_iovec + SUBMIT_COREDUMP_FIELDS);
733 assert(input_fd >= 0);
734
735 journald_crash = is_journald_crash(context);
736
737 /* Vacuum before we write anything again */
738 (void) coredump_vacuum(-1, arg_keep_free, arg_max_use);
739
740 /* Always stream the coredump to disk, if that's possible */
741 r = save_external_coredump(context, input_fd,
742 &filename, &coredump_node_fd, &coredump_fd, &coredump_size, &truncated);
743 if (r < 0)
744 /* Skip whole core dumping part */
745 goto log;
746
747 /* If we don't want to keep the coredump on disk, remove it now, as later on we will lack the privileges for
748 * it. However, we keep the fd to it, so that we can still process it and log it. */
749 r = maybe_remove_external_coredump(filename, coredump_size);
750 if (r < 0)
751 return r;
752 if (r == 0) {
753 const char *coredump_filename;
754
755 coredump_filename = strjoina("COREDUMP_FILENAME=", filename);
756 iovec[n_iovec++] = IOVEC_MAKE_STRING(coredump_filename);
757 } else if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
758 log_info("The core will not be stored: size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
759 coredump_size, arg_external_size_max);
760
761 /* Vacuum again, but exclude the coredump we just created */
762 (void) coredump_vacuum(coredump_node_fd >= 0 ? coredump_node_fd : coredump_fd, arg_keep_free, arg_max_use);
763
764 /* Now, let's drop privileges to become the user who owns the segfaulted process and allocate the coredump
765 * memory under the user's uid. This also ensures that the credentials journald will see are the ones of the
766 * coredumping user, thus making sure the user gets access to the core dump. Let's also get rid of all
767 * capabilities, if we run as root, we won't need them anymore. */
768 r = change_uid_gid(context);
769 if (r < 0)
770 return log_error_errno(r, "Failed to drop privileges: %m");
771
772#if HAVE_ELFUTILS
773 /* Try to get a strack trace if we can */
774 if (coredump_size <= arg_process_size_max) {
775 _cleanup_free_ char *stacktrace = NULL;
776
777 r = coredump_make_stack_trace(coredump_fd, context[CONTEXT_EXE], &stacktrace);
778 if (r >= 0)
779 core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
780 " (", context[CONTEXT_COMM], ") of user ",
781 context[CONTEXT_UID], " dumped core.",
782 journald_crash ? "\nCoredump diverted to " : "",
783 journald_crash ? filename : "",
784 "\n\n", stacktrace);
785 else if (r == -EINVAL)
786 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
787 else
788 log_warning_errno(r, "Failed to generate stack trace: %m");
789 } else
790 log_debug("Not generating stack trace: core size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
791 coredump_size, arg_process_size_max);
792
793 if (!core_message)
794#endif
795log:
796 core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
797 " (", context[CONTEXT_COMM], ") of user ",
798 context[CONTEXT_UID], " dumped core.",
799 journald_crash ? "\nCoredump diverted to " : NULL,
800 journald_crash ? filename : NULL);
801 if (!core_message)
802 return log_oom();
803
804 if (journald_crash) {
805 /* We cannot log to the journal, so just print the MESSAGE.
806 * The target was set previously to something safe. */
807 log_dispatch(LOG_ERR, 0, core_message);
808 return 0;
809 }
810
811 iovec[n_iovec++] = IOVEC_MAKE_STRING(core_message);
812
813 if (truncated)
814 iovec[n_iovec++] = IOVEC_MAKE_STRING("COREDUMP_TRUNCATED=1");
815
816 /* Optionally store the entire coredump in the journal */
817 if (arg_storage == COREDUMP_STORAGE_JOURNAL) {
818 if (coredump_size <= arg_journal_size_max) {
819 size_t sz = 0;
820
821 /* Store the coredump itself in the journal */
822
823 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
824 if (r >= 0)
825 iovec[n_iovec++] = IOVEC_MAKE(coredump_data, sz);
826 else
827 log_warning_errno(r, "Failed to attach the core to the journal entry: %m");
828 } else
829 log_info("The core will not be stored: size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
830 coredump_size, arg_journal_size_max);
831 }
832
833 assert(n_iovec <= n_iovec_allocated);
834
835 r = sd_journal_sendv(iovec, n_iovec);
836 if (r < 0)
837 return log_error_errno(r, "Failed to log coredump: %m");
838
839 return 0;
840}
841
842static void map_context_fields(const struct iovec *iovec, const char* context[]) {
843
844 static const char * const context_field_names[] = {
845 [CONTEXT_PID] = "COREDUMP_PID=",
846 [CONTEXT_UID] = "COREDUMP_UID=",
847 [CONTEXT_GID] = "COREDUMP_GID=",
848 [CONTEXT_SIGNAL] = "COREDUMP_SIGNAL=",
849 [CONTEXT_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
850 [CONTEXT_RLIMIT] = "COREDUMP_RLIMIT=",
851 [CONTEXT_COMM] = "COREDUMP_COMM=",
852 [CONTEXT_EXE] = "COREDUMP_EXE=",
853 };
854
855 unsigned i;
856
857 assert(iovec);
858 assert(context);
859
860 for (i = 0; i < ELEMENTSOF(context_field_names); i++) {
861 size_t l;
862
863 if (!context_field_names[i])
864 continue;
865
866 l = strlen(context_field_names[i]);
867 if (iovec->iov_len < l)
868 continue;
869
870 if (memcmp(iovec->iov_base, context_field_names[i], l) != 0)
871 continue;
872
873 /* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the
874 * buffer, though not included in the iov_len count. (see below) */
875 context[i] = (char*) iovec->iov_base + l;
876 break;
877 }
878}
879
880static int process_socket(int fd) {
881 _cleanup_close_ int coredump_fd = -1;
882 struct iovec *iovec = NULL;
883 size_t n_iovec = 0, n_allocated = 0, i, k;
884 const char *context[_CONTEXT_MAX] = {};
885 int r;
886
887 assert(fd >= 0);
888
889 log_set_target(LOG_TARGET_AUTO);
890 log_parse_environment();
891 log_open();
892
893 log_debug("Processing coredump received on stdin...");
894
895 for (;;) {
896 union {
897 struct cmsghdr cmsghdr;
898 uint8_t buf[CMSG_SPACE(sizeof(int))];
899 } control = {};
900 struct msghdr mh = {
901 .msg_control = &control,
902 .msg_controllen = sizeof(control),
903 .msg_iovlen = 1,
904 };
905 ssize_t n;
906 ssize_t l;
907
908 if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + SUBMIT_COREDUMP_FIELDS)) {
909 r = log_oom();
910 goto finish;
911 }
912
913 l = next_datagram_size_fd(fd);
914 if (l < 0) {
915 r = log_error_errno(l, "Failed to determine datagram size to read: %m");
916 goto finish;
917 }
918
919 assert(l >= 0);
920
921 iovec[n_iovec].iov_len = l;
922 iovec[n_iovec].iov_base = malloc(l + 1);
923 if (!iovec[n_iovec].iov_base) {
924 r = log_oom();
925 goto finish;
926 }
927
928 mh.msg_iov = iovec + n_iovec;
929
930 n = recvmsg(fd, &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
931 if (n < 0) {
932 free(iovec[n_iovec].iov_base);
933 r = log_error_errno(errno, "Failed to receive datagram: %m");
934 goto finish;
935 }
936
937 if (n == 0) {
938 struct cmsghdr *cmsg, *found = NULL;
939 /* The final zero-length datagram carries the file descriptor and tells us that we're done. */
940
941 free(iovec[n_iovec].iov_base);
942
943 CMSG_FOREACH(cmsg, &mh) {
944 if (cmsg->cmsg_level == SOL_SOCKET &&
945 cmsg->cmsg_type == SCM_RIGHTS &&
946 cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
947 assert(!found);
948 found = cmsg;
949 }
950 }
951
952 if (!found) {
953 log_error("Coredump file descriptor missing.");
954 r = -EBADMSG;
955 goto finish;
956 }
957
958 assert(coredump_fd < 0);
959 coredump_fd = *(int*) CMSG_DATA(found);
960 break;
961 }
962
963 /* Add trailing NUL byte, in case these are strings */
964 ((char*) iovec[n_iovec].iov_base)[n] = 0;
965 iovec[n_iovec].iov_len = (size_t) n;
966
967 cmsg_close_all(&mh);
968 map_context_fields(iovec + n_iovec, context);
969 n_iovec++;
970 }
971
972 if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + SUBMIT_COREDUMP_FIELDS)) {
973 r = log_oom();
974 goto finish;
975 }
976
977 /* Make sure we got all data we really need */
978 assert(context[CONTEXT_PID]);
979 assert(context[CONTEXT_UID]);
980 assert(context[CONTEXT_GID]);
981 assert(context[CONTEXT_SIGNAL]);
982 assert(context[CONTEXT_TIMESTAMP]);
983 assert(context[CONTEXT_RLIMIT]);
984 assert(context[CONTEXT_COMM]);
985 assert(coredump_fd >= 0);
986
987 /* Small quirk: the journal fields contain the timestamp padded with six zeroes, so that the kernel-supplied 1s
988 * granularity timestamps becomes 1µs granularity, i.e. the granularity systemd usually operates in. Since we
989 * are reconstructing the original kernel context, we chop this off again, here. */
990 k = strlen(context[CONTEXT_TIMESTAMP]);
991 if (k > 6)
992 context[CONTEXT_TIMESTAMP] = strndupa(context[CONTEXT_TIMESTAMP], k - 6);
993
994 r = submit_coredump(context, iovec, n_allocated, n_iovec, coredump_fd);
995
996finish:
997 for (i = 0; i < n_iovec; i++)
998 free(iovec[i].iov_base);
999 free(iovec);
1000
1001 return r;
1002}
1003
1004static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd) {
1005
1006 static const union sockaddr_union sa = {
1007 .un.sun_family = AF_UNIX,
1008 .un.sun_path = "/run/systemd/coredump",
1009 };
1010 _cleanup_close_ int fd = -1;
1011 size_t i;
1012 int r;
1013
1014 assert(iovec || n_iovec <= 0);
1015 assert(input_fd >= 0);
1016
1017 fd = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0);
1018 if (fd < 0)
1019 return log_error_errno(errno, "Failed to create coredump socket: %m");
1020
1021 if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
1022 return log_error_errno(errno, "Failed to connect to coredump service: %m");
1023
1024 for (i = 0; i < n_iovec; i++) {
1025 struct msghdr mh = {
1026 .msg_iov = (struct iovec*) iovec + i,
1027 .msg_iovlen = 1,
1028 };
1029 struct iovec copy[2];
1030
1031 for (;;) {
1032 if (sendmsg(fd, &mh, MSG_NOSIGNAL) >= 0)
1033 break;
1034
1035 if (errno == EMSGSIZE && mh.msg_iov[0].iov_len > 0) {
1036 /* This field didn't fit? That's a pity. Given that this is just metadata,
1037 * let's truncate the field at half, and try again. We append three dots, in
1038 * order to show that this is truncated. */
1039
1040 if (mh.msg_iov != copy) {
1041 /* We don't want to modify the caller's iovec, hence let's create our
1042 * own array, consisting of two new iovecs, where the first is a
1043 * (truncated) copy of what we want to send, and the second one
1044 * contains the trailing dots. */
1045 copy[0] = iovec[i];
1046 copy[1] = (struct iovec) {
1047 .iov_base = (char[]) { '.', '.', '.' },
1048 .iov_len = 3,
1049 };
1050
1051 mh.msg_iov = copy;
1052 mh.msg_iovlen = 2;
1053 }
1054
1055 copy[0].iov_len /= 2; /* halve it, and try again */
1056 continue;
1057 }
1058
1059 return log_error_errno(errno, "Failed to send coredump datagram: %m");
1060 }
1061 }
1062
1063 r = send_one_fd(fd, input_fd, 0);
1064 if (r < 0)
1065 return log_error_errno(r, "Failed to send coredump fd: %m");
1066
1067 return 0;
1068}
1069
1070static char* set_iovec_field(struct iovec iovec[27], size_t *n_iovec, const char *field, const char *value) {
1071 char *x;
1072
1073 x = strappend(field, value);
1074 if (x)
1075 iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
1076 return x;
1077}
1078
1079static char* set_iovec_field_free(struct iovec iovec[27], size_t *n_iovec, const char *field, char *value) {
1080 char *x;
1081
1082 x = set_iovec_field(iovec, n_iovec, field, value);
1083 free(value);
1084 return x;
1085}
1086
1087static int gather_pid_metadata(
1088 char* context[_CONTEXT_MAX],
1089 char **comm_fallback,
1090 struct iovec *iovec, size_t *n_iovec) {
1091
1092 /* We need 26 empty slots in iovec!
1093 *
1094 * Note that if we fail on oom later on, we do not roll-back changes to the iovec structure. (It remains valid,
1095 * with the first n_iovec fields initialized.) */
1096
1097 uid_t owner_uid;
1098 pid_t pid;
1099 char *t;
1100 const char *p;
1101 int r, signo;
1102
1103 r = parse_pid(context[CONTEXT_PID], &pid);
1104 if (r < 0)
1105 return log_error_errno(r, "Failed to parse PID \"%s\": %m", context[CONTEXT_PID]);
1106
1107 r = get_process_comm(pid, &context[CONTEXT_COMM]);
1108 if (r < 0) {
1109 log_warning_errno(r, "Failed to get COMM, falling back to the command line: %m");
1110 context[CONTEXT_COMM] = strv_join(comm_fallback, " ");
1111 if (!context[CONTEXT_COMM])
1112 return log_oom();
1113 }
1114
1115 r = get_process_exe(pid, &context[CONTEXT_EXE]);
1116 if (r < 0)
1117 log_warning_errno(r, "Failed to get EXE, ignoring: %m");
1118
1119 if (cg_pid_get_unit(pid, &context[CONTEXT_UNIT]) >= 0) {
1120 if (!is_journald_crash((const char**) context)) {
1121 /* OK, now we know it's not the journal, hence we can make use of it now. */
1122 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1123 log_open();
1124 }
1125
1126 /* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */
1127 if (is_pid1_crash((const char**) context)) {
1128 log_notice("Due to PID 1 having crashed coredump collection will now be turned off.");
1129 disable_coredumps();
1130 }
1131
1132 set_iovec_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]);
1133 }
1134
1135 if (cg_pid_get_user_unit(pid, &t) >= 0)
1136 set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t);
1137
1138 /* The next few are mandatory */
1139 if (!set_iovec_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID]))
1140 return log_oom();
1141
1142 if (!set_iovec_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID]))
1143 return log_oom();
1144
1145 if (!set_iovec_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID]))
1146 return log_oom();
1147
1148 if (!set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]))
1149 return log_oom();
1150
1151 if (!set_iovec_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]))
1152 return log_oom();
1153
1154 if (!set_iovec_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM]))
1155 return log_oom();
1156
1157 if (context[CONTEXT_EXE] &&
1158 !set_iovec_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE]))
1159 return log_oom();
1160
1161 if (sd_pid_get_session(pid, &t) >= 0)
1162 set_iovec_field_free(iovec, n_iovec, "COREDUMP_SESSION=", t);
1163
1164 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
1165 r = asprintf(&t, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
1166 if (r > 0)
1167 iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t);
1168 }
1169
1170 if (sd_pid_get_slice(pid, &t) >= 0)
1171 set_iovec_field_free(iovec, n_iovec, "COREDUMP_SLICE=", t);
1172
1173 if (get_process_cmdline(pid, 0, false, &t) >= 0)
1174 set_iovec_field_free(iovec, n_iovec, "COREDUMP_CMDLINE=", t);
1175
1176 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0)
1177 set_iovec_field_free(iovec, n_iovec, "COREDUMP_CGROUP=", t);
1178
1179 if (compose_open_fds(pid, &t) >= 0)
1180 set_iovec_field_free(iovec, n_iovec, "COREDUMP_OPEN_FDS=", t);
1181
1182 p = procfs_file_alloca(pid, "status");
1183 if (read_full_file(p, &t, NULL) >= 0)
1184 set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_STATUS=", t);
1185
1186 p = procfs_file_alloca(pid, "maps");
1187 if (read_full_file(p, &t, NULL) >= 0)
1188 set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MAPS=", t);
1189
1190 p = procfs_file_alloca(pid, "limits");
1191 if (read_full_file(p, &t, NULL) >= 0)
1192 set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_LIMITS=", t);
1193
1194 p = procfs_file_alloca(pid, "cgroup");
1195 if (read_full_file(p, &t, NULL) >=0)
1196 set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_CGROUP=", t);
1197
1198 p = procfs_file_alloca(pid, "mountinfo");
1199 if (read_full_file(p, &t, NULL) >=0)
1200 set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MOUNTINFO=", t);
1201
1202 if (get_process_cwd(pid, &t) >= 0)
1203 set_iovec_field_free(iovec, n_iovec, "COREDUMP_CWD=", t);
1204
1205 if (get_process_root(pid, &t) >= 0) {
1206 bool proc_self_root_is_slash;
1207
1208 proc_self_root_is_slash = strcmp(t, "/") == 0;
1209
1210 set_iovec_field_free(iovec, n_iovec, "COREDUMP_ROOT=", t);
1211
1212 /* If the process' root is "/", then there is a chance it has
1213 * mounted own root and hence being containerized. */
1214 if (proc_self_root_is_slash && get_process_container_parent_cmdline(pid, &t) > 0)
1215 set_iovec_field_free(iovec, n_iovec, "COREDUMP_CONTAINER_CMDLINE=", t);
1216 }
1217
1218 if (get_process_environ(pid, &t) >= 0)
1219 set_iovec_field_free(iovec, n_iovec, "COREDUMP_ENVIRON=", t);
1220
1221 t = strjoin("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000");
1222 if (t)
1223 iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t);
1224
1225 if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo))
1226 set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo));
1227
1228 return 0; /* we successfully acquired all metadata */
1229}
1230
1231static int process_kernel(int argc, char* argv[]) {
1232
1233 char* context[_CONTEXT_MAX] = {};
1234 struct iovec iovec[28 + SUBMIT_COREDUMP_FIELDS];
1235 size_t i, n_iovec, n_to_free = 0;
1236 int r;
1237
1238 log_debug("Processing coredump received from the kernel...");
1239
1240 if (argc < CONTEXT_COMM + 1) {
1241 log_error("Not enough arguments passed by the kernel (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1);
1242 return -EINVAL;
1243 }
1244
1245 context[CONTEXT_PID] = argv[1 + CONTEXT_PID];
1246 context[CONTEXT_UID] = argv[1 + CONTEXT_UID];
1247 context[CONTEXT_GID] = argv[1 + CONTEXT_GID];
1248 context[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL];
1249 context[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP];
1250 context[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT];
1251
1252 r = gather_pid_metadata(context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free);
1253 if (r < 0)
1254 goto finish;
1255
1256 n_iovec = n_to_free;
1257
1258 iovec[n_iovec++] = IOVEC_MAKE_STRING("MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR);
1259
1260 assert_cc(2 == LOG_CRIT);
1261 iovec[n_iovec++] = IOVEC_MAKE_STRING("PRIORITY=2");
1262
1263 assert(n_iovec <= ELEMENTSOF(iovec));
1264
1265 if (is_journald_crash((const char**) context) || is_pid1_crash((const char**) context))
1266 r = submit_coredump((const char**) context,
1267 iovec, ELEMENTSOF(iovec), n_iovec,
1268 STDIN_FILENO);
1269 else
1270 r = send_iovec(iovec, n_iovec, STDIN_FILENO);
1271
1272 finish:
1273 for (i = 0; i < n_to_free; i++)
1274 free(iovec[i].iov_base);
1275
1276 /* Those fields are allocated by gather_pid_metadata */
1277 free(context[CONTEXT_COMM]);
1278 free(context[CONTEXT_EXE]);
1279 free(context[CONTEXT_UNIT]);
1280
1281 return r;
1282}
1283
1284static int process_backtrace(int argc, char *argv[]) {
1285 char *context[_CONTEXT_MAX] = {};
1286 _cleanup_free_ char *message = NULL;
1287 _cleanup_free_ struct iovec *iovec = NULL;
1288 size_t n_iovec, n_allocated, n_to_free = 0, i;
1289 int r;
1290 JournalImporter importer = {
1291 .fd = STDIN_FILENO,
1292 };
1293
1294 log_debug("Processing backtrace on stdin...");
1295
1296 if (argc < CONTEXT_COMM + 1) {
1297 log_error("Not enough arguments passed (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1);
1298 return -EINVAL;
1299 }
1300
1301 context[CONTEXT_PID] = argv[2 + CONTEXT_PID];
1302 context[CONTEXT_UID] = argv[2 + CONTEXT_UID];
1303 context[CONTEXT_GID] = argv[2 + CONTEXT_GID];
1304 context[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL];
1305 context[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP];
1306 context[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT];
1307
1308 n_allocated = 33 + COREDUMP_STORAGE_EXTERNAL;
1309 /* 25 metadata, 2 static, +unknown input, 4 storage, rounded up */
1310 iovec = new(struct iovec, n_allocated);
1311 if (!iovec)
1312 return log_oom();
1313
1314 r = gather_pid_metadata(context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free);
1315 if (r < 0)
1316 goto finish;
1317 if (r > 0) {
1318 /* This was a special crash, and has already been processed. */
1319 r = 0;
1320 goto finish;
1321 }
1322 n_iovec = n_to_free;
1323
1324 for (;;) {
1325 r = journal_importer_process_data(&importer);
1326 if (r < 0) {
1327 log_error_errno(r, "Failed to parse journal entry on stdin: %m");
1328 goto finish;
1329 }
1330 if (r == 1 || /* complete entry */
1331 journal_importer_eof(&importer)) /* end of data */
1332 break;
1333 }
1334
1335 if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + importer.iovw.count + 2))
1336 return log_oom();
1337
1338 if (journal_importer_eof(&importer)) {
1339 log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter");
1340
1341 message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
1342 " (", context[CONTEXT_COMM], ")"
1343 " of user ", context[CONTEXT_UID],
1344 " failed with ", context[CONTEXT_SIGNAL]);
1345 if (!message) {
1346 r = log_oom();
1347 goto finish;
1348 }
1349 iovec[n_iovec++] = IOVEC_MAKE_STRING(message);
1350 } else {
1351 for (i = 0; i < importer.iovw.count; i++)
1352 iovec[n_iovec++] = importer.iovw.iovec[i];
1353 }
1354
1355 iovec[n_iovec++] = IOVEC_MAKE_STRING("MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR);
1356 assert_cc(2 == LOG_CRIT);
1357 iovec[n_iovec++] = IOVEC_MAKE_STRING("PRIORITY=2");
1358
1359 assert(n_iovec <= n_allocated);
1360
1361 r = sd_journal_sendv(iovec, n_iovec);
1362 if (r < 0)
1363 log_error_errno(r, "Failed to log backtrace: %m");
1364
1365 finish:
1366 for (i = 0; i < n_to_free; i++)
1367 free(iovec[i].iov_base);
1368
1369 /* Those fields are allocated by gather_pid_metadata */
1370 free(context[CONTEXT_COMM]);
1371 free(context[CONTEXT_EXE]);
1372 free(context[CONTEXT_UNIT]);
1373
1374 return r;
1375}
1376
1377int main(int argc, char *argv[]) {
1378 int r;
1379
1380 /* First, log to a safe place, since we don't know what crashed and it might
1381 * be journald which we'd rather not log to then. */
1382
1383 log_set_target(LOG_TARGET_KMSG);
1384 log_open();
1385
1386 /* Make sure we never enter a loop */
1387 (void) prctl(PR_SET_DUMPABLE, 0);
1388
1389 /* Ignore all parse errors */
1390 (void) parse_config();
1391
1392 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
1393 log_debug("Selected compression %s.", yes_no(arg_compress));
1394
1395 r = sd_listen_fds(false);
1396 if (r < 0) {
1397 log_error_errno(r, "Failed to determine number of file descriptor: %m");
1398 goto finish;
1399 }
1400
1401 /* If we got an fd passed, we are running in coredumpd mode. Otherwise we
1402 * are invoked from the kernel as coredump handler. */
1403 if (r == 0) {
1404 if (streq_ptr(argv[1], "--backtrace"))
1405 r = process_backtrace(argc, argv);
1406 else
1407 r = process_kernel(argc, argv);
1408 } else if (r == 1)
1409 r = process_socket(SD_LISTEN_FDS_START);
1410 else {
1411 log_error("Received unexpected number of file descriptors.");
1412 r = -EINVAL;
1413 }
1414
1415finish:
1416 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1417}