chiark / gitweb /
journald: there's no point in turning on SO_TIMESTAMP for audit sockets, audit doesn...
[elogind.git] / src / journal / coredump.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2012 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <sys/prctl.h>
26 #include <sys/types.h>
27 #include <sys/xattr.h>
28
29 #ifdef HAVE_ELFUTILS
30 #  include <dwarf.h>
31 #  include <elfutils/libdwfl.h>
32 #endif
33
34 #include "systemd/sd-journal.h"
35 #include "systemd/sd-login.h"
36
37 #include "log.h"
38 #include "util.h"
39 #include "strv.h"
40 #include "macro.h"
41 #include "mkdir.h"
42 #include "special.h"
43 #include "cgroup-util.h"
44 #include "journald-native.h"
45 #include "conf-parser.h"
46 #include "copy.h"
47 #include "stacktrace.h"
48 #include "path-util.h"
49 #include "compress.h"
50 #include "coredump-vacuum.h"
51
52 #ifdef HAVE_ACL
53 #  include <sys/acl.h>
54 #  include "acl-util.h"
55 #endif
56
57 /* The maximum size up to which we process coredumps */
58 #define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
59
60 /* The maximum size up to which we leave the coredump around on
61  * disk */
62 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
63
64 /* The maximum size up to which we store the coredump in the
65  * journal */
66 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
67
68 /* Make sure to not make this larger than the maximum journal entry
69  * size. See DATA_SIZE_MAX in journald-native.c. */
70 assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
71
72 enum {
73         INFO_PID,
74         INFO_UID,
75         INFO_GID,
76         INFO_SIGNAL,
77         INFO_TIMESTAMP,
78         INFO_COMM,
79         INFO_EXE,
80         _INFO_LEN
81 };
82
83 typedef enum CoredumpStorage {
84         COREDUMP_STORAGE_NONE,
85         COREDUMP_STORAGE_EXTERNAL,
86         COREDUMP_STORAGE_JOURNAL,
87         COREDUMP_STORAGE_BOTH,
88         _COREDUMP_STORAGE_MAX,
89         _COREDUMP_STORAGE_INVALID = -1
90 } CoredumpStorage;
91
92 static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
93         [COREDUMP_STORAGE_NONE] = "none",
94         [COREDUMP_STORAGE_EXTERNAL] = "external",
95         [COREDUMP_STORAGE_JOURNAL] = "journal",
96         [COREDUMP_STORAGE_BOTH] = "both",
97 };
98
99 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
100 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
101
102 static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
103 static bool arg_compress = true;
104 static off_t arg_process_size_max = PROCESS_SIZE_MAX;
105 static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
106 static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
107 static off_t arg_keep_free = (off_t) -1;
108 static off_t arg_max_use = (off_t) -1;
109
110 static int parse_config(void) {
111         static const ConfigTableItem items[] = {
112                 { "Coredump", "Storage",          config_parse_coredump_storage,  0, &arg_storage           },
113                 { "Coredump", "Compress",         config_parse_bool,              0, &arg_compress          },
114                 { "Coredump", "ProcessSizeMax",   config_parse_iec_off,           0, &arg_process_size_max  },
115                 { "Coredump", "ExternalSizeMax",  config_parse_iec_off,           0, &arg_external_size_max },
116                 { "Coredump", "JournalSizeMax",   config_parse_iec_size,          0, &arg_journal_size_max  },
117                 { "Coredump", "KeepFree",         config_parse_iec_off,           0, &arg_keep_free         },
118                 { "Coredump", "MaxUse",           config_parse_iec_off,           0, &arg_max_use           },
119                 {}
120         };
121
122         return config_parse(NULL, "/etc/systemd/coredump.conf", NULL,
123                             "Coredump\0",
124                             config_item_table_lookup, items,
125                             false, false, true, NULL);
126 }
127
128 static int fix_acl(int fd, uid_t uid) {
129
130 #ifdef HAVE_ACL
131         _cleanup_(acl_freep) acl_t acl = NULL;
132         acl_entry_t entry;
133         acl_permset_t permset;
134
135         assert(fd >= 0);
136
137         if (uid <= SYSTEM_UID_MAX)
138                 return 0;
139
140         /* Make sure normal users can read (but not write or delete)
141          * their own coredumps */
142
143         acl = acl_get_fd(fd);
144         if (!acl) {
145                 log_error("Failed to get ACL: %m");
146                 return -errno;
147         }
148
149         if (acl_create_entry(&acl, &entry) < 0 ||
150             acl_set_tag_type(entry, ACL_USER) < 0 ||
151             acl_set_qualifier(entry, &uid) < 0) {
152                 log_error("Failed to patch ACL: %m");
153                 return -errno;
154         }
155
156         if (acl_get_permset(entry, &permset) < 0 ||
157             acl_add_perm(permset, ACL_READ) < 0 ||
158             calc_acl_mask_if_needed(&acl) < 0) {
159                 log_warning("Failed to patch ACL: %m");
160                 return -errno;
161         }
162
163         if (acl_set_fd(fd, acl) < 0) {
164                 log_error("Failed to apply ACL: %m");
165                 return -errno;
166         }
167 #endif
168
169         return 0;
170 }
171
172 static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
173
174         static const char * const xattrs[_INFO_LEN] = {
175                 [INFO_PID] = "user.coredump.pid",
176                 [INFO_UID] = "user.coredump.uid",
177                 [INFO_GID] = "user.coredump.gid",
178                 [INFO_SIGNAL] = "user.coredump.signal",
179                 [INFO_TIMESTAMP] = "user.coredump.timestamp",
180                 [INFO_COMM] = "user.coredump.comm",
181                 [INFO_EXE] = "user.coredump.exe",
182         };
183
184         int r = 0;
185         unsigned i;
186
187         assert(fd >= 0);
188
189         /* Attach some metadata to coredumps via extended
190          * attributes. Just because we can. */
191
192         for (i = 0; i < _INFO_LEN; i++) {
193                 int k;
194
195                 if (isempty(info[i]) || !xattrs[i])
196                         continue;
197
198                 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
199                 if (k < 0 && r == 0)
200                         r = -errno;
201         }
202
203         return r;
204 }
205
206 #define filename_escape(s) xescape((s), "./ ")
207
208 static int fix_permissions(
209                 int fd,
210                 const char *filename,
211                 const char *target,
212                 const char *info[_INFO_LEN],
213                 uid_t uid) {
214
215         assert(fd >= 0);
216         assert(filename);
217         assert(target);
218         assert(info);
219
220         /* Ignore errors on these */
221         fchmod(fd, 0640);
222         fix_acl(fd, uid);
223         fix_xattr(fd, info);
224
225         if (fsync(fd) < 0) {
226                 log_error("Failed to sync coredump %s: %m", filename);
227                 return -errno;
228         }
229
230         if (rename(filename, target) < 0) {
231                 log_error("Failed to rename coredump %s -> %s: %m", filename, target);
232                 return -errno;
233         }
234
235         return 0;
236 }
237
238 static int maybe_remove_external_coredump(const char *filename, off_t size) {
239
240         /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
241
242         if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
243             size <= arg_external_size_max)
244                 return 0;
245
246         if (!filename)
247                 return 1;
248
249         if (unlink(filename) < 0 && errno != ENOENT) {
250                 log_error("Failed to unlink %s: %m", filename);
251                 return -errno;
252         }
253
254         return 1;
255 }
256
257 static int make_filename(const char *info[_INFO_LEN], char **ret) {
258         _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
259         sd_id128_t boot;
260         int r;
261
262         assert(info);
263
264         c = filename_escape(info[INFO_COMM]);
265         if (!c)
266                 return -ENOMEM;
267
268         u = filename_escape(info[INFO_UID]);
269         if (!u)
270                 return -ENOMEM;
271
272         r = sd_id128_get_boot(&boot);
273         if (r < 0)
274                 return r;
275
276         p = filename_escape(info[INFO_PID]);
277         if (!p)
278                 return -ENOMEM;
279
280         t = filename_escape(info[INFO_TIMESTAMP]);
281         if (!t)
282                 return -ENOMEM;
283
284         if (asprintf(ret,
285                      "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
286                      c,
287                      u,
288                      SD_ID128_FORMAT_VAL(boot),
289                      p,
290                      t) < 0)
291                 return -ENOMEM;
292
293         return 0;
294 }
295
296 static int save_external_coredump(
297                 const char *info[_INFO_LEN],
298                 uid_t uid,
299                 char **ret_filename,
300                 int *ret_fd,
301                 off_t *ret_size) {
302
303         _cleanup_free_ char *fn = NULL, *tmp = NULL;
304         _cleanup_close_ int fd = -1;
305         struct stat st;
306         int r;
307
308         assert(info);
309         assert(ret_filename);
310         assert(ret_fd);
311         assert(ret_size);
312
313         r = make_filename(info, &fn);
314         if (r < 0) {
315                 log_error("Failed to determine coredump file name: %s", strerror(-r));
316                 return r;
317         }
318
319         tmp = tempfn_random(fn);
320         if (!tmp)
321                 return log_oom();
322
323         mkdir_p_label("/var/lib/systemd/coredump", 0755);
324
325         fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
326         if (fd < 0) {
327                 log_error("Failed to create coredump file %s: %m", tmp);
328                 return -errno;
329         }
330
331         r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
332         if (r == -E2BIG) {
333                 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
334                 goto fail;
335         } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
336                 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
337                 goto fail;
338         } else if (r < 0) {
339                 log_error("Failed to dump coredump to file: %s", strerror(-r));
340                 goto fail;
341         }
342
343         if (fstat(fd, &st) < 0) {
344                 log_error("Failed to fstat coredump %s: %m", tmp);
345                 goto fail;
346         }
347
348         if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
349                 log_error("Failed to seek on %s: %m", tmp);
350                 goto fail;
351         }
352
353 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
354         /* If we will remove the coredump anyway, do not compress. */
355         if (maybe_remove_external_coredump(NULL, st.st_size) == 0
356             && arg_compress) {
357
358                 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
359                 _cleanup_close_ int fd_compressed = -1;
360
361                 fn_compressed = strappend(fn, COMPRESSED_EXT);
362                 if (!fn_compressed) {
363                         log_oom();
364                         goto uncompressed;
365                 }
366
367                 tmp_compressed = tempfn_random(fn_compressed);
368                 if (!tmp_compressed) {
369                         log_oom();
370                         goto uncompressed;
371                 }
372
373                 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
374                 if (fd_compressed < 0) {
375                         log_error("Failed to create file %s: %m", tmp_compressed);
376                         goto uncompressed;
377                 }
378
379                 r = compress_stream(fd, fd_compressed, -1);
380                 if (r < 0) {
381                         log_error("Failed to compress %s: %s", tmp_compressed, strerror(-r));
382                         goto fail_compressed;
383                 }
384
385                 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
386                 if (r < 0)
387                         goto fail_compressed;
388
389                 /* OK, this worked, we can get rid of the uncompressed version now */
390                 unlink_noerrno(tmp);
391
392                 *ret_filename = fn_compressed;    /* compressed */
393                 *ret_fd = fd;                     /* uncompressed */
394                 *ret_size = st.st_size;           /* uncompressed */
395
396                 fn_compressed = NULL;
397                 fd = -1;
398
399                 return 0;
400
401         fail_compressed:
402                 unlink_noerrno(tmp_compressed);
403         }
404
405 uncompressed:
406 #endif
407         r = fix_permissions(fd, tmp, fn, info, uid);
408         if (r < 0)
409                 goto fail;
410
411         *ret_filename = fn;
412         *ret_fd = fd;
413         *ret_size = st.st_size;
414
415         fn = NULL;
416         fd = -1;
417
418         return 0;
419
420 fail:
421         unlink_noerrno(tmp);
422         return r;
423 }
424
425 static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
426         _cleanup_free_ char *field = NULL;
427         ssize_t n;
428
429         assert(fd >= 0);
430         assert(ret);
431         assert(ret_size);
432
433         if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
434                 log_warning("Failed to seek: %m");
435                 return -errno;
436         }
437
438         field = malloc(9 + size);
439         if (!field) {
440                 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
441                 return -ENOMEM;
442         }
443
444         memcpy(field, "COREDUMP=", 9);
445
446         n = read(fd, field + 9, size);
447         if (n < 0) {
448                 log_error("Failed to read core data: %s", strerror(-n));
449                 return (int) n;
450         }
451         if ((size_t) n < size) {
452                 log_error("Core data too short.");
453                 return -EIO;
454         }
455
456         *ret = field;
457         *ret_size = size + 9;
458
459         field = NULL;
460
461         return 0;
462 }
463
464 int main(int argc, char* argv[]) {
465
466         _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
467                 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
468                 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
469                 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
470                 *exe = NULL, *comm = NULL, *filename = NULL;
471         const char *info[_INFO_LEN];
472
473         _cleanup_close_ int coredump_fd = -1;
474
475         struct iovec iovec[18];
476         off_t coredump_size;
477         int r, j = 0;
478         uid_t uid, owner_uid;
479         gid_t gid;
480         pid_t pid;
481         char *t;
482
483         /* Make sure we never enter a loop */
484         prctl(PR_SET_DUMPABLE, 0);
485
486         /* First, log to a safe place, since we don't know what
487          * crashed and it might be journald which we'd rather not log
488          * to then. */
489         log_set_target(LOG_TARGET_KMSG);
490         log_open();
491
492         if (argc < INFO_COMM + 1) {
493                 log_error("Not enough arguments passed from kernel (%d, expected %d).",
494                           argc - 1, INFO_COMM + 1 - 1);
495                 r = -EINVAL;
496                 goto finish;
497         }
498
499         /* Ignore all parse errors */
500         parse_config();
501
502         log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
503         log_debug("Selected compression %s.", yes_no(arg_compress));
504
505         r = parse_uid(argv[INFO_UID + 1], &uid);
506         if (r < 0) {
507                 log_error("Failed to parse UID.");
508                 goto finish;
509         }
510
511         r = parse_pid(argv[INFO_PID + 1], &pid);
512         if (r < 0) {
513                 log_error("Failed to parse PID.");
514                 goto finish;
515         }
516
517         r = parse_gid(argv[INFO_GID + 1], &gid);
518         if (r < 0) {
519                 log_error("Failed to parse GID.");
520                 goto finish;
521         }
522
523         if (get_process_comm(pid, &comm) < 0) {
524                 log_warning("Failed to get COMM, falling back to the commandline.");
525                 comm = strv_join(argv + INFO_COMM + 1, " ");
526         }
527
528         if (get_process_exe(pid, &exe) < 0)
529                 log_warning("Failed to get EXE.");
530
531         info[INFO_PID] = argv[INFO_PID + 1];
532         info[INFO_UID] = argv[INFO_UID + 1];
533         info[INFO_GID] = argv[INFO_GID + 1];
534         info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
535         info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
536         info[INFO_COMM] = comm;
537         info[INFO_EXE] = exe;
538
539         if (cg_pid_get_unit(pid, &t) >= 0) {
540
541                 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
542
543                         /* If we are journald, we cut things short,
544                          * don't write to the journal, but still
545                          * create a coredump. */
546
547                         if (arg_storage != COREDUMP_STORAGE_NONE)
548                                 arg_storage = COREDUMP_STORAGE_EXTERNAL;
549
550                         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
551                         if (r < 0)
552                                 goto finish;
553
554                         r = maybe_remove_external_coredump(filename, coredump_size);
555                         if (r < 0)
556                                 goto finish;
557
558                         log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
559                         goto finish;
560                 }
561
562                 core_unit = strappend("COREDUMP_UNIT=", t);
563         } else if (cg_pid_get_user_unit(pid, &t) >= 0)
564                 core_unit = strappend("COREDUMP_USER_UNIT=", t);
565
566         if (core_unit)
567                 IOVEC_SET_STRING(iovec[j++], core_unit);
568
569         /* OK, now we know it's not the journal, hence we can make use
570          * of it now. */
571         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
572         log_open();
573
574         core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
575         if (core_pid)
576                 IOVEC_SET_STRING(iovec[j++], core_pid);
577
578         core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
579         if (core_uid)
580                 IOVEC_SET_STRING(iovec[j++], core_uid);
581
582         core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
583         if (core_gid)
584                 IOVEC_SET_STRING(iovec[j++], core_gid);
585
586         core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
587         if (core_signal)
588                 IOVEC_SET_STRING(iovec[j++], core_signal);
589
590         if (sd_pid_get_session(pid, &t) >= 0) {
591                 core_session = strappend("COREDUMP_SESSION=", t);
592                 free(t);
593
594                 if (core_session)
595                         IOVEC_SET_STRING(iovec[j++], core_session);
596         }
597
598         if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
599                 r = asprintf(&core_owner_uid,
600                              "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
601                 if (r > 0)
602                         IOVEC_SET_STRING(iovec[j++], core_owner_uid);
603         }
604
605         if (sd_pid_get_slice(pid, &t) >= 0) {
606                 core_slice = strappend("COREDUMP_SLICE=", t);
607                 free(t);
608
609                 if (core_slice)
610                         IOVEC_SET_STRING(iovec[j++], core_slice);
611         }
612
613         if (comm) {
614                 core_comm = strappend("COREDUMP_COMM=", comm);
615                 if (core_comm)
616                         IOVEC_SET_STRING(iovec[j++], core_comm);
617         }
618
619         if (exe) {
620                 core_exe = strappend("COREDUMP_EXE=", exe);
621                 if (core_exe)
622                         IOVEC_SET_STRING(iovec[j++], core_exe);
623         }
624
625         if (get_process_cmdline(pid, 0, false, &t) >= 0) {
626                 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
627                 free(t);
628
629                 if (core_cmdline)
630                         IOVEC_SET_STRING(iovec[j++], core_cmdline);
631         }
632
633         if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
634                 core_cgroup = strappend("COREDUMP_CGROUP=", t);
635                 free(t);
636
637                 if (core_cgroup)
638                         IOVEC_SET_STRING(iovec[j++], core_cgroup);
639         }
640
641         core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
642         if (core_timestamp)
643                 IOVEC_SET_STRING(iovec[j++], core_timestamp);
644
645         IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
646         IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
647
648         /* Vacuum before we write anything again */
649         coredump_vacuum(-1, arg_keep_free, arg_max_use);
650
651         /* Always stream the coredump to disk, if that's possible */
652         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
653         if (r < 0)
654                 /* skip whole core dumping part */
655                 goto log;
656
657         /* If we don't want to keep the coredump on disk, remove it
658          * now, as later on we will lack the privileges for
659          * it. However, we keep the fd to it, so that we can still
660          * process it and log it. */
661         r = maybe_remove_external_coredump(filename, coredump_size);
662         if (r < 0)
663                 goto finish;
664         if (r == 0) {
665                 const char *coredump_filename;
666
667                 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
668                 IOVEC_SET_STRING(iovec[j++], coredump_filename);
669         }
670
671         /* Vacuum again, but exclude the coredump we just created */
672         coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
673
674         /* Now, let's drop privileges to become the user who owns the
675          * segfaulted process and allocate the coredump memory under
676          * the user's uid. This also ensures that the credentials
677          * journald will see are the ones of the coredumping user,
678          * thus making sure the user gets access to the core dump. */
679         if (setresgid(gid, gid, gid) < 0 ||
680             setresuid(uid, uid, uid) < 0) {
681                 log_error("Failed to drop privileges: %m");
682                 r = -errno;
683                 goto finish;
684         }
685
686 #ifdef HAVE_ELFUTILS
687         /* Try to get a strack trace if we can */
688         if (coredump_size <= arg_process_size_max) {
689                 _cleanup_free_ char *stacktrace = NULL;
690
691                 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
692                 if (r >= 0)
693                         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
694                 else if (r == -EINVAL)
695                         log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
696                 else
697                         log_warning("Failed to generate stack trace: %s", strerror(-r));
698         }
699
700         if (!core_message)
701 #endif
702 log:
703         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
704         if (core_message)
705                 IOVEC_SET_STRING(iovec[j++], core_message);
706
707         /* Optionally store the entire coredump in the journal */
708         if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
709             coredump_size <= (off_t) arg_journal_size_max) {
710                 size_t sz;
711
712                 /* Store the coredump itself in the journal */
713
714                 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
715                 if (r >= 0) {
716                         iovec[j].iov_base = coredump_data;
717                         iovec[j].iov_len = sz;
718                         j++;
719                 }
720         }
721
722         r = sd_journal_sendv(iovec, j);
723         if (r < 0)
724                 log_error("Failed to log coredump: %s", strerror(-r));
725
726 finish:
727         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
728 }