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