]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/coredump.c
coredump: add simple coredump vacuuming
[thirdparty/systemd.git] / src / journal / coredump.c
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <sys/prctl.h>
26 #include <sys/types.h>
27 #include <sys/xattr.h>
28
29 #include <systemd/sd-journal.h>
30 #include <systemd/sd-login.h>
31
32 #include "log.h"
33 #include "util.h"
34 #include "strv.h"
35 #include "macro.h"
36 #include "mkdir.h"
37 #include "special.h"
38 #include "cgroup-util.h"
39 #include "journald-native.h"
40 #include "conf-parser.h"
41 #include "copy.h"
42 #include "stacktrace.h"
43 #include "path-util.h"
44 #include "compress.h"
45 #include "coredump-vacuum.h"
46
47 #ifdef HAVE_ACL
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
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))
68
69 /* Make sure to not make this larger than the maximum journal entry
70 * size. See ENTRY_SIZE_MAX in journald-native.c. */
71 assert_cc(JOURNAL_SIZE_MAX <= ENTRY_SIZE_MAX);
72
73 enum {
74 INFO_PID,
75 INFO_UID,
76 INFO_GID,
77 INFO_SIGNAL,
78 INFO_TIMESTAMP,
79 INFO_COMM,
80 INFO_EXE,
81 _INFO_LEN
82 };
83
84 typedef 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
93 static 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
100 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
101 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage,
102 CoredumpStorage,
103 "Failed to parse storage setting");
104
105 typedef enum CoredumpCompression {
106 COREDUMP_COMPRESSION_NONE,
107 COREDUMP_COMPRESSION_XZ,
108 _COREDUMP_COMPRESSION_MAX,
109 _COREDUMP_COMPRESSION_INVALID = -1
110 } CoredumpCompression;
111
112 static const char* const coredump_compression_table[_COREDUMP_COMPRESSION_MAX] = {
113 [COREDUMP_COMPRESSION_NONE] = "none",
114 [COREDUMP_COMPRESSION_XZ] = "xz",
115 };
116
117 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_compression, CoredumpCompression);
118 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_compression, coredump_compression,
119 CoredumpCompression,
120 "Failed to parse compression setting");
121
122 static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
123 static CoredumpCompression arg_compression = COREDUMP_COMPRESSION_XZ;
124 static unsigned arg_compression_level = LZMA_PRESET_DEFAULT;
125 static off_t arg_process_size_max = PROCESS_SIZE_MAX;
126 static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
127 static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
128 static off_t arg_keep_free = (off_t) -1;
129 static off_t arg_max_use = (off_t) -1;
130
131 static int parse_config(void) {
132
133 static const ConfigTableItem items[] = {
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 },
141 { "Coredump", "KeepFree", config_parse_iec_off, 0, &arg_keep_free },
142 { "Coredump", "MaxUse", config_parse_iec_off, 0, &arg_max_use },
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);
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
163 }
164
165 static 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
207 static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
208
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",
217 };
218
219 int r = 0;
220 unsigned i;
221
222 /* Attach some metadata to coredumps via extended
223 * attributes. Just because we can. */
224
225 for (i = 0; i < _INFO_LEN; i++) {
226 int k;
227
228 if (isempty(info[i]) || !xattrs[i])
229 continue;
230
231 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
232 if (k < 0 && r == 0)
233 r = -errno;
234 }
235
236 return r;
237 }
238
239 #define filename_escape(s) xescape((s), "./ ")
240
241 static 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
262 static 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
281 static 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) {
287
288 _cleanup_free_ char *p = NULL, *t = NULL, *c = NULL, *fn = NULL, *tmp = NULL, *u = NULL;
289 _cleanup_close_ int fd = -1;
290 sd_id128_t boot;
291 struct stat st;
292 int r;
293
294 assert(info);
295 assert(ret_filename);
296 assert(ret_fd);
297 assert(ret_size);
298
299 c = filename_escape(info[INFO_COMM]);
300 if (!c)
301 return log_oom();
302
303 p = filename_escape(info[INFO_PID]);
304 if (!p)
305 return log_oom();
306
307 u = filename_escape(info[INFO_UID]);
308 if (!u)
309 return log_oom();
310
311 t = filename_escape(info[INFO_TIMESTAMP]);
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,
322 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
323 c,
324 u,
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();
334
335 mkdir_p_label("/var/lib/systemd/coredump", 0755);
336
337 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
338 if (fd < 0) {
339 log_error("Failed to create coredump file %s: %m", tmp);
340 return -errno;
341 }
342
343 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
344 if (r == -E2BIG) {
345 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
346 goto fail;
347 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
348 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
349 goto fail;
350 } else if (r < 0) {
351 log_error("Failed to dump coredump to file: %s", strerror(-r));
352 goto fail;
353 }
354
355 if (fstat(fd, &st) < 0) {
356 log_error("Failed to fstat coredump %s: %m", tmp);
357 goto fail;
358 }
359
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
365 #ifdef HAVE_XZ
366 /* If we will remove the coredump anyway, do not compress. */
367 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
368 && arg_compression == COREDUMP_COMPRESSION_XZ) {
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
381 r = compress_stream(fd, fd2, arg_compression_level, -1);
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);
409 }
410 #endif
411
412 uncompressed:
413 r = fix_permissions(fd, tmp, fn, info, uid);
414 if (r < 0)
415 goto fail;
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
426 fail:
427 unlink_noerrno(tmp);
428 return r;
429 }
430
431 static 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
435 assert(fd >= 0);
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;
442 }
443
444 field = malloc(9 + size);
445 if (!field) {
446 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
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 }
469
470 int main(int argc, char* argv[]) {
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,
475 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
476 *exe = NULL, *comm = NULL, *filename = NULL;
477 const char *info[_INFO_LEN];
478
479 _cleanup_close_ int coredump_fd = -1;
480
481 struct iovec iovec[18];
482 off_t coredump_size;
483 int r, j = 0;
484 uid_t uid, owner_uid;
485 gid_t gid;
486 pid_t pid;
487 char *t;
488
489 /* Make sure we never enter a loop */
490 prctl(PR_SET_DUMPABLE, 0);
491
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);
496 log_open();
497
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);
501 r = -EINVAL;
502 goto finish;
503 }
504
505 /* Ignore all parse errors */
506 parse_config();
507 log_debug("Selected storage '%s'.",
508 coredump_storage_to_string(arg_storage));
509 log_debug("Selected compression %s:%u.",
510 coredump_compression_to_string(arg_compression),
511 arg_compression_level);
512
513 r = parse_uid(argv[INFO_UID + 1], &uid);
514 if (r < 0) {
515 log_error("Failed to parse UID.");
516 goto finish;
517 }
518
519 r = parse_pid(argv[INFO_PID + 1], &pid);
520 if (r < 0) {
521 log_error("Failed to parse PID.");
522 goto finish;
523 }
524
525 r = parse_gid(argv[INFO_GID + 1], &gid);
526 if (r < 0) {
527 log_error("Failed to parse GID.");
528 goto finish;
529 }
530
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
547 if (cg_pid_get_unit(pid, &t) >= 0) {
548
549 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
550
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
558 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
559 if (r < 0)
560 goto finish;
561
562 r = maybe_remove_external_coredump(filename, coredump_size);
563 if (r < 0)
564 goto finish;
565
566 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
567 goto finish;
568 }
569
570 core_unit = strappend("COREDUMP_UNIT=", t);
571 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
572 core_unit = strappend("COREDUMP_USER_UNIT=", t);
573
574 if (core_unit)
575 IOVEC_SET_STRING(iovec[j++], core_unit);
576
577 /* OK, now we know it's not the journal, hence we can make use
578 * of it now. */
579 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
580 log_open();
581
582 core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
583 if (core_pid)
584 IOVEC_SET_STRING(iovec[j++], core_pid);
585
586 core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
587 if (core_uid)
588 IOVEC_SET_STRING(iovec[j++], core_uid);
589
590 core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
591 if (core_gid)
592 IOVEC_SET_STRING(iovec[j++], core_gid);
593
594 core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
595 if (core_signal)
596 IOVEC_SET_STRING(iovec[j++], core_signal);
597
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
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
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) {
628 core_exe = strappend("COREDUMP_EXE=", exe);
629 if (core_exe)
630 IOVEC_SET_STRING(iovec[j++], core_exe);
631 }
632
633 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
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
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
649 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
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
656 /* Vacuum before we write anything again */
657 coredump_vacuum(-1, arg_keep_free, arg_max_use);
658
659 /* Always stream the coredump to disk, if that's possible */
660 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
661 if (r < 0)
662 /* skip whole core dumping part */
663 goto log;
664
665 /* If we don't want to keep the coredump on disk, remove it
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. */
669 r = maybe_remove_external_coredump(filename, coredump_size);
670 if (r < 0)
671 goto finish;
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 }
678
679 /* Vacuum again, but exclude the coredump we just created */
680 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
681
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. */
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
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)
701 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
702 else
703 log_warning("Failed to generate stack trace: %s", strerror(-r));
704 }
705
706 if (!core_message)
707 #endif
708 log:
709 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
710 if (core_message)
711 IOVEC_SET_STRING(iovec[j++], core_message);
712
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;
717
718 /* Store the coredump itself in the journal */
719
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++;
725 }
726 }
727
728 r = sd_journal_sendv(iovec, j);
729 if (r < 0)
730 log_error("Failed to log coredump: %s", strerror(-r));
731
732 finish:
733 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
734 }