chiark / gitweb /
coredump: use openat
[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         size_t ignored_size;
482         const char *fddelim = "", *path;
483         struct dirent *dent = NULL;
484         _cleanup_closedir_ DIR *proc_fd_dir = NULL;
485         _cleanup_close_ int proc_fdinfo_fd = -1;
486         int r = 0;
487
488         assert(pid >= 0);
489         assert(open_fds != NULL);
490
491         path = procfs_file_alloca(pid, "fd");
492         proc_fd_dir = opendir(path);
493         if (!proc_fd_dir)
494                 return -errno;
495
496         proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo",
497                                 O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
498         if (proc_fdinfo_fd < 0)
499                 return -errno;
500
501         stream = open_memstream(open_fds, &ignored_size);
502         if (!stream)
503                 return -ENOMEM;
504
505         for (dent = readdir(proc_fd_dir); dent != NULL; dent = readdir(proc_fd_dir)) {
506                 _cleanup_free_ char *fdname = NULL;
507                 int fd;
508                 _cleanup_fclose_ FILE *fdinfo = NULL;
509                 char line[LINE_MAX];
510
511                 if (dent->d_name[0] == '.' || strcmp(dent->d_name, "..") == 0)
512                         continue;
513
514                 r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &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                 fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
523                 if (fd < 0)
524                         continue;
525
526                 fdinfo = fdopen(fd, "re");
527                 if (fdinfo == NULL) {
528                         close(fd);
529                         continue;
530                 }
531
532                 while(fgets(line, sizeof(line), fdinfo) != NULL)
533                         fprintf(stream, "%s%s",
534                                 line, strchr(line, '\n') == NULL ? "\n" : "");
535         }
536
537         return 0;
538 }
539
540 int main(int argc, char* argv[]) {
541
542         _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
543                 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
544                 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
545                 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL, *core_open_fds = NULL,
546                 *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL,
547                 *core_cwd = NULL, *core_root = NULL, *core_environ = NULL,
548                 *exe = NULL, *comm = NULL, *filename = NULL;
549         const char *info[_INFO_LEN];
550
551         _cleanup_close_ int coredump_fd = -1;
552
553         struct iovec iovec[26];
554         off_t coredump_size;
555         int r, j = 0;
556         uid_t uid, owner_uid;
557         gid_t gid;
558         pid_t pid;
559         char *t;
560         const char *p;
561
562         /* Make sure we never enter a loop */
563         prctl(PR_SET_DUMPABLE, 0);
564
565         /* First, log to a safe place, since we don't know what
566          * crashed and it might be journald which we'd rather not log
567          * to then. */
568         log_set_target(LOG_TARGET_KMSG);
569         log_open();
570
571         if (argc < INFO_COMM + 1) {
572                 log_error("Not enough arguments passed from kernel (%d, expected %d).",
573                           argc - 1, INFO_COMM + 1 - 1);
574                 r = -EINVAL;
575                 goto finish;
576         }
577
578         /* Ignore all parse errors */
579         parse_config();
580
581         log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
582         log_debug("Selected compression %s.", yes_no(arg_compress));
583
584         r = parse_uid(argv[INFO_UID + 1], &uid);
585         if (r < 0) {
586                 log_error("Failed to parse UID.");
587                 goto finish;
588         }
589
590         r = parse_pid(argv[INFO_PID + 1], &pid);
591         if (r < 0) {
592                 log_error("Failed to parse PID.");
593                 goto finish;
594         }
595
596         r = parse_gid(argv[INFO_GID + 1], &gid);
597         if (r < 0) {
598                 log_error("Failed to parse GID.");
599                 goto finish;
600         }
601
602         if (get_process_comm(pid, &comm) < 0) {
603                 log_warning("Failed to get COMM, falling back to the command line.");
604                 comm = strv_join(argv + INFO_COMM + 1, " ");
605         }
606
607         if (get_process_exe(pid, &exe) < 0)
608                 log_warning("Failed to get EXE.");
609
610         info[INFO_PID] = argv[INFO_PID + 1];
611         info[INFO_UID] = argv[INFO_UID + 1];
612         info[INFO_GID] = argv[INFO_GID + 1];
613         info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
614         info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
615         info[INFO_COMM] = comm;
616         info[INFO_EXE] = exe;
617
618         if (cg_pid_get_unit(pid, &t) >= 0) {
619
620                 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
621
622                         /* If we are journald, we cut things short,
623                          * don't write to the journal, but still
624                          * create a coredump. */
625
626                         if (arg_storage != COREDUMP_STORAGE_NONE)
627                                 arg_storage = COREDUMP_STORAGE_EXTERNAL;
628
629                         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
630                         if (r < 0)
631                                 goto finish;
632
633                         r = maybe_remove_external_coredump(filename, coredump_size);
634                         if (r < 0)
635                                 goto finish;
636
637                         log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
638                         goto finish;
639                 }
640
641                 core_unit = strappend("COREDUMP_UNIT=", t);
642         } else if (cg_pid_get_user_unit(pid, &t) >= 0)
643                 core_unit = strappend("COREDUMP_USER_UNIT=", t);
644
645         if (core_unit)
646                 IOVEC_SET_STRING(iovec[j++], core_unit);
647
648         /* OK, now we know it's not the journal, hence we can make use
649          * of it now. */
650         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
651         log_open();
652
653         core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
654         if (core_pid)
655                 IOVEC_SET_STRING(iovec[j++], core_pid);
656
657         core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
658         if (core_uid)
659                 IOVEC_SET_STRING(iovec[j++], core_uid);
660
661         core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
662         if (core_gid)
663                 IOVEC_SET_STRING(iovec[j++], core_gid);
664
665         core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
666         if (core_signal)
667                 IOVEC_SET_STRING(iovec[j++], core_signal);
668
669         if (sd_pid_get_session(pid, &t) >= 0) {
670                 core_session = strappend("COREDUMP_SESSION=", t);
671                 free(t);
672
673                 if (core_session)
674                         IOVEC_SET_STRING(iovec[j++], core_session);
675         }
676
677         if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
678                 r = asprintf(&core_owner_uid,
679                              "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
680                 if (r > 0)
681                         IOVEC_SET_STRING(iovec[j++], core_owner_uid);
682         }
683
684         if (sd_pid_get_slice(pid, &t) >= 0) {
685                 core_slice = strappend("COREDUMP_SLICE=", t);
686                 free(t);
687
688                 if (core_slice)
689                         IOVEC_SET_STRING(iovec[j++], core_slice);
690         }
691
692         if (comm) {
693                 core_comm = strappend("COREDUMP_COMM=", comm);
694                 if (core_comm)
695                         IOVEC_SET_STRING(iovec[j++], core_comm);
696         }
697
698         if (exe) {
699                 core_exe = strappend("COREDUMP_EXE=", exe);
700                 if (core_exe)
701                         IOVEC_SET_STRING(iovec[j++], core_exe);
702         }
703
704         if (get_process_cmdline(pid, 0, false, &t) >= 0) {
705                 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
706                 free(t);
707
708                 if (core_cmdline)
709                         IOVEC_SET_STRING(iovec[j++], core_cmdline);
710         }
711
712         if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
713                 core_cgroup = strappend("COREDUMP_CGROUP=", t);
714                 free(t);
715
716                 if (core_cgroup)
717                         IOVEC_SET_STRING(iovec[j++], core_cgroup);
718         }
719
720         if (compose_open_fds(pid, &t) >= 0) {
721                 core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
722                 free(t);
723
724                 if (core_open_fds)
725                         IOVEC_SET_STRING(iovec[j++], core_open_fds);
726         }
727
728         p = procfs_file_alloca(pid, "status");
729         if (read_full_file(p, &t, NULL) >= 0) {
730                 core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
731                 free(t);
732
733                 if (core_proc_status)
734                         IOVEC_SET_STRING(iovec[j++], core_proc_status);
735         }
736
737         p = procfs_file_alloca(pid, "maps");
738         if (read_full_file(p, &t, NULL) >= 0) {
739                 core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
740                 free(t);
741
742                 if (core_proc_maps)
743                         IOVEC_SET_STRING(iovec[j++], core_proc_maps);
744         }
745
746         p = procfs_file_alloca(pid, "limits");
747         if (read_full_file(p, &t, NULL) >= 0) {
748                 core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
749                 free(t);
750
751                 if (core_proc_limits)
752                         IOVEC_SET_STRING(iovec[j++], core_proc_limits);
753         }
754
755         p = procfs_file_alloca(pid, "cgroup");
756         if (read_full_file(p, &t, NULL) >=0) {
757                 core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
758                 free(t);
759
760                 if (core_proc_cgroup)
761                         IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
762         }
763
764         if (get_process_cwd(pid, &t) >= 0) {
765                 core_cwd = strappend("COREDUMP_CWD=", t);
766                 free(t);
767
768                 if (core_cwd)
769                         IOVEC_SET_STRING(iovec[j++], core_cwd);
770         }
771
772         if (get_process_root(pid, &t) >= 0) {
773                 core_root = strappend("COREDUMP_ROOT=", t);
774                 free(t);
775
776                 if (core_root)
777                         IOVEC_SET_STRING(iovec[j++], core_root);
778         }
779
780         if (get_process_environ(pid, &t) >= 0) {
781                 core_environ = strappend("COREDUMP_ENVIRON=", t);
782                 free(t);
783
784                 if (core_environ)
785                         IOVEC_SET_STRING(iovec[j++], core_environ);
786         }
787
788         core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
789         if (core_timestamp)
790                 IOVEC_SET_STRING(iovec[j++], core_timestamp);
791
792         IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
793         IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
794
795         /* Vacuum before we write anything again */
796         coredump_vacuum(-1, arg_keep_free, arg_max_use);
797
798         /* Always stream the coredump to disk, if that's possible */
799         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
800         if (r < 0)
801                 /* skip whole core dumping part */
802                 goto log;
803
804         /* If we don't want to keep the coredump on disk, remove it
805          * now, as later on we will lack the privileges for
806          * it. However, we keep the fd to it, so that we can still
807          * process it and log it. */
808         r = maybe_remove_external_coredump(filename, coredump_size);
809         if (r < 0)
810                 goto finish;
811         if (r == 0) {
812                 const char *coredump_filename;
813
814                 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
815                 IOVEC_SET_STRING(iovec[j++], coredump_filename);
816         }
817
818         /* Vacuum again, but exclude the coredump we just created */
819         coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
820
821         /* Now, let's drop privileges to become the user who owns the
822          * segfaulted process and allocate the coredump memory under
823          * the user's uid. This also ensures that the credentials
824          * journald will see are the ones of the coredumping user,
825          * thus making sure the user gets access to the core dump. */
826         if (setresgid(gid, gid, gid) < 0 ||
827             setresuid(uid, uid, uid) < 0) {
828                 log_error("Failed to drop privileges: %m");
829                 r = -errno;
830                 goto finish;
831         }
832
833 #ifdef HAVE_ELFUTILS
834         /* Try to get a strack trace if we can */
835         if (coredump_size <= arg_process_size_max) {
836                 _cleanup_free_ char *stacktrace = NULL;
837
838                 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
839                 if (r >= 0)
840                         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
841                 else if (r == -EINVAL)
842                         log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
843                 else
844                         log_warning("Failed to generate stack trace: %s", strerror(-r));
845         }
846
847         if (!core_message)
848 #endif
849 log:
850         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
851         if (core_message)
852                 IOVEC_SET_STRING(iovec[j++], core_message);
853
854         /* Optionally store the entire coredump in the journal */
855         if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
856             coredump_size <= (off_t) arg_journal_size_max) {
857                 size_t sz;
858
859                 /* Store the coredump itself in the journal */
860
861                 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
862                 if (r >= 0) {
863                         iovec[j].iov_base = coredump_data;
864                         iovec[j].iov_len = sz;
865                         j++;
866                 }
867         }
868
869         r = sd_journal_sendv(iovec, j);
870         if (r < 0)
871                 log_error("Failed to log coredump: %s", strerror(-r));
872
873 finish:
874         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
875 }