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