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