]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
shell-completion: prevent mangling unit names
[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
LP
28
29#include <systemd/sd-journal.h>
30#include <systemd/sd-login.h>
31
32#include "log.h"
33#include "util.h"
1eef15b1 34#include "strv.h"
b7f7c685 35#include "macro.h"
49e942b2 36#include "mkdir.h"
803a3464 37#include "special.h"
ba1261bc 38#include "cgroup-util.h"
d18d46ec 39#include "journald-native.h"
34c10968
LP
40#include "conf-parser.h"
41#include "copy.h"
8d4e028f 42#include "stacktrace.h"
6388c315 43#include "path-util.h"
cfd652ed 44#include "compress.h"
0dc5d23c 45#include "coredump-vacuum.h"
34c10968
LP
46
47#ifdef HAVE_ACL
34727273
ZJS
48# include <sys/acl.h>
49# include "acl-util.h"
50#endif
51
34c10968
LP
52/* The maximum size up to which we process coredumps */
53#define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
54
55/* The maximum size up to which we leave the coredump around on
56 * disk */
57#define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
58
59/* The maximum size up to which we store the coredump in the
60 * journal */
61#define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
f5e04665 62
c4aa09b0 63/* Make sure to not make this larger than the maximum journal entry
874bc134
ZJS
64 * size. See DATA_SIZE_MAX in journald-native.c. */
65assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
f5e04665
LP
66
67enum {
1eef15b1
ZJS
68 INFO_PID,
69 INFO_UID,
70 INFO_GID,
71 INFO_SIGNAL,
72 INFO_TIMESTAMP,
73 INFO_COMM,
74 INFO_EXE,
75 _INFO_LEN
f5e04665
LP
76};
77
34c10968
LP
78typedef enum CoredumpStorage {
79 COREDUMP_STORAGE_NONE,
80 COREDUMP_STORAGE_EXTERNAL,
81 COREDUMP_STORAGE_JOURNAL,
82 COREDUMP_STORAGE_BOTH,
83 _COREDUMP_STORAGE_MAX,
84 _COREDUMP_STORAGE_INVALID = -1
85} CoredumpStorage;
86
34c10968
LP
87static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
88 [COREDUMP_STORAGE_NONE] = "none",
89 [COREDUMP_STORAGE_EXTERNAL] = "external",
90 [COREDUMP_STORAGE_JOURNAL] = "journal",
91 [COREDUMP_STORAGE_BOTH] = "both",
92};
93
94DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
8c9571d0 95static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
34727273
ZJS
96
97static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
8c9571d0 98static bool arg_compress = true;
34727273
ZJS
99static off_t arg_process_size_max = PROCESS_SIZE_MAX;
100static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
101static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
0dc5d23c
LP
102static off_t arg_keep_free = (off_t) -1;
103static off_t arg_max_use = (off_t) -1;
34c10968
LP
104
105static int parse_config(void) {
34c10968 106 static const ConfigTableItem items[] = {
8c9571d0
LP
107 { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
108 { "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
109 { "Coredump", "ProcessSizeMax", config_parse_iec_off, 0, &arg_process_size_max },
110 { "Coredump", "ExternalSizeMax", config_parse_iec_off, 0, &arg_external_size_max },
111 { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
112 { "Coredump", "KeepFree", config_parse_iec_off, 0, &arg_keep_free },
113 { "Coredump", "MaxUse", config_parse_iec_off, 0, &arg_max_use },
34c10968
LP
114 {}
115 };
116
36f822c4
ZJS
117 return config_parse(NULL, "/etc/systemd/coredump.conf", NULL,
118 "Coredump\0",
119 config_item_table_lookup, items,
120 false, false, true, NULL);
34c10968
LP
121}
122
123static int fix_acl(int fd, uid_t uid) {
124
125#ifdef HAVE_ACL
126 _cleanup_(acl_freep) acl_t acl = NULL;
127 acl_entry_t entry;
128 acl_permset_t permset;
129
b59233e6
LP
130 assert(fd >= 0);
131
34c10968
LP
132 if (uid <= SYSTEM_UID_MAX)
133 return 0;
134
135 /* Make sure normal users can read (but not write or delete)
136 * their own coredumps */
137
138 acl = acl_get_fd(fd);
139 if (!acl) {
140 log_error("Failed to get ACL: %m");
141 return -errno;
142 }
143
144 if (acl_create_entry(&acl, &entry) < 0 ||
145 acl_set_tag_type(entry, ACL_USER) < 0 ||
146 acl_set_qualifier(entry, &uid) < 0) {
147 log_error("Failed to patch ACL: %m");
148 return -errno;
149 }
150
151 if (acl_get_permset(entry, &permset) < 0 ||
152 acl_add_perm(permset, ACL_READ) < 0 ||
153 calc_acl_mask_if_needed(&acl) < 0) {
154 log_warning("Failed to patch ACL: %m");
155 return -errno;
156 }
157
158 if (acl_set_fd(fd, acl) < 0) {
159 log_error("Failed to apply ACL: %m");
160 return -errno;
161 }
162#endif
163
164 return 0;
165}
166
1eef15b1 167static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
0cd77f97 168
1eef15b1
ZJS
169 static const char * const xattrs[_INFO_LEN] = {
170 [INFO_PID] = "user.coredump.pid",
171 [INFO_UID] = "user.coredump.uid",
172 [INFO_GID] = "user.coredump.gid",
173 [INFO_SIGNAL] = "user.coredump.signal",
174 [INFO_TIMESTAMP] = "user.coredump.timestamp",
175 [INFO_COMM] = "user.coredump.comm",
176 [INFO_EXE] = "user.coredump.exe",
0cd77f97
LP
177 };
178
34c10968 179 int r = 0;
0cd77f97 180 unsigned i;
34c10968 181
b59233e6
LP
182 assert(fd >= 0);
183
1eef15b1 184 /* Attach some metadata to coredumps via extended
34c10968
LP
185 * attributes. Just because we can. */
186
1eef15b1
ZJS
187 for (i = 0; i < _INFO_LEN; i++) {
188 int k;
189
190 if (isempty(info[i]) || !xattrs[i])
0cd77f97 191 continue;
34c10968 192
1eef15b1
ZJS
193 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
194 if (k < 0 && r == 0)
34c10968 195 r = -errno;
0cd77f97 196 }
34c10968
LP
197
198 return r;
199}
200
b0b21dce 201#define filename_escape(s) xescape((s), "./ ")
34c10968 202
b59233e6
LP
203static int fix_permissions(
204 int fd,
205 const char *filename,
206 const char *target,
207 const char *info[_INFO_LEN],
208 uid_t uid) {
209
210 assert(fd >= 0);
211 assert(filename);
212 assert(target);
213 assert(info);
cfd652ed
ZJS
214
215 /* Ignore errors on these */
216 fchmod(fd, 0640);
217 fix_acl(fd, uid);
218 fix_xattr(fd, info);
219
220 if (fsync(fd) < 0) {
221 log_error("Failed to sync coredump %s: %m", filename);
222 return -errno;
223 }
224
225 if (rename(filename, target) < 0) {
226 log_error("Failed to rename coredump %s -> %s: %m", filename, target);
227 return -errno;
228 }
229
230 return 0;
231}
232
233static int maybe_remove_external_coredump(const char *filename, off_t size) {
234
b59233e6 235 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
cfd652ed
ZJS
236
237 if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
238 size <= arg_external_size_max)
239 return 0;
240
241 if (!filename)
242 return 1;
243
9d951bf4 244 if (unlink(filename) < 0 && errno != ENOENT) {
cfd652ed
ZJS
245 log_error("Failed to unlink %s: %m", filename);
246 return -errno;
247 }
248
249 return 1;
250}
251
b59233e6
LP
252static int make_filename(const char *info[_INFO_LEN], char **ret) {
253 _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
34c10968 254 sd_id128_t boot;
34c10968
LP
255 int r;
256
1eef15b1 257 assert(info);
34c10968 258
1eef15b1 259 c = filename_escape(info[INFO_COMM]);
34c10968 260 if (!c)
b59233e6 261 return -ENOMEM;
34c10968 262
0dc5d23c
LP
263 u = filename_escape(info[INFO_UID]);
264 if (!u)
b59233e6 265 return -ENOMEM;
34c10968
LP
266
267 r = sd_id128_get_boot(&boot);
b59233e6 268 if (r < 0)
34c10968 269 return r;
34c10968 270
b59233e6
LP
271 p = filename_escape(info[INFO_PID]);
272 if (!p)
273 return -ENOMEM;
274
275 t = filename_escape(info[INFO_TIMESTAMP]);
276 if (!t)
277 return -ENOMEM;
278
279 if (asprintf(ret,
0dc5d23c 280 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
34c10968 281 c,
0dc5d23c 282 u,
34c10968
LP
283 SD_ID128_FORMAT_VAL(boot),
284 p,
b59233e6
LP
285 t) < 0)
286 return -ENOMEM;
287
288 return 0;
289}
290
291static int save_external_coredump(
292 const char *info[_INFO_LEN],
293 uid_t uid,
294 char **ret_filename,
295 int *ret_fd,
296 off_t *ret_size) {
297
298 _cleanup_free_ char *fn = NULL, *tmp = NULL;
299 _cleanup_close_ int fd = -1;
300 struct stat st;
301 int r;
302
303 assert(info);
304 assert(ret_filename);
305 assert(ret_fd);
306 assert(ret_size);
307
308 r = make_filename(info, &fn);
309 if (r < 0) {
310 log_error("Failed to determine coredump file name: %s", strerror(-r));
311 return r;
312 }
34c10968
LP
313
314 tmp = tempfn_random(fn);
315 if (!tmp)
316 return log_oom();
803a3464 317
d2e54fae 318 mkdir_p_label("/var/lib/systemd/coredump", 0755);
803a3464 319
34c10968
LP
320 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
321 if (fd < 0) {
cfd652ed 322 log_error("Failed to create coredump file %s: %m", tmp);
803a3464
LP
323 return -errno;
324 }
325
93240d3a
LP
326 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
327 if (r == -E2BIG) {
0dc5d23c 328 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
329 goto fail;
330 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
0dc5d23c 331 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
332 goto fail;
333 } else if (r < 0) {
34c10968
LP
334 log_error("Failed to dump coredump to file: %s", strerror(-r));
335 goto fail;
336 }
803a3464 337
34c10968 338 if (fstat(fd, &st) < 0) {
1eef15b1 339 log_error("Failed to fstat coredump %s: %m", tmp);
34c10968
LP
340 goto fail;
341 }
342
7849c2ac
TA
343 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
344 log_error("Failed to seek on %s: %m", tmp);
b59233e6 345 goto fail;
7849c2ac
TA
346 }
347
d89c8fdf 348#if defined(HAVE_XZ) || defined(HAVE_LZ4)
cfd652ed 349 /* If we will remove the coredump anyway, do not compress. */
34727273 350 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
8c9571d0 351 && arg_compress) {
cfd652ed 352
b59233e6
LP
353 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
354 _cleanup_close_ int fd_compressed = -1;
cfd652ed 355
d89c8fdf 356 fn_compressed = strappend(fn, COMPRESSED_EXT);
b59233e6 357 if (!fn_compressed) {
d89c8fdf 358 log_oom();
cfd652ed
ZJS
359 goto uncompressed;
360 }
361
b59233e6
LP
362 tmp_compressed = tempfn_random(fn_compressed);
363 if (!tmp_compressed) {
d89c8fdf 364 log_oom();
b59233e6 365 goto uncompressed;
cfd652ed
ZJS
366 }
367
b59233e6
LP
368 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
369 if (fd_compressed < 0) {
370 log_error("Failed to create file %s: %m", tmp_compressed);
371 goto uncompressed;
cfd652ed
ZJS
372 }
373
d89c8fdf 374 r = compress_stream(fd, fd_compressed, -1);
b59233e6
LP
375 if (r < 0) {
376 log_error("Failed to compress %s: %s", tmp_compressed, strerror(-r));
377 goto fail_compressed;
378 }
379
380 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
cfd652ed 381 if (r < 0)
b59233e6
LP
382 goto fail_compressed;
383
384 /* OK, this worked, we can get rid of the uncompressed version now */
385 unlink_noerrno(tmp);
cfd652ed 386
b59233e6
LP
387 *ret_filename = fn_compressed; /* compressed */
388 *ret_fd = fd; /* uncompressed */
389 *ret_size = st.st_size; /* uncompressed */
cfd652ed 390
b59233e6 391 fn_compressed = NULL;
cfd652ed
ZJS
392 fd = -1;
393
394 return 0;
395
b59233e6
LP
396 fail_compressed:
397 unlink_noerrno(tmp_compressed);
34c10968 398 }
cfd652ed
ZJS
399
400uncompressed:
3b1a55e1 401#endif
cfd652ed
ZJS
402 r = fix_permissions(fd, tmp, fn, info, uid);
403 if (r < 0)
404 goto fail;
34c10968
LP
405
406 *ret_filename = fn;
407 *ret_fd = fd;
408 *ret_size = st.st_size;
409
410 fn = NULL;
411 fd = -1;
412
413 return 0;
414
415fail:
416 unlink_noerrno(tmp);
417 return r;
418}
419
420static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
421 _cleanup_free_ char *field = NULL;
422 ssize_t n;
423
8d4e028f 424 assert(fd >= 0);
34c10968
LP
425 assert(ret);
426 assert(ret_size);
427
428 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
429 log_warning("Failed to seek: %m");
430 return -errno;
803a3464
LP
431 }
432
34c10968
LP
433 field = malloc(9 + size);
434 if (!field) {
cfd652ed 435 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
34c10968
LP
436 return -ENOMEM;
437 }
438
439 memcpy(field, "COREDUMP=", 9);
440
441 n = read(fd, field + 9, size);
442 if (n < 0) {
443 log_error("Failed to read core data: %s", strerror(-n));
444 return (int) n;
445 }
446 if ((size_t) n < size) {
447 log_error("Core data too short.");
448 return -EIO;
449 }
450
451 *ret = field;
452 *ret_size = size + 9;
453
454 field = NULL;
455
456 return 0;
457}
803a3464 458
f5e04665 459int main(int argc, char* argv[]) {
34c10968
LP
460
461 _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
462 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
463 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
9fe13294
ZJS
464 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
465 *exe = NULL, *comm = NULL, *filename = NULL;
1eef15b1 466 const char *info[_INFO_LEN];
34c10968
LP
467
468 _cleanup_close_ int coredump_fd = -1;
469
9fe13294 470 struct iovec iovec[18];
34c10968 471 off_t coredump_size;
f5e04665 472 int r, j = 0;
a035f819 473 uid_t uid, owner_uid;
fee80f69 474 gid_t gid;
a035f819 475 pid_t pid;
34c10968 476 char *t;
f5e04665 477
34c10968 478 /* Make sure we never enter a loop */
803a3464 479 prctl(PR_SET_DUMPABLE, 0);
f5e04665 480
34c10968
LP
481 /* First, log to a safe place, since we don't know what
482 * crashed and it might be journald which we'd rather not log
483 * to then. */
484 log_set_target(LOG_TARGET_KMSG);
34c10968 485 log_open();
803a3464 486
1eef15b1
ZJS
487 if (argc < INFO_COMM + 1) {
488 log_error("Not enough arguments passed from kernel (%d, expected %d).",
489 argc - 1, INFO_COMM + 1 - 1);
f5e04665
LP
490 r = -EINVAL;
491 goto finish;
492 }
493
34c10968
LP
494 /* Ignore all parse errors */
495 parse_config();
8c9571d0
LP
496
497 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
498 log_debug("Selected compression %s.", yes_no(arg_compress));
34c10968 499
1eef15b1 500 r = parse_uid(argv[INFO_UID + 1], &uid);
f5e04665 501 if (r < 0) {
34c10968
LP
502 log_error("Failed to parse UID.");
503 goto finish;
504 }
803a3464 505
1eef15b1 506 r = parse_pid(argv[INFO_PID + 1], &pid);
34c10968 507 if (r < 0) {
f5e04665 508 log_error("Failed to parse PID.");
f5e04665
LP
509 goto finish;
510 }
511
1eef15b1 512 r = parse_gid(argv[INFO_GID + 1], &gid);
34c10968
LP
513 if (r < 0) {
514 log_error("Failed to parse GID.");
515 goto finish;
516 }
517
1eef15b1
ZJS
518 if (get_process_comm(pid, &comm) < 0) {
519 log_warning("Failed to get COMM, falling back to the commandline.");
520 comm = strv_join(argv + INFO_COMM + 1, " ");
521 }
522
523 if (get_process_exe(pid, &exe) < 0)
524 log_warning("Failed to get EXE.");
525
526 info[INFO_PID] = argv[INFO_PID + 1];
527 info[INFO_UID] = argv[INFO_UID + 1];
528 info[INFO_GID] = argv[INFO_GID + 1];
529 info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
530 info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
531 info[INFO_COMM] = comm;
532 info[INFO_EXE] = exe;
533
ba1261bc 534 if (cg_pid_get_unit(pid, &t) >= 0) {
803a3464
LP
535
536 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
803a3464 537
34c10968
LP
538 /* If we are journald, we cut things short,
539 * don't write to the journal, but still
540 * create a coredump. */
541
542 if (arg_storage != COREDUMP_STORAGE_NONE)
543 arg_storage = COREDUMP_STORAGE_EXTERNAL;
544
9fe13294 545 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968
LP
546 if (r < 0)
547 goto finish;
548
9fe13294 549 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
550 if (r < 0)
551 goto finish;
552
9fe13294 553 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
803a3464
LP
554 goto finish;
555 }
556
557 core_unit = strappend("COREDUMP_UNIT=", t);
b7f7c685 558 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
f9045468 559 core_unit = strappend("COREDUMP_USER_UNIT=", t);
803a3464 560
f9045468
MT
561 if (core_unit)
562 IOVEC_SET_STRING(iovec[j++], core_unit);
563
34c10968
LP
564 /* OK, now we know it's not the journal, hence we can make use
565 * of it now. */
803a3464
LP
566 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
567 log_open();
568
1eef15b1 569 core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
f5e04665
LP
570 if (core_pid)
571 IOVEC_SET_STRING(iovec[j++], core_pid);
572
1eef15b1 573 core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
f5e04665
LP
574 if (core_uid)
575 IOVEC_SET_STRING(iovec[j++], core_uid);
576
1eef15b1 577 core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
f5e04665
LP
578 if (core_gid)
579 IOVEC_SET_STRING(iovec[j++], core_gid);
580
1eef15b1 581 core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
f5e04665
LP
582 if (core_signal)
583 IOVEC_SET_STRING(iovec[j++], core_signal);
584
f5e04665
LP
585 if (sd_pid_get_session(pid, &t) >= 0) {
586 core_session = strappend("COREDUMP_SESSION=", t);
587 free(t);
588
589 if (core_session)
590 IOVEC_SET_STRING(iovec[j++], core_session);
591 }
592
a035f819
LP
593 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
594 asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
595
596 if (core_owner_uid)
597 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
598 }
599
600 if (sd_pid_get_slice(pid, &t) >= 0) {
601 core_slice = strappend("COREDUMP_SLICE=", t);
602 free(t);
603
604 if (core_slice)
605 IOVEC_SET_STRING(iovec[j++], core_slice);
606 }
607
1eef15b1
ZJS
608 if (comm) {
609 core_comm = strappend("COREDUMP_COMM=", comm);
610 if (core_comm)
611 IOVEC_SET_STRING(iovec[j++], core_comm);
612 }
613
614 if (exe) {
8d4e028f 615 core_exe = strappend("COREDUMP_EXE=", exe);
f5e04665
LP
616 if (core_exe)
617 IOVEC_SET_STRING(iovec[j++], core_exe);
618 }
619
9bdbc2e2 620 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
f5e04665
LP
621 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
622 free(t);
623
624 if (core_cmdline)
625 IOVEC_SET_STRING(iovec[j++], core_cmdline);
626 }
627
a035f819
LP
628 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
629 core_cgroup = strappend("COREDUMP_CGROUP=", t);
630 free(t);
631
632 if (core_cgroup)
633 IOVEC_SET_STRING(iovec[j++], core_cgroup);
634 }
635
1eef15b1 636 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
f5e04665
LP
637 if (core_timestamp)
638 IOVEC_SET_STRING(iovec[j++], core_timestamp);
639
640 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
641 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
642
0dc5d23c
LP
643 /* Vacuum before we write anything again */
644 coredump_vacuum(-1, arg_keep_free, arg_max_use);
645
34c10968 646 /* Always stream the coredump to disk, if that's possible */
9fe13294 647 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968 648 if (r < 0)
2424a475
ZJS
649 /* skip whole core dumping part */
650 goto log;
34c10968
LP
651
652 /* If we don't want to keep the coredump on disk, remove it
8d4e028f
LP
653 * now, as later on we will lack the privileges for
654 * it. However, we keep the fd to it, so that we can still
655 * process it and log it. */
9fe13294 656 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
657 if (r < 0)
658 goto finish;
9fe13294
ZJS
659 if (r == 0) {
660 const char *coredump_filename;
661
662 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
663 IOVEC_SET_STRING(iovec[j++], coredump_filename);
664 }
34c10968 665
0dc5d23c
LP
666 /* Vacuum again, but exclude the coredump we just created */
667 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
668
fee80f69
LP
669 /* Now, let's drop privileges to become the user who owns the
670 * segfaulted process and allocate the coredump memory under
671 * his uid. This also ensures that the credentials journald
672 * will see are the ones of the coredumping user, thus making
673 * sure the user himself gets access to the core dump. */
fee80f69
LP
674 if (setresgid(gid, gid, gid) < 0 ||
675 setresuid(uid, uid, uid) < 0) {
676 log_error("Failed to drop privileges: %m");
677 r = -errno;
678 goto finish;
679 }
680
8d4e028f
LP
681#ifdef HAVE_ELFUTILS
682 /* Try to get a strack trace if we can */
683 if (coredump_size <= arg_process_size_max) {
684 _cleanup_free_ char *stacktrace = NULL;
685
686 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
687 if (r >= 0)
1eef15b1 688 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
8d4e028f
LP
689 else
690 log_warning("Failed to generate stack trace: %s", strerror(-r));
691 }
692
693 if (!core_message)
694#endif
2424a475 695log:
1eef15b1 696 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
8d4e028f
LP
697 if (core_message)
698 IOVEC_SET_STRING(iovec[j++], core_message);
699
34c10968
LP
700 /* Optionally store the entire coredump in the journal */
701 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
702 coredump_size <= (off_t) arg_journal_size_max) {
703 size_t sz;
fee80f69 704
34c10968 705 /* Store the coredump itself in the journal */
fee80f69 706
34c10968
LP
707 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
708 if (r >= 0) {
709 iovec[j].iov_base = coredump_data;
710 iovec[j].iov_len = sz;
711 j++;
ca0ceb6f 712 }
fee80f69
LP
713 }
714
f5e04665
LP
715 r = sd_journal_sendv(iovec, j);
716 if (r < 0)
872c8faa 717 log_error("Failed to log coredump: %s", strerror(-r));
f5e04665
LP
718
719finish:
f5e04665
LP
720 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
721}