]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
µhttp-util: fix compilation without gnutls
[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
LP
63/* Make sure to not make this larger than the maximum journal entry
64 * size. See ENTRY_SIZE_MAX in journald-native.c. */
34c10968 65assert_cc(JOURNAL_SIZE_MAX <= ENTRY_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
cf677ac1 117 return config_parse(
34c10968
LP
118 NULL,
119 "/etc/systemd/coredump.conf",
120 NULL,
121 "Coredump\0",
122 config_item_table_lookup,
e9f3d2d5 123 items,
34c10968
LP
124 false,
125 false,
126 NULL);
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) {
316 log_error("Failed to determine coredump file name: %s", strerror(-r));
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
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);
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
LP
381 if (r < 0) {
382 log_error("Failed to compress %s: %s", tmp_compressed, strerror(-r));
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) {
449 log_error("Failed to read core data: %s", strerror(-n));
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
f5e04665 465int main(int argc, char* argv[]) {
34c10968
LP
466
467 _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
468 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
469 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
9fe13294
ZJS
470 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
471 *exe = NULL, *comm = NULL, *filename = NULL;
1eef15b1 472 const char *info[_INFO_LEN];
34c10968
LP
473
474 _cleanup_close_ int coredump_fd = -1;
475
9fe13294 476 struct iovec iovec[18];
34c10968 477 off_t coredump_size;
f5e04665 478 int r, j = 0;
a035f819 479 uid_t uid, owner_uid;
fee80f69 480 gid_t gid;
a035f819 481 pid_t pid;
34c10968 482 char *t;
f5e04665 483
34c10968 484 /* Make sure we never enter a loop */
803a3464 485 prctl(PR_SET_DUMPABLE, 0);
f5e04665 486
34c10968
LP
487 /* First, log to a safe place, since we don't know what
488 * crashed and it might be journald which we'd rather not log
489 * to then. */
490 log_set_target(LOG_TARGET_KMSG);
34c10968 491 log_open();
803a3464 492
1eef15b1
ZJS
493 if (argc < INFO_COMM + 1) {
494 log_error("Not enough arguments passed from kernel (%d, expected %d).",
495 argc - 1, INFO_COMM + 1 - 1);
f5e04665
LP
496 r = -EINVAL;
497 goto finish;
498 }
499
34c10968
LP
500 /* Ignore all parse errors */
501 parse_config();
8c9571d0
LP
502
503 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
504 log_debug("Selected compression %s.", yes_no(arg_compress));
34c10968 505
1eef15b1 506 r = parse_uid(argv[INFO_UID + 1], &uid);
f5e04665 507 if (r < 0) {
34c10968
LP
508 log_error("Failed to parse UID.");
509 goto finish;
510 }
803a3464 511
1eef15b1 512 r = parse_pid(argv[INFO_PID + 1], &pid);
34c10968 513 if (r < 0) {
f5e04665 514 log_error("Failed to parse PID.");
f5e04665
LP
515 goto finish;
516 }
517
1eef15b1 518 r = parse_gid(argv[INFO_GID + 1], &gid);
34c10968
LP
519 if (r < 0) {
520 log_error("Failed to parse GID.");
521 goto finish;
522 }
523
1eef15b1
ZJS
524 if (get_process_comm(pid, &comm) < 0) {
525 log_warning("Failed to get COMM, falling back to the commandline.");
526 comm = strv_join(argv + INFO_COMM + 1, " ");
527 }
528
529 if (get_process_exe(pid, &exe) < 0)
530 log_warning("Failed to get EXE.");
531
532 info[INFO_PID] = argv[INFO_PID + 1];
533 info[INFO_UID] = argv[INFO_UID + 1];
534 info[INFO_GID] = argv[INFO_GID + 1];
535 info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
536 info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
537 info[INFO_COMM] = comm;
538 info[INFO_EXE] = exe;
539
ba1261bc 540 if (cg_pid_get_unit(pid, &t) >= 0) {
803a3464
LP
541
542 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
803a3464 543
34c10968
LP
544 /* If we are journald, we cut things short,
545 * don't write to the journal, but still
546 * create a coredump. */
547
548 if (arg_storage != COREDUMP_STORAGE_NONE)
549 arg_storage = COREDUMP_STORAGE_EXTERNAL;
550
9fe13294 551 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968
LP
552 if (r < 0)
553 goto finish;
554
9fe13294 555 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
556 if (r < 0)
557 goto finish;
558
9fe13294 559 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
803a3464
LP
560 goto finish;
561 }
562
563 core_unit = strappend("COREDUMP_UNIT=", t);
b7f7c685 564 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
f9045468 565 core_unit = strappend("COREDUMP_USER_UNIT=", t);
803a3464 566
f9045468
MT
567 if (core_unit)
568 IOVEC_SET_STRING(iovec[j++], core_unit);
569
34c10968
LP
570 /* OK, now we know it's not the journal, hence we can make use
571 * of it now. */
803a3464
LP
572 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
573 log_open();
574
1eef15b1 575 core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
f5e04665
LP
576 if (core_pid)
577 IOVEC_SET_STRING(iovec[j++], core_pid);
578
1eef15b1 579 core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
f5e04665
LP
580 if (core_uid)
581 IOVEC_SET_STRING(iovec[j++], core_uid);
582
1eef15b1 583 core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
f5e04665
LP
584 if (core_gid)
585 IOVEC_SET_STRING(iovec[j++], core_gid);
586
1eef15b1 587 core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
f5e04665
LP
588 if (core_signal)
589 IOVEC_SET_STRING(iovec[j++], core_signal);
590
f5e04665
LP
591 if (sd_pid_get_session(pid, &t) >= 0) {
592 core_session = strappend("COREDUMP_SESSION=", t);
593 free(t);
594
595 if (core_session)
596 IOVEC_SET_STRING(iovec[j++], core_session);
597 }
598
a035f819
LP
599 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
600 asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
601
602 if (core_owner_uid)
603 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
604 }
605
606 if (sd_pid_get_slice(pid, &t) >= 0) {
607 core_slice = strappend("COREDUMP_SLICE=", t);
608 free(t);
609
610 if (core_slice)
611 IOVEC_SET_STRING(iovec[j++], core_slice);
612 }
613
1eef15b1
ZJS
614 if (comm) {
615 core_comm = strappend("COREDUMP_COMM=", comm);
616 if (core_comm)
617 IOVEC_SET_STRING(iovec[j++], core_comm);
618 }
619
620 if (exe) {
8d4e028f 621 core_exe = strappend("COREDUMP_EXE=", exe);
f5e04665
LP
622 if (core_exe)
623 IOVEC_SET_STRING(iovec[j++], core_exe);
624 }
625
9bdbc2e2 626 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
f5e04665
LP
627 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
628 free(t);
629
630 if (core_cmdline)
631 IOVEC_SET_STRING(iovec[j++], core_cmdline);
632 }
633
a035f819
LP
634 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
635 core_cgroup = strappend("COREDUMP_CGROUP=", t);
636 free(t);
637
638 if (core_cgroup)
639 IOVEC_SET_STRING(iovec[j++], core_cgroup);
640 }
641
1eef15b1 642 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
f5e04665
LP
643 if (core_timestamp)
644 IOVEC_SET_STRING(iovec[j++], core_timestamp);
645
646 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
647 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
648
0dc5d23c
LP
649 /* Vacuum before we write anything again */
650 coredump_vacuum(-1, arg_keep_free, arg_max_use);
651
34c10968 652 /* Always stream the coredump to disk, if that's possible */
9fe13294 653 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968 654 if (r < 0)
2424a475
ZJS
655 /* skip whole core dumping part */
656 goto log;
34c10968
LP
657
658 /* If we don't want to keep the coredump on disk, remove it
8d4e028f
LP
659 * now, as later on we will lack the privileges for
660 * it. However, we keep the fd to it, so that we can still
661 * process it and log it. */
9fe13294 662 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
663 if (r < 0)
664 goto finish;
9fe13294
ZJS
665 if (r == 0) {
666 const char *coredump_filename;
667
668 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
669 IOVEC_SET_STRING(iovec[j++], coredump_filename);
670 }
34c10968 671
0dc5d23c
LP
672 /* Vacuum again, but exclude the coredump we just created */
673 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
674
fee80f69
LP
675 /* Now, let's drop privileges to become the user who owns the
676 * segfaulted process and allocate the coredump memory under
677 * his uid. This also ensures that the credentials journald
678 * will see are the ones of the coredumping user, thus making
679 * sure the user himself gets access to the core dump. */
fee80f69
LP
680 if (setresgid(gid, gid, gid) < 0 ||
681 setresuid(uid, uid, uid) < 0) {
682 log_error("Failed to drop privileges: %m");
683 r = -errno;
684 goto finish;
685 }
686
8d4e028f
LP
687#ifdef HAVE_ELFUTILS
688 /* Try to get a strack trace if we can */
689 if (coredump_size <= arg_process_size_max) {
690 _cleanup_free_ char *stacktrace = NULL;
691
692 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
693 if (r >= 0)
1eef15b1 694 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
8d4e028f
LP
695 else
696 log_warning("Failed to generate stack trace: %s", strerror(-r));
697 }
698
699 if (!core_message)
700#endif
2424a475 701log:
1eef15b1 702 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
8d4e028f
LP
703 if (core_message)
704 IOVEC_SET_STRING(iovec[j++], core_message);
705
34c10968
LP
706 /* Optionally store the entire coredump in the journal */
707 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
708 coredump_size <= (off_t) arg_journal_size_max) {
709 size_t sz;
fee80f69 710
34c10968 711 /* Store the coredump itself in the journal */
fee80f69 712
34c10968
LP
713 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
714 if (r >= 0) {
715 iovec[j].iov_base = coredump_data;
716 iovec[j].iov_len = sz;
717 j++;
ca0ceb6f 718 }
fee80f69
LP
719 }
720
f5e04665
LP
721 r = sd_journal_sendv(iovec, j);
722 if (r < 0)
872c8faa 723 log_error("Failed to log coredump: %s", strerror(-r));
f5e04665
LP
724
725finish:
f5e04665
LP
726 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
727}