chiark / gitweb /
coredump: log coredump even if core dumping fails
[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
45 #ifdef HAVE_ACL
46 #include <sys/acl.h>
47 #include "acl-util.h"
48 #endif
49
50 /* The maximum size up to which we process coredumps */
51 #define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
52
53 /* The maximum size up to which we leave the coredump around on
54  * disk */
55 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
56
57 /* The maximum size up to which we store the coredump in the
58  * journal */
59 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
60
61 /* Make sure to not make this larger than the maximum journal entry
62  * size. See ENTRY_SIZE_MAX in journald-native.c. */
63 assert_cc(JOURNAL_SIZE_MAX <= ENTRY_SIZE_MAX);
64
65 enum {
66         INFO_PID,
67         INFO_UID,
68         INFO_GID,
69         INFO_SIGNAL,
70         INFO_TIMESTAMP,
71         INFO_COMM,
72         INFO_EXE,
73         _INFO_LEN
74 };
75
76 typedef enum CoredumpStorage {
77         COREDUMP_STORAGE_NONE,
78         COREDUMP_STORAGE_EXTERNAL,
79         COREDUMP_STORAGE_JOURNAL,
80         COREDUMP_STORAGE_BOTH,
81         _COREDUMP_STORAGE_MAX,
82         _COREDUMP_STORAGE_INVALID = -1
83 } CoredumpStorage;
84
85 static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
86 static off_t arg_process_size_max = PROCESS_SIZE_MAX;
87 static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
88 static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
89
90 static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
91         [COREDUMP_STORAGE_NONE] = "none",
92         [COREDUMP_STORAGE_EXTERNAL] = "external",
93         [COREDUMP_STORAGE_JOURNAL] = "journal",
94         [COREDUMP_STORAGE_BOTH] = "both",
95 };
96
97 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
98 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
99
100 static int parse_config(void) {
101
102         static const ConfigTableItem items[] = {
103                 { "Coredump", "ProcessSizeMax",  config_parse_iec_off,           0, &arg_process_size_max  },
104                 { "Coredump", "ExternalSizeMax", config_parse_iec_off,           0, &arg_external_size_max },
105                 { "Coredump", "JournalSizeMax",  config_parse_iec_size,          0, &arg_journal_size_max  },
106                 { "Coredump", "Storage",         config_parse_coredump_storage,  0, &arg_storage           },
107                 {}
108         };
109
110         return config_parse(
111                         NULL,
112                         "/etc/systemd/coredump.conf",
113                         NULL,
114                         "Coredump\0",
115                         config_item_table_lookup,
116                         (void*) items,
117                         false,
118                         false,
119                         NULL);
120 }
121
122 static int fix_acl(int fd, uid_t uid) {
123
124 #ifdef HAVE_ACL
125         _cleanup_(acl_freep) acl_t acl = NULL;
126         acl_entry_t entry;
127         acl_permset_t permset;
128
129         if (uid <= SYSTEM_UID_MAX)
130                 return 0;
131
132         /* Make sure normal users can read (but not write or delete)
133          * their own coredumps */
134
135         acl = acl_get_fd(fd);
136         if (!acl) {
137                 log_error("Failed to get ACL: %m");
138                 return -errno;
139         }
140
141         if (acl_create_entry(&acl, &entry) < 0 ||
142             acl_set_tag_type(entry, ACL_USER) < 0 ||
143             acl_set_qualifier(entry, &uid) < 0) {
144                 log_error("Failed to patch ACL: %m");
145                 return -errno;
146         }
147
148         if (acl_get_permset(entry, &permset) < 0 ||
149             acl_add_perm(permset, ACL_READ) < 0 ||
150             calc_acl_mask_if_needed(&acl) < 0) {
151                 log_warning("Failed to patch ACL: %m");
152                 return -errno;
153         }
154
155         if (acl_set_fd(fd, acl) < 0) {
156                 log_error("Failed to apply ACL: %m");
157                 return -errno;
158         }
159 #endif
160
161         return 0;
162 }
163
164 static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
165
166         static const char * const xattrs[_INFO_LEN] = {
167                 [INFO_PID] = "user.coredump.pid",
168                 [INFO_UID] = "user.coredump.uid",
169                 [INFO_GID] = "user.coredump.gid",
170                 [INFO_SIGNAL] = "user.coredump.signal",
171                 [INFO_TIMESTAMP] = "user.coredump.timestamp",
172                 [INFO_COMM] = "user.coredump.comm",
173                 [INFO_EXE] = "user.coredump.exe",
174         };
175
176         int r = 0;
177         unsigned i;
178
179         /* Attach some metadata to coredumps via extended
180          * attributes. Just because we can. */
181
182         for (i = 0; i < _INFO_LEN; i++) {
183                 int k;
184
185                 if (isempty(info[i]) || !xattrs[i])
186                         continue;
187
188                 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
189                 if (k < 0 && r == 0)
190                         r = -errno;
191         }
192
193         return r;
194 }
195
196 #define filename_escape(s) xescape((s), "./ ")
197
198 static int save_external_coredump(const char *info[_INFO_LEN],
199                                   uid_t uid,
200                                   char **ret_filename,
201                                   int *ret_fd,
202                                   off_t *ret_size) {
203
204         _cleanup_free_ char *p = NULL, *t = NULL, *c = NULL, *fn = NULL, *tmp = NULL;
205         _cleanup_close_ int fd = -1;
206         sd_id128_t boot;
207         struct stat st;
208         int r;
209
210         assert(info);
211         assert(ret_filename);
212         assert(ret_fd);
213         assert(ret_size);
214
215         c = filename_escape(info[INFO_COMM]);
216         if (!c)
217                 return log_oom();
218
219         p = filename_escape(info[INFO_PID]);
220         if (!p)
221                 return log_oom();
222
223         t = filename_escape(info[INFO_TIMESTAMP]);
224         if (!t)
225                 return log_oom();
226
227         r = sd_id128_get_boot(&boot);
228         if (r < 0) {
229                 log_error("Failed to determine boot ID: %s", strerror(-r));
230                 return r;
231         }
232
233         r = asprintf(&fn,
234                      "/var/lib/systemd/coredump/core.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
235                      c,
236                      SD_ID128_FORMAT_VAL(boot),
237                      p,
238                      t);
239         if (r < 0)
240                 return log_oom();
241
242         tmp = tempfn_random(fn);
243         if (!tmp)
244                 return log_oom();
245
246         mkdir_p_label("/var/lib/systemd/coredump", 0755);
247
248         fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
249         if (fd < 0) {
250                 log_error("Failed to create coredump file: %m");
251                 return -errno;
252         }
253
254         r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
255         if (r == -E2BIG) {
256                 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.",
257                           info[INFO_PID], info[INFO_COMM]);
258                 goto fail;
259         } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
260                 log_error("Not enough disk space for coredump of %s (%s), refusing.",
261                           info[INFO_PID], info[INFO_COMM]);
262                 goto fail;
263         } else if (r < 0) {
264                 log_error("Failed to dump coredump to file: %s", strerror(-r));
265                 goto fail;
266         }
267
268         /* Ignore errors on these */
269         fchmod(fd, 0640);
270         fix_acl(fd, uid);
271         fix_xattr(fd, info);
272
273         if (fsync(fd) < 0) {
274                 log_error("Failed to sync coredump %s: %m", tmp);
275                 r = -errno;
276                 goto fail;
277         }
278
279         if (fstat(fd, &st) < 0) {
280                 log_error("Failed to fstat coredump %s: %m", tmp);
281                 r = -errno;
282                 goto fail;
283         }
284
285         if (rename(tmp, fn) < 0) {
286                 log_error("Failed to rename coredump %s -> %s: %m", tmp, fn);
287                 r = -errno;
288                 goto fail;
289         }
290
291         *ret_filename = fn;
292         *ret_fd = fd;
293         *ret_size = st.st_size;
294
295         fn = NULL;
296         fd = -1;
297
298         return 0;
299
300 fail:
301         unlink_noerrno(tmp);
302         return r;
303 }
304
305 static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
306         _cleanup_free_ char *field = NULL;
307         ssize_t n;
308
309         assert(fd >= 0);
310         assert(ret);
311         assert(ret_size);
312
313         if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
314                 log_warning("Failed to seek: %m");
315                 return -errno;
316         }
317
318         field = malloc(9 + size);
319         if (!field) {
320                 log_warning("Failed to allocate memory fore coredump, coredump will not be stored.");
321                 return -ENOMEM;
322         }
323
324         memcpy(field, "COREDUMP=", 9);
325
326         n = read(fd, field + 9, size);
327         if (n < 0) {
328                 log_error("Failed to read core data: %s", strerror(-n));
329                 return (int) n;
330         }
331         if ((size_t) n < size) {
332                 log_error("Core data too short.");
333                 return -EIO;
334         }
335
336         *ret = field;
337         *ret_size = size + 9;
338
339         field = NULL;
340
341         return 0;
342 }
343
344 static int maybe_remove_external_coredump(const char *filename, off_t size) {
345
346         if (!filename)
347                 return 0;
348
349         if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
350             size <= arg_external_size_max)
351                 return 0;
352
353         if (unlink(filename) < 0) {
354                 log_error("Failed to unlink %s: %m", filename);
355                 return -errno;
356         }
357
358         return 0;
359 }
360
361 int main(int argc, char* argv[]) {
362
363         _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
364                 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
365                 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
366                 *coredump_filename = NULL, *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
367                 *exe = NULL, *comm = NULL;
368         const char *info[_INFO_LEN];
369
370         _cleanup_close_ int coredump_fd = -1;
371
372         struct iovec iovec[17];
373         off_t coredump_size;
374         int r, j = 0;
375         uid_t uid, owner_uid;
376         gid_t gid;
377         pid_t pid;
378         char *t;
379
380         /* Make sure we never enter a loop */
381         prctl(PR_SET_DUMPABLE, 0);
382
383         /* First, log to a safe place, since we don't know what
384          * crashed and it might be journald which we'd rather not log
385          * to then. */
386         log_set_target(LOG_TARGET_KMSG);
387         log_open();
388
389         if (argc < INFO_COMM + 1) {
390                 log_error("Not enough arguments passed from kernel (%d, expected %d).",
391                           argc - 1, INFO_COMM + 1 - 1);
392                 r = -EINVAL;
393                 goto finish;
394         }
395
396         /* Ignore all parse errors */
397         parse_config();
398         log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
399
400         r = parse_uid(argv[INFO_UID + 1], &uid);
401         if (r < 0) {
402                 log_error("Failed to parse UID.");
403                 goto finish;
404         }
405
406         r = parse_pid(argv[INFO_PID + 1], &pid);
407         if (r < 0) {
408                 log_error("Failed to parse PID.");
409                 goto finish;
410         }
411
412         r = parse_gid(argv[INFO_GID + 1], &gid);
413         if (r < 0) {
414                 log_error("Failed to parse GID.");
415                 goto finish;
416         }
417
418         if (get_process_comm(pid, &comm) < 0) {
419                 log_warning("Failed to get COMM, falling back to the commandline.");
420                 comm = strv_join(argv + INFO_COMM + 1, " ");
421         }
422
423         if (get_process_exe(pid, &exe) < 0)
424                 log_warning("Failed to get EXE.");
425
426         info[INFO_PID] = argv[INFO_PID + 1];
427         info[INFO_UID] = argv[INFO_UID + 1];
428         info[INFO_GID] = argv[INFO_GID + 1];
429         info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
430         info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
431         info[INFO_COMM] = comm;
432         info[INFO_EXE] = exe;
433
434         if (cg_pid_get_unit(pid, &t) >= 0) {
435
436                 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
437
438                         /* If we are journald, we cut things short,
439                          * don't write to the journal, but still
440                          * create a coredump. */
441
442                         if (arg_storage != COREDUMP_STORAGE_NONE)
443                                 arg_storage = COREDUMP_STORAGE_EXTERNAL;
444
445                         r = save_external_coredump(info, uid, &coredump_filename, &coredump_fd, &coredump_size);
446                         if (r < 0)
447                                 goto finish;
448
449                         r = maybe_remove_external_coredump(coredump_filename, coredump_size);
450                         if (r < 0)
451                                 goto finish;
452
453                         log_info("Detected coredump of the journal daemon itself, diverted to %s.", coredump_filename);
454                         goto finish;
455                 }
456
457                 core_unit = strappend("COREDUMP_UNIT=", t);
458         } else if (cg_pid_get_user_unit(pid, &t) >= 0)
459                 core_unit = strappend("COREDUMP_USER_UNIT=", t);
460
461         if (core_unit)
462                 IOVEC_SET_STRING(iovec[j++], core_unit);
463
464         /* OK, now we know it's not the journal, hence we can make use
465          * of it now. */
466         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
467         log_open();
468
469         core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
470         if (core_pid)
471                 IOVEC_SET_STRING(iovec[j++], core_pid);
472
473         core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
474         if (core_uid)
475                 IOVEC_SET_STRING(iovec[j++], core_uid);
476
477         core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
478         if (core_gid)
479                 IOVEC_SET_STRING(iovec[j++], core_gid);
480
481         core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
482         if (core_signal)
483                 IOVEC_SET_STRING(iovec[j++], core_signal);
484
485         if (sd_pid_get_session(pid, &t) >= 0) {
486                 core_session = strappend("COREDUMP_SESSION=", t);
487                 free(t);
488
489                 if (core_session)
490                         IOVEC_SET_STRING(iovec[j++], core_session);
491         }
492
493         if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
494                 asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
495
496                 if (core_owner_uid)
497                         IOVEC_SET_STRING(iovec[j++], core_owner_uid);
498         }
499
500         if (sd_pid_get_slice(pid, &t) >= 0) {
501                 core_slice = strappend("COREDUMP_SLICE=", t);
502                 free(t);
503
504                 if (core_slice)
505                         IOVEC_SET_STRING(iovec[j++], core_slice);
506         }
507
508         if (comm) {
509                 core_comm = strappend("COREDUMP_COMM=", comm);
510                 if (core_comm)
511                         IOVEC_SET_STRING(iovec[j++], core_comm);
512         }
513
514         if (exe) {
515                 core_exe = strappend("COREDUMP_EXE=", exe);
516                 if (core_exe)
517                         IOVEC_SET_STRING(iovec[j++], core_exe);
518         }
519
520         if (get_process_cmdline(pid, 0, false, &t) >= 0) {
521                 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
522                 free(t);
523
524                 if (core_cmdline)
525                         IOVEC_SET_STRING(iovec[j++], core_cmdline);
526         }
527
528         if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
529                 core_cgroup = strappend("COREDUMP_CGROUP=", t);
530                 free(t);
531
532                 if (core_cgroup)
533                         IOVEC_SET_STRING(iovec[j++], core_cgroup);
534         }
535
536         core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
537         if (core_timestamp)
538                 IOVEC_SET_STRING(iovec[j++], core_timestamp);
539
540         IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
541         IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
542
543         /* Always stream the coredump to disk, if that's possible */
544         r = save_external_coredump(info, uid, &coredump_filename, &coredump_fd, &coredump_size);
545         if (r < 0)
546                 /* skip whole core dumping part */
547                 goto log;
548
549         /* If we don't want to keep the coredump on disk, remove it
550          * now, as later on we will lack the privileges for
551          * it. However, we keep the fd to it, so that we can still
552          * process it and log it. */
553         r = maybe_remove_external_coredump(coredump_filename, coredump_size);
554         if (r < 0)
555                 goto finish;
556
557         /* Now, let's drop privileges to become the user who owns the
558          * segfaulted process and allocate the coredump memory under
559          * his uid. This also ensures that the credentials journald
560          * will see are the ones of the coredumping user, thus making
561          * sure the user himself gets access to the core dump. */
562         if (setresgid(gid, gid, gid) < 0 ||
563             setresuid(uid, uid, uid) < 0) {
564                 log_error("Failed to drop privileges: %m");
565                 r = -errno;
566                 goto finish;
567         }
568
569 #ifdef HAVE_ELFUTILS
570         /* Try to get a strack trace if we can */
571         if (coredump_size <= arg_process_size_max) {
572                 _cleanup_free_ char *stacktrace = NULL;
573
574                 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
575                 if (r >= 0)
576                         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
577                 else
578                         log_warning("Failed to generate stack trace: %s", strerror(-r));
579         }
580
581         if (!core_message)
582 #endif
583 log:
584         core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
585         if (core_message)
586                 IOVEC_SET_STRING(iovec[j++], core_message);
587
588         /* Optionally store the entire coredump in the journal */
589         if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
590             coredump_size <= (off_t) arg_journal_size_max) {
591                 size_t sz;
592
593                 /* Store the coredump itself in the journal */
594
595                 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
596                 if (r >= 0) {
597                         iovec[j].iov_base = coredump_data;
598                         iovec[j].iov_len = sz;
599                         j++;
600                 }
601         }
602
603         r = sd_journal_sendv(iovec, j);
604         if (r < 0)
605                 log_error("Failed to log coredump: %s", strerror(-r));
606
607 finish:
608         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
609 }