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