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