]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
coredumpctl: remove unused variable
[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"
34c10968
LP
45
46#ifdef HAVE_ACL
34727273
ZJS
47# include <sys/acl.h>
48# include "acl-util.h"
49#endif
50
51#ifdef HAVE_XZ
52# include <lzma.h>
53#else
54# define LZMA_PRESET_DEFAULT 0
34c10968
LP
55#endif
56
57/* The maximum size up to which we process coredumps */
58#define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
59
60/* The maximum size up to which we leave the coredump around on
61 * disk */
62#define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
63
64/* The maximum size up to which we store the coredump in the
65 * journal */
66#define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
f5e04665 67
c4aa09b0
LP
68/* Make sure to not make this larger than the maximum journal entry
69 * size. See ENTRY_SIZE_MAX in journald-native.c. */
34c10968 70assert_cc(JOURNAL_SIZE_MAX <= ENTRY_SIZE_MAX);
f5e04665
LP
71
72enum {
1eef15b1
ZJS
73 INFO_PID,
74 INFO_UID,
75 INFO_GID,
76 INFO_SIGNAL,
77 INFO_TIMESTAMP,
78 INFO_COMM,
79 INFO_EXE,
80 _INFO_LEN
f5e04665
LP
81};
82
34c10968
LP
83typedef enum CoredumpStorage {
84 COREDUMP_STORAGE_NONE,
85 COREDUMP_STORAGE_EXTERNAL,
86 COREDUMP_STORAGE_JOURNAL,
87 COREDUMP_STORAGE_BOTH,
88 _COREDUMP_STORAGE_MAX,
89 _COREDUMP_STORAGE_INVALID = -1
90} CoredumpStorage;
91
34c10968
LP
92static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
93 [COREDUMP_STORAGE_NONE] = "none",
94 [COREDUMP_STORAGE_EXTERNAL] = "external",
95 [COREDUMP_STORAGE_JOURNAL] = "journal",
96 [COREDUMP_STORAGE_BOTH] = "both",
97};
98
99DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
34727273
ZJS
100static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage,
101 CoredumpStorage,
102 "Failed to parse storage setting");
103
104typedef enum CoredumpCompression {
105 COREDUMP_COMPRESSION_NONE,
106 COREDUMP_COMPRESSION_XZ,
107 _COREDUMP_COMPRESSION_MAX,
108 _COREDUMP_COMPRESSION_INVALID = -1
109} CoredumpCompression;
110
111static const char* const coredump_compression_table[_COREDUMP_COMPRESSION_MAX] = {
112 [COREDUMP_COMPRESSION_NONE] = "none",
113 [COREDUMP_COMPRESSION_XZ] = "xz",
114};
115
116DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_compression, CoredumpCompression);
117static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_compression, coredump_compression,
118 CoredumpCompression,
119 "Failed to parse compression setting");
120
121static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
122static CoredumpCompression arg_compression = COREDUMP_COMPRESSION_XZ;
123static unsigned arg_compression_level = LZMA_PRESET_DEFAULT;
124
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;
34c10968
LP
128
129static int parse_config(void) {
130
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 },
134 { "Coredump", "CompressionLevel", config_parse_unsigned, 0, &arg_compression_level },
135
136 { "Coredump", "ProcessSizeMax", config_parse_iec_off, 0, &arg_process_size_max },
137 { "Coredump", "ExternalSizeMax", config_parse_iec_off, 0, &arg_external_size_max },
138 { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
34c10968
LP
139 {}
140 };
141
142 return config_parse(
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);
34727273
ZJS
152
153#ifdef HAVE_XZ
154 if (arg_compression_level > 9) {
155 log_warning("Invalid CompressionLevel %u, ignoring.", arg_compression_level);
156 arg_compression_level = LZMA_PRESET_DEFAULT;
157 }
158#endif
34c10968
LP
159}
160
161static int fix_acl(int fd, uid_t uid) {
162
163#ifdef HAVE_ACL
164 _cleanup_(acl_freep) acl_t acl = NULL;
165 acl_entry_t entry;
166 acl_permset_t permset;
167
168 if (uid <= SYSTEM_UID_MAX)
169 return 0;
170
171 /* Make sure normal users can read (but not write or delete)
172 * their own coredumps */
173
174 acl = acl_get_fd(fd);
175 if (!acl) {
176 log_error("Failed to get ACL: %m");
177 return -errno;
178 }
179
180 if (acl_create_entry(&acl, &entry) < 0 ||
181 acl_set_tag_type(entry, ACL_USER) < 0 ||
182 acl_set_qualifier(entry, &uid) < 0) {
183 log_error("Failed to patch ACL: %m");
184 return -errno;
185 }
186
187 if (acl_get_permset(entry, &permset) < 0 ||
188 acl_add_perm(permset, ACL_READ) < 0 ||
189 calc_acl_mask_if_needed(&acl) < 0) {
190 log_warning("Failed to patch ACL: %m");
191 return -errno;
192 }
193
194 if (acl_set_fd(fd, acl) < 0) {
195 log_error("Failed to apply ACL: %m");
196 return -errno;
197 }
198#endif
199
200 return 0;
201}
202
1eef15b1 203static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
0cd77f97 204
1eef15b1
ZJS
205 static const char * const xattrs[_INFO_LEN] = {
206 [INFO_PID] = "user.coredump.pid",
207 [INFO_UID] = "user.coredump.uid",
208 [INFO_GID] = "user.coredump.gid",
209 [INFO_SIGNAL] = "user.coredump.signal",
210 [INFO_TIMESTAMP] = "user.coredump.timestamp",
211 [INFO_COMM] = "user.coredump.comm",
212 [INFO_EXE] = "user.coredump.exe",
0cd77f97
LP
213 };
214
34c10968 215 int r = 0;
0cd77f97 216 unsigned i;
34c10968 217
1eef15b1 218 /* Attach some metadata to coredumps via extended
34c10968
LP
219 * attributes. Just because we can. */
220
1eef15b1
ZJS
221 for (i = 0; i < _INFO_LEN; i++) {
222 int k;
223
224 if (isempty(info[i]) || !xattrs[i])
0cd77f97 225 continue;
34c10968 226
1eef15b1
ZJS
227 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
228 if (k < 0 && r == 0)
34c10968 229 r = -errno;
0cd77f97 230 }
34c10968
LP
231
232 return r;
233}
234
b0b21dce 235#define filename_escape(s) xescape((s), "./ ")
34c10968 236
cfd652ed
ZJS
237static int fix_permissions(int fd, const char *filename, const char *target,
238 const char *info[_INFO_LEN], uid_t uid) {
239
240 /* Ignore errors on these */
241 fchmod(fd, 0640);
242 fix_acl(fd, uid);
243 fix_xattr(fd, info);
244
245 if (fsync(fd) < 0) {
246 log_error("Failed to sync coredump %s: %m", filename);
247 return -errno;
248 }
249
250 if (rename(filename, target) < 0) {
251 log_error("Failed to rename coredump %s -> %s: %m", filename, target);
252 return -errno;
253 }
254
255 return 0;
256}
257
258static int maybe_remove_external_coredump(const char *filename, off_t size) {
259
260 /* Returns 1 if might remove, 0 if will not remove, <0 on error. */
261
262 if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
263 size <= arg_external_size_max)
264 return 0;
265
266 if (!filename)
267 return 1;
268
269 if (unlink(filename) < 0) {
270 log_error("Failed to unlink %s: %m", filename);
271 return -errno;
272 }
273
274 return 1;
275}
276
277
1eef15b1
ZJS
278static int save_external_coredump(const char *info[_INFO_LEN],
279 uid_t uid,
280 char **ret_filename,
281 int *ret_fd,
282 off_t *ret_size) {
283
34c10968
LP
284 _cleanup_free_ char *p = NULL, *t = NULL, *c = NULL, *fn = NULL, *tmp = NULL;
285 _cleanup_close_ int fd = -1;
286 sd_id128_t boot;
287 struct stat st;
288 int r;
289
1eef15b1 290 assert(info);
34c10968
LP
291 assert(ret_filename);
292 assert(ret_fd);
293 assert(ret_size);
294
1eef15b1 295 c = filename_escape(info[INFO_COMM]);
34c10968
LP
296 if (!c)
297 return log_oom();
298
1eef15b1 299 p = filename_escape(info[INFO_PID]);
34c10968
LP
300 if (!p)
301 return log_oom();
302
1eef15b1 303 t = filename_escape(info[INFO_TIMESTAMP]);
34c10968
LP
304 if (!t)
305 return log_oom();
306
307 r = sd_id128_get_boot(&boot);
308 if (r < 0) {
309 log_error("Failed to determine boot ID: %s", strerror(-r));
310 return r;
311 }
312
313 r = asprintf(&fn,
314 "/var/lib/systemd/coredump/core.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
315 c,
316 SD_ID128_FORMAT_VAL(boot),
317 p,
318 t);
319 if (r < 0)
320 return log_oom();
321
322 tmp = tempfn_random(fn);
323 if (!tmp)
324 return log_oom();
803a3464 325
d2e54fae 326 mkdir_p_label("/var/lib/systemd/coredump", 0755);
803a3464 327
34c10968
LP
328 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
329 if (fd < 0) {
cfd652ed 330 log_error("Failed to create coredump file %s: %m", tmp);
803a3464
LP
331 return -errno;
332 }
333
93240d3a
LP
334 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
335 if (r == -E2BIG) {
1eef15b1
ZJS
336 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.",
337 info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
338 goto fail;
339 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
1eef15b1
ZJS
340 log_error("Not enough disk space for coredump of %s (%s), refusing.",
341 info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
342 goto fail;
343 } else if (r < 0) {
34c10968
LP
344 log_error("Failed to dump coredump to file: %s", strerror(-r));
345 goto fail;
346 }
803a3464 347
cfd652ed
ZJS
348 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
349 log_error("Failed to seek on %s: %m", tmp);
350 goto uncompressed;
34c10968 351 }
803a3464 352
34c10968 353 if (fstat(fd, &st) < 0) {
1eef15b1 354 log_error("Failed to fstat coredump %s: %m", tmp);
34c10968
LP
355 goto fail;
356 }
357
cfd652ed
ZJS
358#ifdef HAVE_XZ
359 /* If we will remove the coredump anyway, do not compress. */
34727273
ZJS
360 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
361 && arg_compression == COREDUMP_COMPRESSION_XZ) {
cfd652ed
ZJS
362
363 _cleanup_free_ char *fn2 = NULL;
364 char *tmp2;
365 _cleanup_close_ int fd2 = -1;
366
367 tmp2 = strappenda(tmp, ".xz");
368 fd2 = open(tmp2, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
369 if (fd2 < 0) {
370 log_error("Failed to create file %s: %m", tmp2);
371 goto uncompressed;
372 }
373
34727273 374 r = compress_stream(fd, fd2, arg_compression_level, -1);
cfd652ed
ZJS
375 if (r < 0) {
376 log_error("Failed to compress %s: %s", tmp2, strerror(-r));
377 unlink_noerrno(tmp2);
378 goto fail2;
379 }
380
381 fn2 = strappend(fn, ".xz");
382 if (!fn2) {
383 log_oom();
384 goto fail2;
385 }
386
387 r = fix_permissions(fd2, tmp2, fn2, info, uid);
388 if (r < 0)
389 goto fail2;
390
391 *ret_filename = fn2; /* compressed */
392 *ret_fd = fd; /* uncompressed */
393 *ret_size = st.st_size; /* uncompressed */
394
395 fn2 = NULL;
396 fd = -1;
397
398 return 0;
399
400 fail2:
401 unlink_noerrno(tmp2);
34c10968 402 }
cfd652ed
ZJS
403#endif
404
405uncompressed:
406 r = fix_permissions(fd, tmp, fn, info, uid);
407 if (r < 0)
408 goto fail;
34c10968
LP
409
410 *ret_filename = fn;
411 *ret_fd = fd;
412 *ret_size = st.st_size;
413
414 fn = NULL;
415 fd = -1;
416
417 return 0;
418
419fail:
420 unlink_noerrno(tmp);
421 return r;
422}
423
424static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
425 _cleanup_free_ char *field = NULL;
426 ssize_t n;
427
8d4e028f 428 assert(fd >= 0);
34c10968
LP
429 assert(ret);
430 assert(ret_size);
431
432 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
433 log_warning("Failed to seek: %m");
434 return -errno;
803a3464
LP
435 }
436
34c10968
LP
437 field = malloc(9 + size);
438 if (!field) {
cfd652ed 439 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
34c10968
LP
440 return -ENOMEM;
441 }
442
443 memcpy(field, "COREDUMP=", 9);
444
445 n = read(fd, field + 9, size);
446 if (n < 0) {
447 log_error("Failed to read core data: %s", strerror(-n));
448 return (int) n;
449 }
450 if ((size_t) n < size) {
451 log_error("Core data too short.");
452 return -EIO;
453 }
454
455 *ret = field;
456 *ret_size = size + 9;
457
458 field = NULL;
459
460 return 0;
461}
803a3464 462
f5e04665 463int main(int argc, char* argv[]) {
34c10968
LP
464
465 _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
466 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
467 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
9fe13294
ZJS
468 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
469 *exe = NULL, *comm = NULL, *filename = NULL;
1eef15b1 470 const char *info[_INFO_LEN];
34c10968
LP
471
472 _cleanup_close_ int coredump_fd = -1;
473
9fe13294 474 struct iovec iovec[18];
34c10968 475 off_t coredump_size;
f5e04665 476 int r, j = 0;
a035f819 477 uid_t uid, owner_uid;
fee80f69 478 gid_t gid;
a035f819 479 pid_t pid;
34c10968 480 char *t;
f5e04665 481
34c10968 482 /* Make sure we never enter a loop */
803a3464 483 prctl(PR_SET_DUMPABLE, 0);
f5e04665 484
34c10968
LP
485 /* First, log to a safe place, since we don't know what
486 * crashed and it might be journald which we'd rather not log
487 * to then. */
488 log_set_target(LOG_TARGET_KMSG);
34c10968 489 log_open();
803a3464 490
1eef15b1
ZJS
491 if (argc < INFO_COMM + 1) {
492 log_error("Not enough arguments passed from kernel (%d, expected %d).",
493 argc - 1, INFO_COMM + 1 - 1);
f5e04665
LP
494 r = -EINVAL;
495 goto finish;
496 }
497
34c10968
LP
498 /* Ignore all parse errors */
499 parse_config();
34727273
ZJS
500 log_debug("Selected storage '%s'.",
501 coredump_storage_to_string(arg_storage));
502 log_debug("Selected compression %s:%u.",
2bb9a7a2 503 coredump_compression_to_string(arg_compression),
34727273 504 arg_compression_level);
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
34c10968 649 /* Always stream the coredump to disk, if that's possible */
9fe13294 650 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968 651 if (r < 0)
2424a475
ZJS
652 /* skip whole core dumping part */
653 goto log;
34c10968
LP
654
655 /* If we don't want to keep the coredump on disk, remove it
8d4e028f
LP
656 * now, as later on we will lack the privileges for
657 * it. However, we keep the fd to it, so that we can still
658 * process it and log it. */
9fe13294 659 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
660 if (r < 0)
661 goto finish;
9fe13294
ZJS
662 if (r == 0) {
663 const char *coredump_filename;
664
665 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
666 IOVEC_SET_STRING(iovec[j++], coredump_filename);
667 }
34c10968 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}