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