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