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