]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
coredump: don't expose the compression level as configuration option
[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
52#ifdef HAVE_XZ
53# include <lzma.h>
54#else
55# define LZMA_PRESET_DEFAULT 0
34c10968
LP
56#endif
57
58/* The maximum size up to which we process coredumps */
59#define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
60
61/* The maximum size up to which we leave the coredump around on
62 * disk */
63#define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
64
65/* The maximum size up to which we store the coredump in the
66 * journal */
67#define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
f5e04665 68
c4aa09b0
LP
69/* Make sure to not make this larger than the maximum journal entry
70 * size. See ENTRY_SIZE_MAX in journald-native.c. */
34c10968 71assert_cc(JOURNAL_SIZE_MAX <= ENTRY_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);
34727273
ZJS
101static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage,
102 CoredumpStorage,
103 "Failed to parse storage setting");
104
105typedef enum CoredumpCompression {
106 COREDUMP_COMPRESSION_NONE,
107 COREDUMP_COMPRESSION_XZ,
108 _COREDUMP_COMPRESSION_MAX,
109 _COREDUMP_COMPRESSION_INVALID = -1
110} CoredumpCompression;
111
112static const char* const coredump_compression_table[_COREDUMP_COMPRESSION_MAX] = {
113 [COREDUMP_COMPRESSION_NONE] = "none",
114 [COREDUMP_COMPRESSION_XZ] = "xz",
115};
116
117DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_compression, CoredumpCompression);
118static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_compression, coredump_compression,
119 CoredumpCompression,
120 "Failed to parse compression setting");
121
122static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
123static CoredumpCompression arg_compression = COREDUMP_COMPRESSION_XZ;
34727273
ZJS
124static off_t arg_process_size_max = PROCESS_SIZE_MAX;
125static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
126static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
0dc5d23c
LP
127static off_t arg_keep_free = (off_t) -1;
128static off_t arg_max_use = (off_t) -1;
34c10968
LP
129
130static int parse_config(void) {
34c10968 131 static const ConfigTableItem items[] = {
34727273
ZJS
132 { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
133 { "Coredump", "Compression", config_parse_coredump_compression, 0, &arg_compression },
34727273
ZJS
134 { "Coredump", "ProcessSizeMax", config_parse_iec_off, 0, &arg_process_size_max },
135 { "Coredump", "ExternalSizeMax", config_parse_iec_off, 0, &arg_external_size_max },
136 { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
0dc5d23c
LP
137 { "Coredump", "KeepFree", config_parse_iec_off, 0, &arg_keep_free },
138 { "Coredump", "MaxUse", config_parse_iec_off, 0, &arg_max_use },
34c10968
LP
139 {}
140 };
141
cf677ac1 142 return config_parse(
34c10968
LP
143 NULL,
144 "/etc/systemd/coredump.conf",
145 NULL,
146 "Coredump\0",
147 config_item_table_lookup,
148 (void*) items,
149 false,
150 false,
151 NULL);
152}
153
154static int fix_acl(int fd, uid_t uid) {
155
156#ifdef HAVE_ACL
157 _cleanup_(acl_freep) acl_t acl = NULL;
158 acl_entry_t entry;
159 acl_permset_t permset;
160
161 if (uid <= SYSTEM_UID_MAX)
162 return 0;
163
164 /* Make sure normal users can read (but not write or delete)
165 * their own coredumps */
166
167 acl = acl_get_fd(fd);
168 if (!acl) {
169 log_error("Failed to get ACL: %m");
170 return -errno;
171 }
172
173 if (acl_create_entry(&acl, &entry) < 0 ||
174 acl_set_tag_type(entry, ACL_USER) < 0 ||
175 acl_set_qualifier(entry, &uid) < 0) {
176 log_error("Failed to patch ACL: %m");
177 return -errno;
178 }
179
180 if (acl_get_permset(entry, &permset) < 0 ||
181 acl_add_perm(permset, ACL_READ) < 0 ||
182 calc_acl_mask_if_needed(&acl) < 0) {
183 log_warning("Failed to patch ACL: %m");
184 return -errno;
185 }
186
187 if (acl_set_fd(fd, acl) < 0) {
188 log_error("Failed to apply ACL: %m");
189 return -errno;
190 }
191#endif
192
193 return 0;
194}
195
1eef15b1 196static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
0cd77f97 197
1eef15b1
ZJS
198 static const char * const xattrs[_INFO_LEN] = {
199 [INFO_PID] = "user.coredump.pid",
200 [INFO_UID] = "user.coredump.uid",
201 [INFO_GID] = "user.coredump.gid",
202 [INFO_SIGNAL] = "user.coredump.signal",
203 [INFO_TIMESTAMP] = "user.coredump.timestamp",
204 [INFO_COMM] = "user.coredump.comm",
205 [INFO_EXE] = "user.coredump.exe",
0cd77f97
LP
206 };
207
34c10968 208 int r = 0;
0cd77f97 209 unsigned i;
34c10968 210
1eef15b1 211 /* Attach some metadata to coredumps via extended
34c10968
LP
212 * attributes. Just because we can. */
213
1eef15b1
ZJS
214 for (i = 0; i < _INFO_LEN; i++) {
215 int k;
216
217 if (isempty(info[i]) || !xattrs[i])
0cd77f97 218 continue;
34c10968 219
1eef15b1
ZJS
220 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
221 if (k < 0 && r == 0)
34c10968 222 r = -errno;
0cd77f97 223 }
34c10968
LP
224
225 return r;
226}
227
b0b21dce 228#define filename_escape(s) xescape((s), "./ ")
34c10968 229
cfd652ed
ZJS
230static int fix_permissions(int fd, const char *filename, const char *target,
231 const char *info[_INFO_LEN], uid_t uid) {
232
233 /* Ignore errors on these */
234 fchmod(fd, 0640);
235 fix_acl(fd, uid);
236 fix_xattr(fd, info);
237
238 if (fsync(fd) < 0) {
239 log_error("Failed to sync coredump %s: %m", filename);
240 return -errno;
241 }
242
243 if (rename(filename, target) < 0) {
244 log_error("Failed to rename coredump %s -> %s: %m", filename, target);
245 return -errno;
246 }
247
248 return 0;
249}
250
251static int maybe_remove_external_coredump(const char *filename, off_t size) {
252
253 /* Returns 1 if might remove, 0 if will not remove, <0 on error. */
254
255 if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
256 size <= arg_external_size_max)
257 return 0;
258
259 if (!filename)
260 return 1;
261
9d951bf4 262 if (unlink(filename) < 0 && errno != ENOENT) {
cfd652ed
ZJS
263 log_error("Failed to unlink %s: %m", filename);
264 return -errno;
265 }
266
267 return 1;
268}
269
0dc5d23c
LP
270static int save_external_coredump(
271 const char *info[_INFO_LEN],
272 uid_t uid,
273 char **ret_filename,
274 int *ret_fd,
275 off_t *ret_size) {
cfd652ed 276
0dc5d23c 277 _cleanup_free_ char *p = NULL, *t = NULL, *c = NULL, *fn = NULL, *tmp = NULL, *u = NULL;
34c10968
LP
278 _cleanup_close_ int fd = -1;
279 sd_id128_t boot;
280 struct stat st;
281 int r;
282
1eef15b1 283 assert(info);
34c10968
LP
284 assert(ret_filename);
285 assert(ret_fd);
286 assert(ret_size);
287
1eef15b1 288 c = filename_escape(info[INFO_COMM]);
34c10968
LP
289 if (!c)
290 return log_oom();
291
1eef15b1 292 p = filename_escape(info[INFO_PID]);
34c10968
LP
293 if (!p)
294 return log_oom();
295
0dc5d23c
LP
296 u = filename_escape(info[INFO_UID]);
297 if (!u)
298 return log_oom();
299
1eef15b1 300 t = filename_escape(info[INFO_TIMESTAMP]);
34c10968
LP
301 if (!t)
302 return log_oom();
303
304 r = sd_id128_get_boot(&boot);
305 if (r < 0) {
306 log_error("Failed to determine boot ID: %s", strerror(-r));
307 return r;
308 }
309
310 r = asprintf(&fn,
0dc5d23c 311 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
34c10968 312 c,
0dc5d23c 313 u,
34c10968
LP
314 SD_ID128_FORMAT_VAL(boot),
315 p,
316 t);
317 if (r < 0)
318 return log_oom();
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
LP
332 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
333 if (r == -E2BIG) {
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) {
34c10968
LP
340 log_error("Failed to dump coredump to file: %s", strerror(-r));
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);
351 goto uncompressed;
352 }
353
cfd652ed
ZJS
354#ifdef HAVE_XZ
355 /* If we will remove the coredump anyway, do not compress. */
34727273
ZJS
356 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
357 && arg_compression == COREDUMP_COMPRESSION_XZ) {
cfd652ed
ZJS
358
359 _cleanup_free_ char *fn2 = NULL;
360 char *tmp2;
361 _cleanup_close_ int fd2 = -1;
362
363 tmp2 = strappenda(tmp, ".xz");
364 fd2 = open(tmp2, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
365 if (fd2 < 0) {
366 log_error("Failed to create file %s: %m", tmp2);
367 goto uncompressed;
368 }
369
cf677ac1 370 r = compress_stream(fd, fd2, LZMA_PRESET_DEFAULT, -1);
cfd652ed
ZJS
371 if (r < 0) {
372 log_error("Failed to compress %s: %s", tmp2, strerror(-r));
373 unlink_noerrno(tmp2);
374 goto fail2;
375 }
376
377 fn2 = strappend(fn, ".xz");
378 if (!fn2) {
379 log_oom();
380 goto fail2;
381 }
382
383 r = fix_permissions(fd2, tmp2, fn2, info, uid);
384 if (r < 0)
385 goto fail2;
386
387 *ret_filename = fn2; /* compressed */
388 *ret_fd = fd; /* uncompressed */
389 *ret_size = st.st_size; /* uncompressed */
390
391 fn2 = NULL;
392 fd = -1;
393
394 return 0;
395
396 fail2:
397 unlink_noerrno(tmp2);
34c10968 398 }
cfd652ed
ZJS
399#endif
400
401uncompressed:
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();
34727273
ZJS
496 log_debug("Selected storage '%s'.",
497 coredump_storage_to_string(arg_storage));
cf677ac1
LP
498 log_debug("Selected compression %s.",
499 coredump_compression_to_string(arg_compression));
34c10968 500
1eef15b1 501 r = parse_uid(argv[INFO_UID + 1], &uid);
f5e04665 502 if (r < 0) {
34c10968
LP
503 log_error("Failed to parse UID.");
504 goto finish;
505 }
803a3464 506
1eef15b1 507 r = parse_pid(argv[INFO_PID + 1], &pid);
34c10968 508 if (r < 0) {
f5e04665 509 log_error("Failed to parse PID.");
f5e04665
LP
510 goto finish;
511 }
512
1eef15b1 513 r = parse_gid(argv[INFO_GID + 1], &gid);
34c10968
LP
514 if (r < 0) {
515 log_error("Failed to parse GID.");
516 goto finish;
517 }
518
1eef15b1
ZJS
519 if (get_process_comm(pid, &comm) < 0) {
520 log_warning("Failed to get COMM, falling back to the commandline.");
521 comm = strv_join(argv + INFO_COMM + 1, " ");
522 }
523
524 if (get_process_exe(pid, &exe) < 0)
525 log_warning("Failed to get EXE.");
526
527 info[INFO_PID] = argv[INFO_PID + 1];
528 info[INFO_UID] = argv[INFO_UID + 1];
529 info[INFO_GID] = argv[INFO_GID + 1];
530 info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
531 info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
532 info[INFO_COMM] = comm;
533 info[INFO_EXE] = exe;
534
ba1261bc 535 if (cg_pid_get_unit(pid, &t) >= 0) {
803a3464
LP
536
537 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
803a3464 538
34c10968
LP
539 /* If we are journald, we cut things short,
540 * don't write to the journal, but still
541 * create a coredump. */
542
543 if (arg_storage != COREDUMP_STORAGE_NONE)
544 arg_storage = COREDUMP_STORAGE_EXTERNAL;
545
9fe13294 546 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968
LP
547 if (r < 0)
548 goto finish;
549
9fe13294 550 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
551 if (r < 0)
552 goto finish;
553
9fe13294 554 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
803a3464
LP
555 goto finish;
556 }
557
558 core_unit = strappend("COREDUMP_UNIT=", t);
b7f7c685 559 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
f9045468 560 core_unit = strappend("COREDUMP_USER_UNIT=", t);
803a3464 561
f9045468
MT
562 if (core_unit)
563 IOVEC_SET_STRING(iovec[j++], core_unit);
564
34c10968
LP
565 /* OK, now we know it's not the journal, hence we can make use
566 * of it now. */
803a3464
LP
567 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
568 log_open();
569
1eef15b1 570 core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
f5e04665
LP
571 if (core_pid)
572 IOVEC_SET_STRING(iovec[j++], core_pid);
573
1eef15b1 574 core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
f5e04665
LP
575 if (core_uid)
576 IOVEC_SET_STRING(iovec[j++], core_uid);
577
1eef15b1 578 core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
f5e04665
LP
579 if (core_gid)
580 IOVEC_SET_STRING(iovec[j++], core_gid);
581
1eef15b1 582 core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
f5e04665
LP
583 if (core_signal)
584 IOVEC_SET_STRING(iovec[j++], core_signal);
585
f5e04665
LP
586 if (sd_pid_get_session(pid, &t) >= 0) {
587 core_session = strappend("COREDUMP_SESSION=", t);
588 free(t);
589
590 if (core_session)
591 IOVEC_SET_STRING(iovec[j++], core_session);
592 }
593
a035f819
LP
594 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
595 asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
596
597 if (core_owner_uid)
598 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
599 }
600
601 if (sd_pid_get_slice(pid, &t) >= 0) {
602 core_slice = strappend("COREDUMP_SLICE=", t);
603 free(t);
604
605 if (core_slice)
606 IOVEC_SET_STRING(iovec[j++], core_slice);
607 }
608
1eef15b1
ZJS
609 if (comm) {
610 core_comm = strappend("COREDUMP_COMM=", comm);
611 if (core_comm)
612 IOVEC_SET_STRING(iovec[j++], core_comm);
613 }
614
615 if (exe) {
8d4e028f 616 core_exe = strappend("COREDUMP_EXE=", exe);
f5e04665
LP
617 if (core_exe)
618 IOVEC_SET_STRING(iovec[j++], core_exe);
619 }
620
9bdbc2e2 621 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
f5e04665
LP
622 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
623 free(t);
624
625 if (core_cmdline)
626 IOVEC_SET_STRING(iovec[j++], core_cmdline);
627 }
628
a035f819
LP
629 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
630 core_cgroup = strappend("COREDUMP_CGROUP=", t);
631 free(t);
632
633 if (core_cgroup)
634 IOVEC_SET_STRING(iovec[j++], core_cgroup);
635 }
636
1eef15b1 637 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
f5e04665
LP
638 if (core_timestamp)
639 IOVEC_SET_STRING(iovec[j++], core_timestamp);
640
641 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
642 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
643
0dc5d23c
LP
644 /* Vacuum before we write anything again */
645 coredump_vacuum(-1, arg_keep_free, arg_max_use);
646
34c10968 647 /* Always stream the coredump to disk, if that's possible */
9fe13294 648 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968 649 if (r < 0)
2424a475
ZJS
650 /* skip whole core dumping part */
651 goto log;
34c10968
LP
652
653 /* If we don't want to keep the coredump on disk, remove it
8d4e028f
LP
654 * now, as later on we will lack the privileges for
655 * it. However, we keep the fd to it, so that we can still
656 * process it and log it. */
9fe13294 657 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
658 if (r < 0)
659 goto finish;
9fe13294
ZJS
660 if (r == 0) {
661 const char *coredump_filename;
662
663 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
664 IOVEC_SET_STRING(iovec[j++], coredump_filename);
665 }
34c10968 666
0dc5d23c
LP
667 /* Vacuum again, but exclude the coredump we just created */
668 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
669
fee80f69
LP
670 /* Now, let's drop privileges to become the user who owns the
671 * segfaulted process and allocate the coredump memory under
672 * his uid. This also ensures that the credentials journald
673 * will see are the ones of the coredumping user, thus making
674 * sure the user himself gets access to the core dump. */
fee80f69
LP
675 if (setresgid(gid, gid, gid) < 0 ||
676 setresuid(uid, uid, uid) < 0) {
677 log_error("Failed to drop privileges: %m");
678 r = -errno;
679 goto finish;
680 }
681
8d4e028f
LP
682#ifdef HAVE_ELFUTILS
683 /* Try to get a strack trace if we can */
684 if (coredump_size <= arg_process_size_max) {
685 _cleanup_free_ char *stacktrace = NULL;
686
687 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
688 if (r >= 0)
1eef15b1 689 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
8d4e028f
LP
690 else
691 log_warning("Failed to generate stack trace: %s", strerror(-r));
692 }
693
694 if (!core_message)
695#endif
2424a475 696log:
1eef15b1 697 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
8d4e028f
LP
698 if (core_message)
699 IOVEC_SET_STRING(iovec[j++], core_message);
700
34c10968
LP
701 /* Optionally store the entire coredump in the journal */
702 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
703 coredump_size <= (off_t) arg_journal_size_max) {
704 size_t sz;
fee80f69 705
34c10968 706 /* Store the coredump itself in the journal */
fee80f69 707
34c10968
LP
708 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
709 if (r >= 0) {
710 iovec[j].iov_base = coredump_data;
711 iovec[j].iov_len = sz;
712 j++;
ca0ceb6f 713 }
fee80f69
LP
714 }
715
f5e04665
LP
716 r = sd_journal_sendv(iovec, j);
717 if (r < 0)
872c8faa 718 log_error("Failed to log coredump: %s", strerror(-r));
f5e04665
LP
719
720finish:
f5e04665
LP
721 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
722}