]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
Revert "journal: do not check for number of files"
[thirdparty/systemd.git] / src / journal / coredump.c
CommitLineData
f5e04665
LP
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
5430f7f2
LP
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
f5e04665
LP
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
5430f7f2 16 Lesser General Public License for more details.
f5e04665 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
f5e04665
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <unistd.h>
803a3464
LP
24#include <stdio.h>
25#include <sys/prctl.h>
34c10968 26#include <sys/types.h>
cacd6403 27#include <sys/xattr.h>
f5e04665 28
4d229b31
UTL
29#ifdef HAVE_ELFUTILS
30# include <dwarf.h>
31# include <elfutils/libdwfl.h>
32#endif
33
73f860db
ZJS
34#include "systemd/sd-journal.h"
35#include "systemd/sd-login.h"
f5e04665
LP
36
37#include "log.h"
38#include "util.h"
3f132692 39#include "fileio.h"
1eef15b1 40#include "strv.h"
b7f7c685 41#include "macro.h"
49e942b2 42#include "mkdir.h"
803a3464 43#include "special.h"
ba1261bc 44#include "cgroup-util.h"
d18d46ec 45#include "journald-native.h"
34c10968
LP
46#include "conf-parser.h"
47#include "copy.h"
8d4e028f 48#include "stacktrace.h"
6388c315 49#include "path-util.h"
cfd652ed 50#include "compress.h"
0dc5d23c 51#include "coredump-vacuum.h"
f8eeeaf9 52#include "acl-util.h"
34727273 53
34c10968
LP
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))
f5e04665 64
c4aa09b0 65/* Make sure to not make this larger than the maximum journal entry
874bc134
ZJS
66 * size. See DATA_SIZE_MAX in journald-native.c. */
67assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
f5e04665
LP
68
69enum {
1eef15b1
ZJS
70 INFO_PID,
71 INFO_UID,
72 INFO_GID,
73 INFO_SIGNAL,
74 INFO_TIMESTAMP,
75 INFO_COMM,
76 INFO_EXE,
77 _INFO_LEN
f5e04665
LP
78};
79
34c10968
LP
80typedef 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
34c10968
LP
89static 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
96DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
8c9571d0 97static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
34727273
ZJS
98
99static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
8c9571d0 100static bool arg_compress = true;
34727273
ZJS
101static off_t arg_process_size_max = PROCESS_SIZE_MAX;
102static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
103static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
0dc5d23c
LP
104static off_t arg_keep_free = (off_t) -1;
105static off_t arg_max_use = (off_t) -1;
34c10968
LP
106
107static int parse_config(void) {
34c10968 108 static const ConfigTableItem items[] = {
8c9571d0
LP
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 },
34c10968
LP
116 {}
117 };
118
301af7e4
JT
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);
34c10968
LP
124}
125
126static 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
b59233e6
LP
133 assert(fd >= 0);
134
34c10968
LP
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);
4a62c710
MS
142 if (!acl)
143 return log_error_errno(errno, "Failed to get ACL: %m");
34c10968
LP
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) {
56f64d95 148 log_error_errno(errno, "Failed to patch ACL: %m");
34c10968
LP
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) {
56f64d95 155 log_warning_errno(errno, "Failed to patch ACL: %m");
34c10968
LP
156 return -errno;
157 }
158
4a62c710
MS
159 if (acl_set_fd(fd, acl) < 0)
160 return log_error_errno(errno, "Failed to apply ACL: %m");
34c10968
LP
161#endif
162
163 return 0;
164}
165
1eef15b1 166static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
0cd77f97 167
1eef15b1
ZJS
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",
0cd77f97
LP
176 };
177
34c10968 178 int r = 0;
0cd77f97 179 unsigned i;
34c10968 180
b59233e6
LP
181 assert(fd >= 0);
182
1eef15b1 183 /* Attach some metadata to coredumps via extended
34c10968
LP
184 * attributes. Just because we can. */
185
1eef15b1
ZJS
186 for (i = 0; i < _INFO_LEN; i++) {
187 int k;
188
189 if (isempty(info[i]) || !xattrs[i])
0cd77f97 190 continue;
34c10968 191
1eef15b1
ZJS
192 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
193 if (k < 0 && r == 0)
34c10968 194 r = -errno;
0cd77f97 195 }
34c10968
LP
196
197 return r;
198}
199
b0b21dce 200#define filename_escape(s) xescape((s), "./ ")
34c10968 201
b59233e6
LP
202static 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);
cfd652ed
ZJS
213
214 /* Ignore errors on these */
215 fchmod(fd, 0640);
216 fix_acl(fd, uid);
217 fix_xattr(fd, info);
218
4a62c710
MS
219 if (fsync(fd) < 0)
220 return log_error_errno(errno, "Failed to sync coredump %s: %m", filename);
cfd652ed 221
4a62c710
MS
222 if (rename(filename, target) < 0)
223 return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
cfd652ed
ZJS
224
225 return 0;
226}
227
228static int maybe_remove_external_coredump(const char *filename, off_t size) {
229
b59233e6 230 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
cfd652ed
ZJS
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
4a62c710
MS
239 if (unlink(filename) < 0 && errno != ENOENT)
240 return log_error_errno(errno, "Failed to unlink %s: %m", filename);
cfd652ed
ZJS
241
242 return 1;
243}
244
b59233e6
LP
245static int make_filename(const char *info[_INFO_LEN], char **ret) {
246 _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
34c10968 247 sd_id128_t boot;
34c10968
LP
248 int r;
249
1eef15b1 250 assert(info);
34c10968 251
1eef15b1 252 c = filename_escape(info[INFO_COMM]);
34c10968 253 if (!c)
b59233e6 254 return -ENOMEM;
34c10968 255
0dc5d23c
LP
256 u = filename_escape(info[INFO_UID]);
257 if (!u)
b59233e6 258 return -ENOMEM;
34c10968
LP
259
260 r = sd_id128_get_boot(&boot);
b59233e6 261 if (r < 0)
34c10968 262 return r;
34c10968 263
b59233e6
LP
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,
0dc5d23c 273 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
34c10968 274 c,
0dc5d23c 275 u,
34c10968
LP
276 SD_ID128_FORMAT_VAL(boot),
277 p,
b59233e6
LP
278 t) < 0)
279 return -ENOMEM;
280
281 return 0;
282}
283
284static 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);
23bbb0de
MS
302 if (r < 0)
303 return log_error_errno(r, "Failed to determine coredump file name: %m");
34c10968 304
ae6c3cc0
LP
305 r = tempfn_random(fn, &tmp);
306 if (r < 0)
307 return log_error_errno(r, "Failed to determine temporary file name: %m");
803a3464 308
d2e54fae 309 mkdir_p_label("/var/lib/systemd/coredump", 0755);
803a3464 310
34c10968 311 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
4a62c710
MS
312 if (fd < 0)
313 return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
803a3464 314
7430ec6a 315 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max, false);
84ee0960 316 if (r == -EFBIG) {
0dc5d23c 317 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
318 goto fail;
319 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
0dc5d23c 320 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
321 goto fail;
322 } else if (r < 0) {
da927ba9 323 log_error_errno(r, "Failed to dump coredump to file: %m");
34c10968
LP
324 goto fail;
325 }
803a3464 326
34c10968 327 if (fstat(fd, &st) < 0) {
56f64d95 328 log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
34c10968
LP
329 goto fail;
330 }
331
7849c2ac 332 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
56f64d95 333 log_error_errno(errno, "Failed to seek on %s: %m", tmp);
b59233e6 334 goto fail;
7849c2ac
TA
335 }
336
d89c8fdf 337#if defined(HAVE_XZ) || defined(HAVE_LZ4)
cfd652ed 338 /* If we will remove the coredump anyway, do not compress. */
34727273 339 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
8c9571d0 340 && arg_compress) {
cfd652ed 341
b59233e6
LP
342 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
343 _cleanup_close_ int fd_compressed = -1;
cfd652ed 344
d89c8fdf 345 fn_compressed = strappend(fn, COMPRESSED_EXT);
b59233e6 346 if (!fn_compressed) {
d89c8fdf 347 log_oom();
cfd652ed
ZJS
348 goto uncompressed;
349 }
350
ae6c3cc0
LP
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);
b59233e6 354 goto uncompressed;
cfd652ed
ZJS
355 }
356
b59233e6
LP
357 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
358 if (fd_compressed < 0) {
56f64d95 359 log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
b59233e6 360 goto uncompressed;
cfd652ed
ZJS
361 }
362
d89c8fdf 363 r = compress_stream(fd, fd_compressed, -1);
b59233e6 364 if (r < 0) {
da927ba9 365 log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
b59233e6
LP
366 goto fail_compressed;
367 }
368
369 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
cfd652ed 370 if (r < 0)
b59233e6
LP
371 goto fail_compressed;
372
373 /* OK, this worked, we can get rid of the uncompressed version now */
374 unlink_noerrno(tmp);
cfd652ed 375
b59233e6
LP
376 *ret_filename = fn_compressed; /* compressed */
377 *ret_fd = fd; /* uncompressed */
378 *ret_size = st.st_size; /* uncompressed */
cfd652ed 379
b59233e6 380 fn_compressed = NULL;
cfd652ed
ZJS
381 fd = -1;
382
383 return 0;
384
b59233e6
LP
385 fail_compressed:
386 unlink_noerrno(tmp_compressed);
34c10968 387 }
cfd652ed
ZJS
388
389uncompressed:
3b1a55e1 390#endif
cfd652ed
ZJS
391 r = fix_permissions(fd, tmp, fn, info, uid);
392 if (r < 0)
393 goto fail;
34c10968
LP
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
404fail:
405 unlink_noerrno(tmp);
406 return r;
407}
408
409static 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
8d4e028f 413 assert(fd >= 0);
34c10968
LP
414 assert(ret);
415 assert(ret_size);
416
4a62c710
MS
417 if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
418 return log_warning_errno(errno, "Failed to seek: %m");
803a3464 419
34c10968
LP
420 field = malloc(9 + size);
421 if (!field) {
cfd652ed 422 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
34c10968
LP
423 return -ENOMEM;
424 }
425
426 memcpy(field, "COREDUMP=", 9);
427
428 n = read(fd, field + 9, size);
23bbb0de
MS
429 if (n < 0)
430 return log_error_errno((int) n, "Failed to read core data: %m");
34c10968
LP
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}
803a3464 443
3f132692
JF
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 */
458static int compose_open_fds(pid_t pid, char **open_fds) {
4d84bc2f
LP
459 _cleanup_closedir_ DIR *proc_fd_dir = NULL;
460 _cleanup_close_ int proc_fdinfo_fd = -1;
461 _cleanup_free_ char *buffer = NULL;
3f132692 462 _cleanup_fclose_ FILE *stream = NULL;
59059b4a 463 const char *fddelim = "", *path;
3f132692 464 struct dirent *dent = NULL;
4d84bc2f 465 size_t size = 0;
3f132692
JF
466 int r = 0;
467
468 assert(pid >= 0);
469 assert(open_fds != NULL);
470
59059b4a 471 path = procfs_file_alloca(pid, "fd");
3f132692 472 proc_fd_dir = opendir(path);
59059b4a
ZJS
473 if (!proc_fd_dir)
474 return -errno;
3f132692 475
4d84bc2f 476 proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo", O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
59059b4a
ZJS
477 if (proc_fdinfo_fd < 0)
478 return -errno;
3f132692 479
4d84bc2f 480 stream = open_memstream(&buffer, &size);
3f132692
JF
481 if (!stream)
482 return -ENOMEM;
483
4d84bc2f 484 FOREACH_DIRENT(dent, proc_fd_dir, return -errno) {
3f132692 485 _cleanup_fclose_ FILE *fdinfo = NULL;
4d84bc2f 486 _cleanup_free_ char *fdname = NULL;
59059b4a 487 char line[LINE_MAX];
4d84bc2f 488 int fd;
3f132692 489
59059b4a 490 r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
3f132692
JF
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 */
59059b4a
ZJS
498 fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
499 if (fd < 0)
3f132692
JF
500 continue;
501
59059b4a
ZJS
502 fdinfo = fdopen(fd, "re");
503 if (fdinfo == NULL) {
504 close(fd);
3f132692 505 continue;
59059b4a 506 }
3f132692 507
4d84bc2f
LP
508 FOREACH_LINE(line, fdinfo, break) {
509 fputs(line, stream);
510 if (!endswith(line, "\n"))
511 fputc('\n', stream);
512 }
3f132692
JF
513 }
514
4d84bc2f
LP
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
3f132692
JF
525 return 0;
526}
527
f5e04665 528int main(int argc, char* argv[]) {
34c10968 529
8c8549db
LP
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;
1eef15b1 544 const char *info[_INFO_LEN];
34c10968
LP
545
546 _cleanup_close_ int coredump_fd = -1;
547
3f132692 548 struct iovec iovec[26];
34c10968 549 off_t coredump_size;
f5e04665 550 int r, j = 0;
a035f819 551 uid_t uid, owner_uid;
fee80f69 552 gid_t gid;
a035f819 553 pid_t pid;
34c10968 554 char *t;
3f132692 555 const char *p;
f5e04665 556
34c10968 557 /* Make sure we never enter a loop */
803a3464 558 prctl(PR_SET_DUMPABLE, 0);
f5e04665 559
34c10968
LP
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);
34c10968 564 log_open();
803a3464 565
1eef15b1
ZJS
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);
f5e04665
LP
569 r = -EINVAL;
570 goto finish;
571 }
572
34c10968
LP
573 /* Ignore all parse errors */
574 parse_config();
8c9571d0
LP
575
576 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
577 log_debug("Selected compression %s.", yes_no(arg_compress));
34c10968 578
1eef15b1 579 r = parse_uid(argv[INFO_UID + 1], &uid);
f5e04665 580 if (r < 0) {
34c10968
LP
581 log_error("Failed to parse UID.");
582 goto finish;
583 }
803a3464 584
1eef15b1 585 r = parse_pid(argv[INFO_PID + 1], &pid);
34c10968 586 if (r < 0) {
f5e04665 587 log_error("Failed to parse PID.");
f5e04665
LP
588 goto finish;
589 }
590
1eef15b1 591 r = parse_gid(argv[INFO_GID + 1], &gid);
34c10968
LP
592 if (r < 0) {
593 log_error("Failed to parse GID.");
594 goto finish;
595 }
596
1eef15b1 597 if (get_process_comm(pid, &comm) < 0) {
3f85ef0f 598 log_warning("Failed to get COMM, falling back to the command line.");
1eef15b1
ZJS
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
ba1261bc 613 if (cg_pid_get_unit(pid, &t) >= 0) {
803a3464
LP
614
615 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
8c8549db 616 free(t);
803a3464 617
34c10968
LP
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
9fe13294 625 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968
LP
626 if (r < 0)
627 goto finish;
628
9fe13294 629 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
630 if (r < 0)
631 goto finish;
632
9fe13294 633 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
803a3464
LP
634 goto finish;
635 }
636
8c8549db
LP
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 }
803a3464 644
f9045468
MT
645 if (core_unit)
646 IOVEC_SET_STRING(iovec[j++], core_unit);
647
34c10968
LP
648 /* OK, now we know it's not the journal, hence we can make use
649 * of it now. */
803a3464
LP
650 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
651 log_open();
652
8c8549db
LP
653 core_pid = strappenda("COREDUMP_PID=", info[INFO_PID]);
654 IOVEC_SET_STRING(iovec[j++], core_pid);
f5e04665 655
8c8549db
LP
656 core_uid = strappenda("COREDUMP_UID=", info[INFO_UID]);
657 IOVEC_SET_STRING(iovec[j++], core_uid);
f5e04665 658
8c8549db
LP
659 core_gid = strappenda("COREDUMP_GID=", info[INFO_GID]);
660 IOVEC_SET_STRING(iovec[j++], core_gid);
f5e04665 661
8c8549db
LP
662 core_signal = strappenda("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
663 IOVEC_SET_STRING(iovec[j++], core_signal);
f5e04665 664
f5e04665 665 if (sd_pid_get_session(pid, &t) >= 0) {
8c8549db 666 core_session = strappenda("COREDUMP_SESSION=", t);
f5e04665
LP
667 free(t);
668
8c8549db 669 IOVEC_SET_STRING(iovec[j++], core_session);
f5e04665
LP
670 }
671
a035f819 672 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
7de80bfe
KZ
673 r = asprintf(&core_owner_uid,
674 "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
675 if (r > 0)
a035f819
LP
676 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
677 }
678
679 if (sd_pid_get_slice(pid, &t) >= 0) {
8c8549db 680 core_slice = strappenda("COREDUMP_SLICE=", t);
a035f819
LP
681 free(t);
682
8c8549db 683 IOVEC_SET_STRING(iovec[j++], core_slice);
a035f819
LP
684 }
685
1eef15b1 686 if (comm) {
8c8549db
LP
687 core_comm = strappenda("COREDUMP_COMM=", comm);
688 IOVEC_SET_STRING(iovec[j++], core_comm);
1eef15b1
ZJS
689 }
690
691 if (exe) {
8c8549db
LP
692 core_exe = strappenda("COREDUMP_EXE=", exe);
693 IOVEC_SET_STRING(iovec[j++], core_exe);
f5e04665
LP
694 }
695
9bdbc2e2 696 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
8c8549db 697 core_cmdline = strappenda("COREDUMP_CMDLINE=", t);
f5e04665
LP
698 free(t);
699
8c8549db 700 IOVEC_SET_STRING(iovec[j++], core_cmdline);
f5e04665
LP
701 }
702
a035f819 703 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
8c8549db 704 core_cgroup = strappenda("COREDUMP_CGROUP=", t);
a035f819
LP
705 free(t);
706
8c8549db 707 IOVEC_SET_STRING(iovec[j++], core_cgroup);
a035f819
LP
708 }
709
3f132692
JF
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) {
8c8549db 755 core_cwd = strappenda("COREDUMP_CWD=", t);
3f132692
JF
756 free(t);
757
8c8549db 758 IOVEC_SET_STRING(iovec[j++], core_cwd);
3f132692
JF
759 }
760
761 if (get_process_root(pid, &t) >= 0) {
8c8549db 762 core_root = strappenda("COREDUMP_ROOT=", t);
3f132692
JF
763 free(t);
764
8c8549db 765 IOVEC_SET_STRING(iovec[j++], core_root);
3f132692
JF
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
1eef15b1 776 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
f5e04665
LP
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
0dc5d23c
LP
783 /* Vacuum before we write anything again */
784 coredump_vacuum(-1, arg_keep_free, arg_max_use);
785
34c10968 786 /* Always stream the coredump to disk, if that's possible */
9fe13294 787 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968 788 if (r < 0)
2424a475
ZJS
789 /* skip whole core dumping part */
790 goto log;
34c10968
LP
791
792 /* If we don't want to keep the coredump on disk, remove it
8d4e028f
LP
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. */
9fe13294 796 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
797 if (r < 0)
798 goto finish;
9fe13294
ZJS
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 }
34c10968 805
0dc5d23c
LP
806 /* Vacuum again, but exclude the coredump we just created */
807 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
808
fee80f69
LP
809 /* Now, let's drop privileges to become the user who owns the
810 * segfaulted process and allocate the coredump memory under
b26c631a
KP
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. */
fee80f69
LP
814 if (setresgid(gid, gid, gid) < 0 ||
815 setresuid(uid, uid, uid) < 0) {
56f64d95 816 log_error_errno(errno, "Failed to drop privileges: %m");
fee80f69
LP
817 r = -errno;
818 goto finish;
819 }
820
8d4e028f
LP
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)
1eef15b1 828 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
4d229b31
UTL
829 else if (r == -EINVAL)
830 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
8d4e028f 831 else
da927ba9 832 log_warning_errno(r, "Failed to generate stack trace: %m");
8d4e028f
LP
833 }
834
835 if (!core_message)
836#endif
2424a475 837log:
1eef15b1 838 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
8d4e028f
LP
839 if (core_message)
840 IOVEC_SET_STRING(iovec[j++], core_message);
841
34c10968
LP
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;
fee80f69 846
34c10968 847 /* Store the coredump itself in the journal */
fee80f69 848
34c10968
LP
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++;
ca0ceb6f 854 }
fee80f69
LP
855 }
856
f5e04665
LP
857 r = sd_journal_sendv(iovec, j);
858 if (r < 0)
da927ba9 859 log_error_errno(r, "Failed to log coredump: %m");
f5e04665
LP
860
861finish:
f5e04665
LP
862 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
863}