]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
systemctl: append default suffix only if none present
[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"
34c10968
LP
52
53#ifdef HAVE_ACL
34727273
ZJS
54# include <sys/acl.h>
55# include "acl-util.h"
56#endif
57
34c10968
LP
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))
f5e04665 68
c4aa09b0 69/* Make sure to not make this larger than the maximum journal entry
874bc134
ZJS
70 * size. See DATA_SIZE_MAX in journald-native.c. */
71assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
f5e04665
LP
72
73enum {
1eef15b1
ZJS
74 INFO_PID,
75 INFO_UID,
76 INFO_GID,
77 INFO_SIGNAL,
78 INFO_TIMESTAMP,
79 INFO_COMM,
80 INFO_EXE,
81 _INFO_LEN
f5e04665
LP
82};
83
34c10968
LP
84typedef 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
34c10968
LP
93static 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
100DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
8c9571d0 101static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
34727273
ZJS
102
103static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
8c9571d0 104static bool arg_compress = true;
34727273
ZJS
105static off_t arg_process_size_max = PROCESS_SIZE_MAX;
106static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
107static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
0dc5d23c
LP
108static off_t arg_keep_free = (off_t) -1;
109static off_t arg_max_use = (off_t) -1;
34c10968
LP
110
111static int parse_config(void) {
34c10968 112 static const ConfigTableItem items[] = {
8c9571d0
LP
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 },
34c10968
LP
120 {}
121 };
122
36f822c4
ZJS
123 return config_parse(NULL, "/etc/systemd/coredump.conf", NULL,
124 "Coredump\0",
125 config_item_table_lookup, items,
126 false, false, true, NULL);
34c10968
LP
127}
128
129static 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
b59233e6
LP
136 assert(fd >= 0);
137
34c10968
LP
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
1eef15b1 173static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
0cd77f97 174
1eef15b1
ZJS
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",
0cd77f97
LP
183 };
184
34c10968 185 int r = 0;
0cd77f97 186 unsigned i;
34c10968 187
b59233e6
LP
188 assert(fd >= 0);
189
1eef15b1 190 /* Attach some metadata to coredumps via extended
34c10968
LP
191 * attributes. Just because we can. */
192
1eef15b1
ZJS
193 for (i = 0; i < _INFO_LEN; i++) {
194 int k;
195
196 if (isempty(info[i]) || !xattrs[i])
0cd77f97 197 continue;
34c10968 198
1eef15b1
ZJS
199 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
200 if (k < 0 && r == 0)
34c10968 201 r = -errno;
0cd77f97 202 }
34c10968
LP
203
204 return r;
205}
206
b0b21dce 207#define filename_escape(s) xescape((s), "./ ")
34c10968 208
b59233e6
LP
209static 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);
cfd652ed
ZJS
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
239static int maybe_remove_external_coredump(const char *filename, off_t size) {
240
b59233e6 241 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
cfd652ed
ZJS
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
9d951bf4 250 if (unlink(filename) < 0 && errno != ENOENT) {
cfd652ed
ZJS
251 log_error("Failed to unlink %s: %m", filename);
252 return -errno;
253 }
254
255 return 1;
256}
257
b59233e6
LP
258static int make_filename(const char *info[_INFO_LEN], char **ret) {
259 _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
34c10968 260 sd_id128_t boot;
34c10968
LP
261 int r;
262
1eef15b1 263 assert(info);
34c10968 264
1eef15b1 265 c = filename_escape(info[INFO_COMM]);
34c10968 266 if (!c)
b59233e6 267 return -ENOMEM;
34c10968 268
0dc5d23c
LP
269 u = filename_escape(info[INFO_UID]);
270 if (!u)
b59233e6 271 return -ENOMEM;
34c10968
LP
272
273 r = sd_id128_get_boot(&boot);
b59233e6 274 if (r < 0)
34c10968 275 return r;
34c10968 276
b59233e6
LP
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,
0dc5d23c 286 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
34c10968 287 c,
0dc5d23c 288 u,
34c10968
LP
289 SD_ID128_FORMAT_VAL(boot),
290 p,
b59233e6
LP
291 t) < 0)
292 return -ENOMEM;
293
294 return 0;
295}
296
297static 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) {
da927ba9 316 log_error_errno(r, "Failed to determine coredump file name: %m");
b59233e6
LP
317 return r;
318 }
34c10968
LP
319
320 tmp = tempfn_random(fn);
321 if (!tmp)
322 return log_oom();
803a3464 323
d2e54fae 324 mkdir_p_label("/var/lib/systemd/coredump", 0755);
803a3464 325
34c10968
LP
326 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
327 if (fd < 0) {
cfd652ed 328 log_error("Failed to create coredump file %s: %m", tmp);
803a3464
LP
329 return -errno;
330 }
331
93240d3a 332 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
84ee0960 333 if (r == -EFBIG) {
0dc5d23c 334 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
335 goto fail;
336 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
0dc5d23c 337 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
338 goto fail;
339 } else if (r < 0) {
da927ba9 340 log_error_errno(r, "Failed to dump coredump to file: %m");
34c10968
LP
341 goto fail;
342 }
803a3464 343
34c10968 344 if (fstat(fd, &st) < 0) {
1eef15b1 345 log_error("Failed to fstat coredump %s: %m", tmp);
34c10968
LP
346 goto fail;
347 }
348
7849c2ac
TA
349 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
350 log_error("Failed to seek on %s: %m", tmp);
b59233e6 351 goto fail;
7849c2ac
TA
352 }
353
d89c8fdf 354#if defined(HAVE_XZ) || defined(HAVE_LZ4)
cfd652ed 355 /* If we will remove the coredump anyway, do not compress. */
34727273 356 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
8c9571d0 357 && arg_compress) {
cfd652ed 358
b59233e6
LP
359 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
360 _cleanup_close_ int fd_compressed = -1;
cfd652ed 361
d89c8fdf 362 fn_compressed = strappend(fn, COMPRESSED_EXT);
b59233e6 363 if (!fn_compressed) {
d89c8fdf 364 log_oom();
cfd652ed
ZJS
365 goto uncompressed;
366 }
367
b59233e6
LP
368 tmp_compressed = tempfn_random(fn_compressed);
369 if (!tmp_compressed) {
d89c8fdf 370 log_oom();
b59233e6 371 goto uncompressed;
cfd652ed
ZJS
372 }
373
b59233e6
LP
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;
cfd652ed
ZJS
378 }
379
d89c8fdf 380 r = compress_stream(fd, fd_compressed, -1);
b59233e6 381 if (r < 0) {
da927ba9 382 log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
b59233e6
LP
383 goto fail_compressed;
384 }
385
386 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
cfd652ed 387 if (r < 0)
b59233e6
LP
388 goto fail_compressed;
389
390 /* OK, this worked, we can get rid of the uncompressed version now */
391 unlink_noerrno(tmp);
cfd652ed 392
b59233e6
LP
393 *ret_filename = fn_compressed; /* compressed */
394 *ret_fd = fd; /* uncompressed */
395 *ret_size = st.st_size; /* uncompressed */
cfd652ed 396
b59233e6 397 fn_compressed = NULL;
cfd652ed
ZJS
398 fd = -1;
399
400 return 0;
401
b59233e6
LP
402 fail_compressed:
403 unlink_noerrno(tmp_compressed);
34c10968 404 }
cfd652ed
ZJS
405
406uncompressed:
3b1a55e1 407#endif
cfd652ed
ZJS
408 r = fix_permissions(fd, tmp, fn, info, uid);
409 if (r < 0)
410 goto fail;
34c10968
LP
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
421fail:
422 unlink_noerrno(tmp);
423 return r;
424}
425
426static 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
8d4e028f 430 assert(fd >= 0);
34c10968
LP
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;
803a3464
LP
437 }
438
34c10968
LP
439 field = malloc(9 + size);
440 if (!field) {
cfd652ed 441 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
34c10968
LP
442 return -ENOMEM;
443 }
444
445 memcpy(field, "COREDUMP=", 9);
446
447 n = read(fd, field + 9, size);
448 if (n < 0) {
da927ba9 449 log_error_errno(n, "Failed to read core data: %m");
34c10968
LP
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}
803a3464 464
3f132692
JF
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 */
479static int compose_open_fds(pid_t pid, char **open_fds) {
480 _cleanup_fclose_ FILE *stream = NULL;
3f132692 481 size_t ignored_size;
59059b4a 482 const char *fddelim = "", *path;
3f132692
JF
483 struct dirent *dent = NULL;
484 _cleanup_closedir_ DIR *proc_fd_dir = NULL;
59059b4a 485 _cleanup_close_ int proc_fdinfo_fd = -1;
3f132692
JF
486 int r = 0;
487
488 assert(pid >= 0);
489 assert(open_fds != NULL);
490
59059b4a 491 path = procfs_file_alloca(pid, "fd");
3f132692 492 proc_fd_dir = opendir(path);
59059b4a
ZJS
493 if (!proc_fd_dir)
494 return -errno;
3f132692 495
59059b4a
ZJS
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;
3f132692
JF
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;
59059b4a 507 int fd;
3f132692 508 _cleanup_fclose_ FILE *fdinfo = NULL;
59059b4a 509 char line[LINE_MAX];
3f132692
JF
510
511 if (dent->d_name[0] == '.' || strcmp(dent->d_name, "..") == 0)
512 continue;
513
59059b4a 514 r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
3f132692
JF
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 */
59059b4a
ZJS
522 fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
523 if (fd < 0)
3f132692
JF
524 continue;
525
59059b4a
ZJS
526 fdinfo = fdopen(fd, "re");
527 if (fdinfo == NULL) {
528 close(fd);
3f132692 529 continue;
59059b4a 530 }
3f132692
JF
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
f5e04665 540int main(int argc, char* argv[]) {
34c10968
LP
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,
3f132692
JF
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,
9fe13294 548 *exe = NULL, *comm = NULL, *filename = NULL;
1eef15b1 549 const char *info[_INFO_LEN];
34c10968
LP
550
551 _cleanup_close_ int coredump_fd = -1;
552
3f132692 553 struct iovec iovec[26];
34c10968 554 off_t coredump_size;
f5e04665 555 int r, j = 0;
a035f819 556 uid_t uid, owner_uid;
fee80f69 557 gid_t gid;
a035f819 558 pid_t pid;
34c10968 559 char *t;
3f132692 560 const char *p;
f5e04665 561
34c10968 562 /* Make sure we never enter a loop */
803a3464 563 prctl(PR_SET_DUMPABLE, 0);
f5e04665 564
34c10968
LP
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);
34c10968 569 log_open();
803a3464 570
1eef15b1
ZJS
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);
f5e04665
LP
574 r = -EINVAL;
575 goto finish;
576 }
577
34c10968
LP
578 /* Ignore all parse errors */
579 parse_config();
8c9571d0
LP
580
581 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
582 log_debug("Selected compression %s.", yes_no(arg_compress));
34c10968 583
1eef15b1 584 r = parse_uid(argv[INFO_UID + 1], &uid);
f5e04665 585 if (r < 0) {
34c10968
LP
586 log_error("Failed to parse UID.");
587 goto finish;
588 }
803a3464 589
1eef15b1 590 r = parse_pid(argv[INFO_PID + 1], &pid);
34c10968 591 if (r < 0) {
f5e04665 592 log_error("Failed to parse PID.");
f5e04665
LP
593 goto finish;
594 }
595
1eef15b1 596 r = parse_gid(argv[INFO_GID + 1], &gid);
34c10968
LP
597 if (r < 0) {
598 log_error("Failed to parse GID.");
599 goto finish;
600 }
601
1eef15b1 602 if (get_process_comm(pid, &comm) < 0) {
3f85ef0f 603 log_warning("Failed to get COMM, falling back to the command line.");
1eef15b1
ZJS
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
ba1261bc 618 if (cg_pid_get_unit(pid, &t) >= 0) {
803a3464
LP
619
620 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
803a3464 621
34c10968
LP
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
9fe13294 629 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968
LP
630 if (r < 0)
631 goto finish;
632
9fe13294 633 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
634 if (r < 0)
635 goto finish;
636
9fe13294 637 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
803a3464
LP
638 goto finish;
639 }
640
641 core_unit = strappend("COREDUMP_UNIT=", t);
b7f7c685 642 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
f9045468 643 core_unit = strappend("COREDUMP_USER_UNIT=", t);
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
1eef15b1 653 core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
f5e04665
LP
654 if (core_pid)
655 IOVEC_SET_STRING(iovec[j++], core_pid);
656
1eef15b1 657 core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
f5e04665
LP
658 if (core_uid)
659 IOVEC_SET_STRING(iovec[j++], core_uid);
660
1eef15b1 661 core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
f5e04665
LP
662 if (core_gid)
663 IOVEC_SET_STRING(iovec[j++], core_gid);
664
1eef15b1 665 core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
f5e04665
LP
666 if (core_signal)
667 IOVEC_SET_STRING(iovec[j++], core_signal);
668
f5e04665
LP
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
a035f819 677 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
7de80bfe
KZ
678 r = asprintf(&core_owner_uid,
679 "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
680 if (r > 0)
a035f819
LP
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
1eef15b1
ZJS
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) {
8d4e028f 699 core_exe = strappend("COREDUMP_EXE=", exe);
f5e04665
LP
700 if (core_exe)
701 IOVEC_SET_STRING(iovec[j++], core_exe);
702 }
703
9bdbc2e2 704 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
f5e04665
LP
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
a035f819
LP
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
3f132692
JF
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
1eef15b1 788 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
f5e04665
LP
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
0dc5d23c
LP
795 /* Vacuum before we write anything again */
796 coredump_vacuum(-1, arg_keep_free, arg_max_use);
797
34c10968 798 /* Always stream the coredump to disk, if that's possible */
9fe13294 799 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968 800 if (r < 0)
2424a475
ZJS
801 /* skip whole core dumping part */
802 goto log;
34c10968
LP
803
804 /* If we don't want to keep the coredump on disk, remove it
8d4e028f
LP
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. */
9fe13294 808 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
809 if (r < 0)
810 goto finish;
9fe13294
ZJS
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 }
34c10968 817
0dc5d23c
LP
818 /* Vacuum again, but exclude the coredump we just created */
819 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
820
fee80f69
LP
821 /* Now, let's drop privileges to become the user who owns the
822 * segfaulted process and allocate the coredump memory under
b26c631a
KP
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. */
fee80f69
LP
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
8d4e028f
LP
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)
1eef15b1 840 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
4d229b31
UTL
841 else if (r == -EINVAL)
842 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
8d4e028f 843 else
da927ba9 844 log_warning_errno(r, "Failed to generate stack trace: %m");
8d4e028f
LP
845 }
846
847 if (!core_message)
848#endif
2424a475 849log:
1eef15b1 850 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
8d4e028f
LP
851 if (core_message)
852 IOVEC_SET_STRING(iovec[j++], core_message);
853
34c10968
LP
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;
fee80f69 858
34c10968 859 /* Store the coredump itself in the journal */
fee80f69 860
34c10968
LP
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++;
ca0ceb6f 866 }
fee80f69
LP
867 }
868
f5e04665
LP
869 r = sd_journal_sendv(iovec, j);
870 if (r < 0)
da927ba9 871 log_error_errno(r, "Failed to log coredump: %m");
f5e04665
LP
872
873finish:
f5e04665
LP
874 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
875}