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