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