chiark / gitweb /
coredump: simplify a few things by allocating small fields on the stack rather than...
[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         /* The small core field we allocate on the stack, to keep things simple */
534         char
535                 *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
536                 *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL,
537                 *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL,
538                 *core_slice = NULL;
539
540         /* The larger ones we allocate on the heap */
541         _cleanup_free_ char
542                 *core_timestamp = NULL,  *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL,
543                 *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL,
544                 *core_proc_cgroup = NULL, *core_environ = NULL;
545
546         _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL;
547         const char *info[_INFO_LEN];
548
549         _cleanup_close_ int coredump_fd = -1;
550
551         struct iovec iovec[26];
552         off_t coredump_size;
553         int r, j = 0;
554         uid_t uid, owner_uid;
555         gid_t gid;
556         pid_t pid;
557         char *t;
558         const char *p;
559
560         /* Make sure we never enter a loop */
561         prctl(PR_SET_DUMPABLE, 0);
562
563         /* First, log to a safe place, since we don't know what
564          * crashed and it might be journald which we'd rather not log
565          * to then. */
566         log_set_target(LOG_TARGET_KMSG);
567         log_open();
568
569         if (argc < INFO_COMM + 1) {
570                 log_error("Not enough arguments passed from kernel (%d, expected %d).",
571                           argc - 1, INFO_COMM + 1 - 1);
572                 r = -EINVAL;
573                 goto finish;
574         }
575
576         /* Ignore all parse errors */
577         parse_config();
578
579         log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
580         log_debug("Selected compression %s.", yes_no(arg_compress));
581
582         r = parse_uid(argv[INFO_UID + 1], &uid);
583         if (r < 0) {
584                 log_error("Failed to parse UID.");
585                 goto finish;
586         }
587
588         r = parse_pid(argv[INFO_PID + 1], &pid);
589         if (r < 0) {
590                 log_error("Failed to parse PID.");
591                 goto finish;
592         }
593
594         r = parse_gid(argv[INFO_GID + 1], &gid);
595         if (r < 0) {
596                 log_error("Failed to parse GID.");
597                 goto finish;
598         }
599
600         if (get_process_comm(pid, &comm) < 0) {
601                 log_warning("Failed to get COMM, falling back to the command line.");
602                 comm = strv_join(argv + INFO_COMM + 1, " ");
603         }
604
605         if (get_process_exe(pid, &exe) < 0)
606                 log_warning("Failed to get EXE.");
607
608         info[INFO_PID] = argv[INFO_PID + 1];
609         info[INFO_UID] = argv[INFO_UID + 1];
610         info[INFO_GID] = argv[INFO_GID + 1];
611         info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
612         info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
613         info[INFO_COMM] = comm;
614         info[INFO_EXE] = exe;
615
616         if (cg_pid_get_unit(pid, &t) >= 0) {
617
618                 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
619                         free(t);
620
621                         /* If we are journald, we cut things short,
622                          * don't write to the journal, but still
623                          * create a coredump. */
624
625                         if (arg_storage != COREDUMP_STORAGE_NONE)
626                                 arg_storage = COREDUMP_STORAGE_EXTERNAL;
627
628                         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
629                         if (r < 0)
630                                 goto finish;
631
632                         r = maybe_remove_external_coredump(filename, coredump_size);
633                         if (r < 0)
634                                 goto finish;
635
636                         log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
637                         goto finish;
638                 }
639
640                 core_unit = strappenda("COREDUMP_UNIT=", t);
641                 free(t);
642
643         } else if (cg_pid_get_user_unit(pid, &t) >= 0) {
644                 core_unit = strappenda("COREDUMP_USER_UNIT=", t);
645                 free(t);
646         }
647
648         if (core_unit)
649                 IOVEC_SET_STRING(iovec[j++], core_unit);
650
651         /* OK, now we know it's not the journal, hence we can make use
652          * of it now. */
653         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
654         log_open();
655
656         core_pid = strappenda("COREDUMP_PID=", info[INFO_PID]);
657         IOVEC_SET_STRING(iovec[j++], core_pid);
658
659         core_uid = strappenda("COREDUMP_UID=", info[INFO_UID]);
660         IOVEC_SET_STRING(iovec[j++], core_uid);
661
662         core_gid = strappenda("COREDUMP_GID=", info[INFO_GID]);
663         IOVEC_SET_STRING(iovec[j++], core_gid);
664
665         core_signal = strappenda("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
666         IOVEC_SET_STRING(iovec[j++], core_signal);
667
668         if (sd_pid_get_session(pid, &t) >= 0) {
669                 core_session = strappenda("COREDUMP_SESSION=", t);
670                 free(t);
671
672                 IOVEC_SET_STRING(iovec[j++], core_session);
673         }
674
675         if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
676                 r = asprintf(&core_owner_uid,
677                              "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
678                 if (r > 0)
679                         IOVEC_SET_STRING(iovec[j++], core_owner_uid);
680         }
681
682         if (sd_pid_get_slice(pid, &t) >= 0) {
683                 core_slice = strappenda("COREDUMP_SLICE=", t);
684                 free(t);
685
686                 IOVEC_SET_STRING(iovec[j++], core_slice);
687         }
688
689         if (comm) {
690                 core_comm = strappenda("COREDUMP_COMM=", comm);
691                 IOVEC_SET_STRING(iovec[j++], core_comm);
692         }
693
694         if (exe) {
695                 core_exe = strappenda("COREDUMP_EXE=", exe);
696                 IOVEC_SET_STRING(iovec[j++], core_exe);
697         }
698
699         if (get_process_cmdline(pid, 0, false, &t) >= 0) {
700                 core_cmdline = strappenda("COREDUMP_CMDLINE=", t);
701                 free(t);
702
703                 IOVEC_SET_STRING(iovec[j++], core_cmdline);
704         }
705
706         if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
707                 core_cgroup = strappenda("COREDUMP_CGROUP=", t);
708                 free(t);
709
710                 IOVEC_SET_STRING(iovec[j++], core_cgroup);
711         }
712
713         if (compose_open_fds(pid, &t) >= 0) {
714                 core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
715                 free(t);
716
717                 if (core_open_fds)
718                         IOVEC_SET_STRING(iovec[j++], core_open_fds);
719         }
720
721         p = procfs_file_alloca(pid, "status");
722         if (read_full_file(p, &t, NULL) >= 0) {
723                 core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
724                 free(t);
725
726                 if (core_proc_status)
727                         IOVEC_SET_STRING(iovec[j++], core_proc_status);
728         }
729
730         p = procfs_file_alloca(pid, "maps");
731         if (read_full_file(p, &t, NULL) >= 0) {
732                 core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
733                 free(t);
734
735                 if (core_proc_maps)
736                         IOVEC_SET_STRING(iovec[j++], core_proc_maps);
737         }
738
739         p = procfs_file_alloca(pid, "limits");
740         if (read_full_file(p, &t, NULL) >= 0) {
741                 core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
742                 free(t);
743
744                 if (core_proc_limits)
745                         IOVEC_SET_STRING(iovec[j++], core_proc_limits);
746         }
747
748         p = procfs_file_alloca(pid, "cgroup");
749         if (read_full_file(p, &t, NULL) >=0) {
750                 core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
751                 free(t);
752
753                 if (core_proc_cgroup)
754                         IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
755         }
756
757         if (get_process_cwd(pid, &t) >= 0) {
758                 core_cwd = strappenda("COREDUMP_CWD=", t);
759                 free(t);
760
761                 IOVEC_SET_STRING(iovec[j++], core_cwd);
762         }
763
764         if (get_process_root(pid, &t) >= 0) {
765                 core_root = strappenda("COREDUMP_ROOT=", t);
766                 free(t);
767
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 }