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