chiark / gitweb /
treewide: use log_*_errno whenever %m is in the format string
[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 "fileio.h"
40 #include "strv.h"
41 #include "macro.h"
42 #include "mkdir.h"
43 #include "special.h"
44 #include "cgroup-util.h"
45 #include "journald-native.h"
46 #include "conf-parser.h"
47 #include "copy.h"
48 #include "stacktrace.h"
49 #include "path-util.h"
50 #include "compress.h"
51 #include "coredump-vacuum.h"
52
53 #ifdef HAVE_ACL
54 #  include <sys/acl.h>
55 #  include "acl-util.h"
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 DATA_SIZE_MAX in journald-native.c. */
71 assert_cc(JOURNAL_SIZE_MAX <= DATA_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, CoredumpStorage, "Failed to parse storage setting");
102
103 static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
104 static bool arg_compress = true;
105 static off_t arg_process_size_max = PROCESS_SIZE_MAX;
106 static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
107 static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
108 static off_t arg_keep_free = (off_t) -1;
109 static off_t arg_max_use = (off_t) -1;
110
111 static int parse_config(void) {
112         static const ConfigTableItem items[] = {
113                 { "Coredump", "Storage",          config_parse_coredump_storage,  0, &arg_storage           },
114                 { "Coredump", "Compress",         config_parse_bool,              0, &arg_compress          },
115                 { "Coredump", "ProcessSizeMax",   config_parse_iec_off,           0, &arg_process_size_max  },
116                 { "Coredump", "ExternalSizeMax",  config_parse_iec_off,           0, &arg_external_size_max },
117                 { "Coredump", "JournalSizeMax",   config_parse_iec_size,          0, &arg_journal_size_max  },
118                 { "Coredump", "KeepFree",         config_parse_iec_off,           0, &arg_keep_free         },
119                 { "Coredump", "MaxUse",           config_parse_iec_off,           0, &arg_max_use           },
120                 {}
121         };
122
123         return config_parse(NULL, "/etc/systemd/coredump.conf", NULL,
124                             "Coredump\0",
125                             config_item_table_lookup, items,
126                             false, false, true, NULL);
127 }
128
129 static int fix_acl(int fd, uid_t uid) {
130
131 #ifdef HAVE_ACL
132         _cleanup_(acl_freep) acl_t acl = NULL;
133         acl_entry_t entry;
134         acl_permset_t permset;
135
136         assert(fd >= 0);
137
138         if (uid <= SYSTEM_UID_MAX)
139                 return 0;
140
141         /* Make sure normal users can read (but not write or delete)
142          * their own coredumps */
143
144         acl = acl_get_fd(fd);
145         if (!acl) {
146                 log_error_errno(errno, "Failed to get ACL: %m");
147                 return -errno;
148         }
149
150         if (acl_create_entry(&acl, &entry) < 0 ||
151             acl_set_tag_type(entry, ACL_USER) < 0 ||
152             acl_set_qualifier(entry, &uid) < 0) {
153                 log_error_errno(errno, "Failed to patch ACL: %m");
154                 return -errno;
155         }
156
157         if (acl_get_permset(entry, &permset) < 0 ||
158             acl_add_perm(permset, ACL_READ) < 0 ||
159             calc_acl_mask_if_needed(&acl) < 0) {
160                 log_warning_errno(errno, "Failed to patch ACL: %m");
161                 return -errno;
162         }
163
164         if (acl_set_fd(fd, acl) < 0) {
165                 log_error_errno(errno, "Failed to apply ACL: %m");
166                 return -errno;
167         }
168 #endif
169
170         return 0;
171 }
172
173 static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
174
175         static const char * const xattrs[_INFO_LEN] = {
176                 [INFO_PID] = "user.coredump.pid",
177                 [INFO_UID] = "user.coredump.uid",
178                 [INFO_GID] = "user.coredump.gid",
179                 [INFO_SIGNAL] = "user.coredump.signal",
180                 [INFO_TIMESTAMP] = "user.coredump.timestamp",
181                 [INFO_COMM] = "user.coredump.comm",
182                 [INFO_EXE] = "user.coredump.exe",
183         };
184
185         int r = 0;
186         unsigned i;
187
188         assert(fd >= 0);
189
190         /* Attach some metadata to coredumps via extended
191          * attributes. Just because we can. */
192
193         for (i = 0; i < _INFO_LEN; i++) {
194                 int k;
195
196                 if (isempty(info[i]) || !xattrs[i])
197                         continue;
198
199                 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
200                 if (k < 0 && r == 0)
201                         r = -errno;
202         }
203
204         return r;
205 }
206
207 #define filename_escape(s) xescape((s), "./ ")
208
209 static int fix_permissions(
210                 int fd,
211                 const char *filename,
212                 const char *target,
213                 const char *info[_INFO_LEN],
214                 uid_t uid) {
215
216         assert(fd >= 0);
217         assert(filename);
218         assert(target);
219         assert(info);
220
221         /* Ignore errors on these */
222         fchmod(fd, 0640);
223         fix_acl(fd, uid);
224         fix_xattr(fd, info);
225
226         if (fsync(fd) < 0) {
227                 log_error_errno(errno, "Failed to sync coredump %s: %m", filename);
228                 return -errno;
229         }
230
231         if (rename(filename, target) < 0) {
232                 log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
233                 return -errno;
234         }
235
236         return 0;
237 }
238
239 static int maybe_remove_external_coredump(const char *filename, off_t size) {
240
241         /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
242
243         if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
244             size <= arg_external_size_max)
245                 return 0;
246
247         if (!filename)
248                 return 1;
249
250         if (unlink(filename) < 0 && errno != ENOENT) {
251                 log_error_errno(errno, "Failed to unlink %s: %m", filename);
252                 return -errno;
253         }
254
255         return 1;
256 }
257
258 static int make_filename(const char *info[_INFO_LEN], char **ret) {
259         _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
260         sd_id128_t boot;
261         int r;
262
263         assert(info);
264
265         c = filename_escape(info[INFO_COMM]);
266         if (!c)
267                 return -ENOMEM;
268
269         u = filename_escape(info[INFO_UID]);
270         if (!u)
271                 return -ENOMEM;
272
273         r = sd_id128_get_boot(&boot);
274         if (r < 0)
275                 return r;
276
277         p = filename_escape(info[INFO_PID]);
278         if (!p)
279                 return -ENOMEM;
280
281         t = filename_escape(info[INFO_TIMESTAMP]);
282         if (!t)
283                 return -ENOMEM;
284
285         if (asprintf(ret,
286                      "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
287                      c,
288                      u,
289                      SD_ID128_FORMAT_VAL(boot),
290                      p,
291                      t) < 0)
292                 return -ENOMEM;
293
294         return 0;
295 }
296
297 static int save_external_coredump(
298                 const char *info[_INFO_LEN],
299                 uid_t uid,
300                 char **ret_filename,
301                 int *ret_fd,
302                 off_t *ret_size) {
303
304         _cleanup_free_ char *fn = NULL, *tmp = NULL;
305         _cleanup_close_ int fd = -1;
306         struct stat st;
307         int r;
308
309         assert(info);
310         assert(ret_filename);
311         assert(ret_fd);
312         assert(ret_size);
313
314         r = make_filename(info, &fn);
315         if (r < 0)
316                 return log_error_errno(r, "Failed to determine coredump file name: %m");
317
318         tmp = tempfn_random(fn);
319         if (!tmp)
320                 return log_oom();
321
322         mkdir_p_label("/var/lib/systemd/coredump", 0755);
323
324         fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
325         if (fd < 0) {
326                 log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
327                 return -errno;
328         }
329
330         r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
331         if (r == -EFBIG) {
332                 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
333                 goto fail;
334         } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
335                 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
336                 goto fail;
337         } else if (r < 0) {
338                 log_error_errno(r, "Failed to dump coredump to file: %m");
339                 goto fail;
340         }
341
342         if (fstat(fd, &st) < 0) {
343                 log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
344                 goto fail;
345         }
346
347         if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
348                 log_error_errno(errno, "Failed to seek on %s: %m", tmp);
349                 goto fail;
350         }
351
352 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
353         /* If we will remove the coredump anyway, do not compress. */
354         if (maybe_remove_external_coredump(NULL, st.st_size) == 0
355             && arg_compress) {
356
357                 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
358                 _cleanup_close_ int fd_compressed = -1;
359
360                 fn_compressed = strappend(fn, COMPRESSED_EXT);
361                 if (!fn_compressed) {
362                         log_oom();
363                         goto uncompressed;
364                 }
365
366                 tmp_compressed = tempfn_random(fn_compressed);
367                 if (!tmp_compressed) {
368                         log_oom();
369                         goto uncompressed;
370                 }
371
372                 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
373                 if (fd_compressed < 0) {
374                         log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
375                         goto uncompressed;
376                 }
377
378                 r = compress_stream(fd, fd_compressed, -1);
379                 if (r < 0) {
380                         log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
381                         goto fail_compressed;
382                 }
383
384                 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
385                 if (r < 0)
386                         goto fail_compressed;
387
388                 /* OK, this worked, we can get rid of the uncompressed version now */
389                 unlink_noerrno(tmp);
390
391                 *ret_filename = fn_compressed;    /* compressed */
392                 *ret_fd = fd;                     /* uncompressed */
393                 *ret_size = st.st_size;           /* uncompressed */
394
395                 fn_compressed = NULL;
396                 fd = -1;
397
398                 return 0;
399
400         fail_compressed:
401                 unlink_noerrno(tmp_compressed);
402         }
403
404 uncompressed:
405 #endif
406         r = fix_permissions(fd, tmp, fn, info, uid);
407         if (r < 0)
408                 goto fail;
409
410         *ret_filename = fn;
411         *ret_fd = fd;
412         *ret_size = st.st_size;
413
414         fn = NULL;
415         fd = -1;
416
417         return 0;
418
419 fail:
420         unlink_noerrno(tmp);
421         return r;
422 }
423
424 static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
425         _cleanup_free_ char *field = NULL;
426         ssize_t n;
427
428         assert(fd >= 0);
429         assert(ret);
430         assert(ret_size);
431
432         if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
433                 log_warning_errno(errno, "Failed to seek: %m");
434                 return -errno;
435         }
436
437         field = malloc(9 + size);
438         if (!field) {
439                 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
440                 return -ENOMEM;
441         }
442
443         memcpy(field, "COREDUMP=", 9);
444
445         n = read(fd, field + 9, size);
446         if (n < 0)
447                 return log_error_errno((int) n, "Failed to read core data: %m");
448         if ((size_t) n < size) {
449                 log_error("Core data too short.");
450                 return -EIO;
451         }
452
453         *ret = field;
454         *ret_size = size + 9;
455
456         field = NULL;
457
458         return 0;
459 }
460
461 /* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
462  * 0:/dev/pts/23
463  * pos:    0
464  * flags:  0100002
465  *
466  * 1:/dev/pts/23
467  * pos:    0
468  * flags:  0100002
469  *
470  * 2:/dev/pts/23
471  * pos:    0
472  * flags:  0100002
473  * EOF
474  */
475 static int compose_open_fds(pid_t pid, char **open_fds) {
476         _cleanup_fclose_ FILE *stream = NULL;
477         size_t ignored_size;
478         const char *fddelim = "", *path;
479         struct dirent *dent = NULL;
480         _cleanup_closedir_ DIR *proc_fd_dir = NULL;
481         _cleanup_close_ int proc_fdinfo_fd = -1;
482         int r = 0;
483
484         assert(pid >= 0);
485         assert(open_fds != NULL);
486
487         path = procfs_file_alloca(pid, "fd");
488         proc_fd_dir = opendir(path);
489         if (!proc_fd_dir)
490                 return -errno;
491
492         proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo",
493                                 O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
494         if (proc_fdinfo_fd < 0)
495                 return -errno;
496
497         stream = open_memstream(open_fds, &ignored_size);
498         if (!stream)
499                 return -ENOMEM;
500
501         for (dent = readdir(proc_fd_dir); dent != NULL; dent = readdir(proc_fd_dir)) {
502                 _cleanup_free_ char *fdname = NULL;
503                 int fd;
504                 _cleanup_fclose_ FILE *fdinfo = NULL;
505                 char line[LINE_MAX];
506
507                 if (dent->d_name[0] == '.' || strcmp(dent->d_name, "..") == 0)
508                         continue;
509
510                 r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
511                 if (r < 0)
512                         return r;
513
514                 fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
515                 fddelim = "\n";
516
517                 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
518                 fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
519                 if (fd < 0)
520                         continue;
521
522                 fdinfo = fdopen(fd, "re");
523                 if (fdinfo == NULL) {
524                         close(fd);
525                         continue;
526                 }
527
528                 while(fgets(line, sizeof(line), fdinfo) != NULL)
529                         fprintf(stream, "%s%s",
530                                 line, strchr(line, '\n') == NULL ? "\n" : "");
531         }
532
533         return 0;
534 }
535
536 int main(int argc, char* argv[]) {
537
538         _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
539                 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
540                 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
541                 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL, *core_open_fds = NULL,
542                 *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL,
543                 *core_cwd = NULL, *core_root = NULL, *core_environ = NULL,
544                 *exe = NULL, *comm = NULL, *filename = NULL;
545         const char *info[_INFO_LEN];
546
547         _cleanup_close_ int coredump_fd = -1;
548
549         struct iovec iovec[26];
550         off_t coredump_size;
551         int r, j = 0;
552         uid_t uid, owner_uid;
553         gid_t gid;
554         pid_t pid;
555         char *t;
556         const char *p;
557
558         /* Make sure we never enter a loop */
559         prctl(PR_SET_DUMPABLE, 0);
560
561         /* First, log to a safe place, since we don't know what
562          * crashed and it might be journald which we'd rather not log
563          * to then. */
564         log_set_target(LOG_TARGET_KMSG);
565         log_open();
566
567         if (argc < INFO_COMM + 1) {
568                 log_error("Not enough arguments passed from kernel (%d, expected %d).",
569                           argc - 1, INFO_COMM + 1 - 1);
570                 r = -EINVAL;
571                 goto finish;
572         }
573
574         /* Ignore all parse errors */
575         parse_config();
576
577         log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
578         log_debug("Selected compression %s.", yes_no(arg_compress));
579
580         r = parse_uid(argv[INFO_UID + 1], &uid);
581         if (r < 0) {
582                 log_error("Failed to parse UID.");
583                 goto finish;
584         }
585
586         r = parse_pid(argv[INFO_PID + 1], &pid);
587         if (r < 0) {
588                 log_error("Failed to parse PID.");
589                 goto finish;
590         }
591
592         r = parse_gid(argv[INFO_GID + 1], &gid);
593         if (r < 0) {
594                 log_error("Failed to parse GID.");
595                 goto finish;
596         }
597
598         if (get_process_comm(pid, &comm) < 0) {
599                 log_warning("Failed to get COMM, falling back to the command line.");
600                 comm = strv_join(argv + INFO_COMM + 1, " ");
601         }
602
603         if (get_process_exe(pid, &exe) < 0)
604                 log_warning("Failed to get EXE.");
605
606         info[INFO_PID] = argv[INFO_PID + 1];
607         info[INFO_UID] = argv[INFO_UID + 1];
608         info[INFO_GID] = argv[INFO_GID + 1];
609         info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
610         info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
611         info[INFO_COMM] = comm;
612         info[INFO_EXE] = exe;
613
614         if (cg_pid_get_unit(pid, &t) >= 0) {
615
616                 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
617
618                         /* If we are journald, we cut things short,
619                          * don't write to the journal, but still
620                          * create a coredump. */
621
622                         if (arg_storage != COREDUMP_STORAGE_NONE)
623                                 arg_storage = COREDUMP_STORAGE_EXTERNAL;
624
625                         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
626                         if (r < 0)
627                                 goto finish;
628
629                         r = maybe_remove_external_coredump(filename, coredump_size);
630                         if (r < 0)
631                                 goto finish;
632
633                         log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
634                         goto finish;
635                 }
636
637                 core_unit = strappend("COREDUMP_UNIT=", t);
638         } else if (cg_pid_get_user_unit(pid, &t) >= 0)
639                 core_unit = strappend("COREDUMP_USER_UNIT=", t);
640
641         if (core_unit)
642                 IOVEC_SET_STRING(iovec[j++], core_unit);
643
644         /* OK, now we know it's not the journal, hence we can make use
645          * of it now. */
646         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
647         log_open();
648
649         core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
650         if (core_pid)
651                 IOVEC_SET_STRING(iovec[j++], core_pid);
652
653         core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
654         if (core_uid)
655                 IOVEC_SET_STRING(iovec[j++], core_uid);
656
657         core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
658         if (core_gid)
659                 IOVEC_SET_STRING(iovec[j++], core_gid);
660
661         core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
662         if (core_signal)
663                 IOVEC_SET_STRING(iovec[j++], core_signal);
664
665         if (sd_pid_get_session(pid, &t) >= 0) {
666                 core_session = strappend("COREDUMP_SESSION=", t);
667                 free(t);
668
669                 if (core_session)
670                         IOVEC_SET_STRING(iovec[j++], core_session);
671         }
672
673         if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
674                 r = asprintf(&core_owner_uid,
675                              "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
676                 if (r > 0)
677                         IOVEC_SET_STRING(iovec[j++], core_owner_uid);
678         }
679
680         if (sd_pid_get_slice(pid, &t) >= 0) {
681                 core_slice = strappend("COREDUMP_SLICE=", t);
682                 free(t);
683
684                 if (core_slice)
685                         IOVEC_SET_STRING(iovec[j++], core_slice);
686         }
687
688         if (comm) {
689                 core_comm = strappend("COREDUMP_COMM=", comm);
690                 if (core_comm)
691                         IOVEC_SET_STRING(iovec[j++], core_comm);
692         }
693
694         if (exe) {
695                 core_exe = strappend("COREDUMP_EXE=", exe);
696                 if (core_exe)
697                         IOVEC_SET_STRING(iovec[j++], core_exe);
698         }
699
700         if (get_process_cmdline(pid, 0, false, &t) >= 0) {
701                 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
702                 free(t);
703
704                 if (core_cmdline)
705                         IOVEC_SET_STRING(iovec[j++], core_cmdline);
706         }
707
708         if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
709                 core_cgroup = strappend("COREDUMP_CGROUP=", t);
710                 free(t);
711
712                 if (core_cgroup)
713                         IOVEC_SET_STRING(iovec[j++], core_cgroup);
714         }
715
716         if (compose_open_fds(pid, &t) >= 0) {
717                 core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
718                 free(t);
719
720                 if (core_open_fds)
721                         IOVEC_SET_STRING(iovec[j++], core_open_fds);
722         }
723
724         p = procfs_file_alloca(pid, "status");
725         if (read_full_file(p, &t, NULL) >= 0) {
726                 core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
727                 free(t);
728
729                 if (core_proc_status)
730                         IOVEC_SET_STRING(iovec[j++], core_proc_status);
731         }
732
733         p = procfs_file_alloca(pid, "maps");
734         if (read_full_file(p, &t, NULL) >= 0) {
735                 core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
736                 free(t);
737
738                 if (core_proc_maps)
739                         IOVEC_SET_STRING(iovec[j++], core_proc_maps);
740         }
741
742         p = procfs_file_alloca(pid, "limits");
743         if (read_full_file(p, &t, NULL) >= 0) {
744                 core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
745                 free(t);
746
747                 if (core_proc_limits)
748                         IOVEC_SET_STRING(iovec[j++], core_proc_limits);
749         }
750
751         p = procfs_file_alloca(pid, "cgroup");
752         if (read_full_file(p, &t, NULL) >=0) {
753                 core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
754                 free(t);
755
756                 if (core_proc_cgroup)
757                         IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
758         }
759
760         if (get_process_cwd(pid, &t) >= 0) {
761                 core_cwd = strappend("COREDUMP_CWD=", t);
762                 free(t);
763
764                 if (core_cwd)
765                         IOVEC_SET_STRING(iovec[j++], core_cwd);
766         }
767
768         if (get_process_root(pid, &t) >= 0) {
769                 core_root = strappend("COREDUMP_ROOT=", t);
770                 free(t);
771
772                 if (core_root)
773                         IOVEC_SET_STRING(iovec[j++], core_root);
774         }
775
776         if (get_process_environ(pid, &t) >= 0) {
777                 core_environ = strappend("COREDUMP_ENVIRON=", t);
778                 free(t);
779
780                 if (core_environ)
781                         IOVEC_SET_STRING(iovec[j++], core_environ);
782         }
783
784         core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
785         if (core_timestamp)
786                 IOVEC_SET_STRING(iovec[j++], core_timestamp);
787
788         IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
789         IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
790
791         /* Vacuum before we write anything again */
792         coredump_vacuum(-1, arg_keep_free, arg_max_use);
793
794         /* Always stream the coredump to disk, if that's possible */
795         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
796         if (r < 0)
797                 /* skip whole core dumping part */
798                 goto log;
799
800         /* If we don't want to keep the coredump on disk, remove it
801          * now, as later on we will lack the privileges for
802          * it. However, we keep the fd to it, so that we can still
803          * process it and log it. */
804         r = maybe_remove_external_coredump(filename, coredump_size);
805         if (r < 0)
806                 goto finish;
807         if (r == 0) {
808                 const char *coredump_filename;
809
810                 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
811                 IOVEC_SET_STRING(iovec[j++], coredump_filename);
812         }
813
814         /* Vacuum again, but exclude the coredump we just created */
815         coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
816
817         /* Now, let's drop privileges to become the user who owns the
818          * segfaulted process and allocate the coredump memory under
819          * the user's uid. This also ensures that the credentials
820          * journald will see are the ones of the coredumping user,
821          * thus making sure the user gets access to the core dump. */
822         if (setresgid(gid, gid, gid) < 0 ||
823             setresuid(uid, uid, uid) < 0) {
824                 log_error_errno(errno, "Failed to drop privileges: %m");
825                 r = -errno;
826                 goto finish;
827         }
828
829 #ifdef HAVE_ELFUTILS
830         /* Try to get a strack trace if we can */
831         if (coredump_size <= arg_process_size_max) {
832                 _cleanup_free_ char *stacktrace = NULL;
833
834                 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
835                 if (r >= 0)
836                         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
837                 else if (r == -EINVAL)
838                         log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
839                 else
840                         log_warning_errno(r, "Failed to generate stack trace: %m");
841         }
842
843         if (!core_message)
844 #endif
845 log:
846         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
847         if (core_message)
848                 IOVEC_SET_STRING(iovec[j++], core_message);
849
850         /* Optionally store the entire coredump in the journal */
851         if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
852             coredump_size <= (off_t) arg_journal_size_max) {
853                 size_t sz;
854
855                 /* Store the coredump itself in the journal */
856
857                 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
858                 if (r >= 0) {
859                         iovec[j].iov_base = coredump_data;
860                         iovec[j].iov_len = sz;
861                         j++;
862                 }
863         }
864
865         r = sd_journal_sendv(iovec, j);
866         if (r < 0)
867                 log_error_errno(r, "Failed to log coredump: %m");
868
869 finish:
870         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
871 }