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