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