Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <stdio.h>
5 : : #include <sys/prctl.h>
6 : : #include <sys/xattr.h>
7 : : #include <unistd.h>
8 : :
9 : : #if HAVE_ELFUTILS
10 : : #include <dwarf.h>
11 : : #include <elfutils/libdwfl.h>
12 : : #endif
13 : :
14 : : #include "sd-daemon.h"
15 : : #include "sd-journal.h"
16 : : #include "sd-login.h"
17 : : #include "sd-messages.h"
18 : :
19 : : #include "acl-util.h"
20 : : #include "alloc-util.h"
21 : : #include "capability-util.h"
22 : : #include "cgroup-util.h"
23 : : #include "compress.h"
24 : : #include "conf-parser.h"
25 : : #include "copy.h"
26 : : #include "coredump-vacuum.h"
27 : : #include "dirent-util.h"
28 : : #include "escape.h"
29 : : #include "fd-util.h"
30 : : #include "fileio.h"
31 : : #include "fs-util.h"
32 : : #include "io-util.h"
33 : : #include "journal-importer.h"
34 : : #include "log.h"
35 : : #include "macro.h"
36 : : #include "main-func.h"
37 : : #include "memory-util.h"
38 : : #include "missing.h"
39 : : #include "mkdir.h"
40 : : #include "parse-util.h"
41 : : #include "process-util.h"
42 : : #include "signal-util.h"
43 : : #include "socket-util.h"
44 : : #include "special.h"
45 : : #include "stacktrace.h"
46 : : #include "string-table.h"
47 : : #include "string-util.h"
48 : : #include "strv.h"
49 : : #include "tmpfile-util.h"
50 : : #include "user-util.h"
51 : :
52 : : /* The maximum size up to which we process coredumps */
53 : : #define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU))
54 : :
55 : : /* The maximum size up to which we leave the coredump around on disk */
56 : : #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
57 : :
58 : : /* The maximum size up to which we store the coredump in the journal */
59 : : #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
60 : : #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
61 : : #else
62 : : /* oss-fuzz limits memory usage. */
63 : : #define JOURNAL_SIZE_MAX ((size_t) (10LU*1024LU*1024LU))
64 : : #endif
65 : :
66 : : /* Make sure to not make this larger than the maximum journal entry
67 : : * size. See DATA_SIZE_MAX in journal-importer.h. */
68 : : assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
69 : :
70 : : enum {
71 : : /* We use these as array indexes for our process metadata cache.
72 : : *
73 : : * The first indices of the cache stores the same metadata as the ones passed by
74 : : * the kernel via argv[], ie the strings array passed by the kernel according to
75 : : * our pattern defined in /proc/sys/kernel/core_pattern (see man:core(5)). */
76 : :
77 : : META_ARGV_PID, /* %P: as seen in the initial pid namespace */
78 : : META_ARGV_UID, /* %u: as seen in the initial user namespace */
79 : : META_ARGV_GID, /* %g: as seen in the initial user namespace */
80 : : META_ARGV_SIGNAL, /* %s: number of signal causing dump */
81 : : META_ARGV_TIMESTAMP, /* %t: time of dump, expressed as seconds since the Epoch */
82 : : META_ARGV_RLIMIT, /* %c: core file size soft resource limit */
83 : : META_ARGV_HOSTNAME, /* %h: hostname */
84 : : _META_ARGV_MAX,
85 : :
86 : : /* The following indexes are cached for a couple of special fields we use (and
87 : : * thereby need to be retrieved quickly) for naming coredump files, and attaching
88 : : * xattrs. Unlike the previous ones they are retrieved from the runtime
89 : : * environment. */
90 : :
91 : : META_COMM = _META_ARGV_MAX,
92 : : _META_MANDATORY_MAX,
93 : :
94 : : /* The rest are similar to the previous ones except that we won't fail if one of
95 : : * them is missing. */
96 : :
97 : : META_EXE = _META_MANDATORY_MAX,
98 : : META_UNIT,
99 : : _META_MAX
100 : : };
101 : :
102 : : static const char * const meta_field_names[_META_MAX] = {
103 : : [META_ARGV_PID] = "COREDUMP_PID=",
104 : : [META_ARGV_UID] = "COREDUMP_UID=",
105 : : [META_ARGV_GID] = "COREDUMP_GID=",
106 : : [META_ARGV_SIGNAL] = "COREDUMP_SIGNAL=",
107 : : [META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
108 : : [META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
109 : : [META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
110 : : [META_COMM] = "COREDUMP_COMM=",
111 : : [META_EXE] = "COREDUMP_EXE=",
112 : : [META_UNIT] = "COREDUMP_UNIT=",
113 : : };
114 : :
115 : : typedef struct Context {
116 : : const char *meta[_META_MAX];
117 : : pid_t pid;
118 : : bool is_pid1;
119 : : bool is_journald;
120 : : } Context;
121 : :
122 : : typedef enum CoredumpStorage {
123 : : COREDUMP_STORAGE_NONE,
124 : : COREDUMP_STORAGE_EXTERNAL,
125 : : COREDUMP_STORAGE_JOURNAL,
126 : : _COREDUMP_STORAGE_MAX,
127 : : _COREDUMP_STORAGE_INVALID = -1
128 : : } CoredumpStorage;
129 : :
130 : : static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
131 : : [COREDUMP_STORAGE_NONE] = "none",
132 : : [COREDUMP_STORAGE_EXTERNAL] = "external",
133 : : [COREDUMP_STORAGE_JOURNAL] = "journal",
134 : : };
135 : :
136 [ # # # # ]: 0 : DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
137 [ # # # # : 0 : static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
# # # # #
# # # ]
138 : :
139 : : static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
140 : : static bool arg_compress = true;
141 : : static uint64_t arg_process_size_max = PROCESS_SIZE_MAX;
142 : : static uint64_t arg_external_size_max = EXTERNAL_SIZE_MAX;
143 : : static uint64_t arg_journal_size_max = JOURNAL_SIZE_MAX;
144 : : static uint64_t arg_keep_free = (uint64_t) -1;
145 : : static uint64_t arg_max_use = (uint64_t) -1;
146 : :
147 : 0 : static int parse_config(void) {
148 : : static const ConfigTableItem items[] = {
149 : : { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
150 : : { "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
151 : : { "Coredump", "ProcessSizeMax", config_parse_iec_uint64, 0, &arg_process_size_max },
152 : : { "Coredump", "ExternalSizeMax", config_parse_iec_uint64, 0, &arg_external_size_max },
153 : : { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
154 : : { "Coredump", "KeepFree", config_parse_iec_uint64, 0, &arg_keep_free },
155 : : { "Coredump", "MaxUse", config_parse_iec_uint64, 0, &arg_max_use },
156 : : {}
157 : : };
158 : :
159 : 0 : return config_parse_many_nulstr(PKGSYSCONFDIR "/coredump.conf",
160 : : CONF_PATHS_NULSTR("systemd/coredump.conf.d"),
161 : : "Coredump\0",
162 : : config_item_table_lookup, items,
163 : : CONFIG_PARSE_WARN, NULL);
164 : : }
165 : :
166 : 0 : static uint64_t storage_size_max(void) {
167 [ # # ]: 0 : if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
168 : 0 : return arg_external_size_max;
169 [ # # ]: 0 : if (arg_storage == COREDUMP_STORAGE_JOURNAL)
170 : 0 : return arg_journal_size_max;
171 [ # # ]: 0 : assert(arg_storage == COREDUMP_STORAGE_NONE);
172 : 0 : return 0;
173 : : }
174 : :
175 : 0 : static int fix_acl(int fd, uid_t uid) {
176 : :
177 : : #if HAVE_ACL
178 : 0 : _cleanup_(acl_freep) acl_t acl = NULL;
179 : : acl_entry_t entry;
180 : : acl_permset_t permset;
181 : : int r;
182 : :
183 [ # # ]: 0 : assert(fd >= 0);
184 : :
185 [ # # # # : 0 : if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
# # ]
186 : 0 : return 0;
187 : :
188 : : /* Make sure normal users can read (but not write or delete)
189 : : * their own coredumps */
190 : :
191 : 0 : acl = acl_get_fd(fd);
192 [ # # ]: 0 : if (!acl)
193 [ # # ]: 0 : return log_error_errno(errno, "Failed to get ACL: %m");
194 : :
195 [ # # # # ]: 0 : if (acl_create_entry(&acl, &entry) < 0 ||
196 [ # # ]: 0 : acl_set_tag_type(entry, ACL_USER) < 0 ||
197 : 0 : acl_set_qualifier(entry, &uid) < 0)
198 [ # # ]: 0 : return log_error_errno(errno, "Failed to patch ACL: %m");
199 : :
200 [ # # # # ]: 0 : if (acl_get_permset(entry, &permset) < 0 ||
201 : 0 : acl_add_perm(permset, ACL_READ) < 0)
202 [ # # ]: 0 : return log_warning_errno(errno, "Failed to patch ACL: %m");
203 : :
204 : 0 : r = calc_acl_mask_if_needed(&acl);
205 [ # # ]: 0 : if (r < 0)
206 [ # # ]: 0 : return log_warning_errno(r, "Failed to patch ACL: %m");
207 : :
208 [ # # ]: 0 : if (acl_set_fd(fd, acl) < 0)
209 [ # # ]: 0 : return log_error_errno(errno, "Failed to apply ACL: %m");
210 : : #endif
211 : :
212 : 0 : return 0;
213 : : }
214 : :
215 : 0 : static int fix_xattr(int fd, const Context *context) {
216 : :
217 : : static const char * const xattrs[_META_MAX] = {
218 : : [META_ARGV_PID] = "user.coredump.pid",
219 : : [META_ARGV_UID] = "user.coredump.uid",
220 : : [META_ARGV_GID] = "user.coredump.gid",
221 : : [META_ARGV_SIGNAL] = "user.coredump.signal",
222 : : [META_ARGV_TIMESTAMP] = "user.coredump.timestamp",
223 : : [META_ARGV_RLIMIT] = "user.coredump.rlimit",
224 : : [META_ARGV_HOSTNAME] = "user.coredump.hostname",
225 : : [META_COMM] = "user.coredump.comm",
226 : : [META_EXE] = "user.coredump.exe",
227 : : };
228 : :
229 : 0 : int r = 0;
230 : : unsigned i;
231 : :
232 [ # # ]: 0 : assert(fd >= 0);
233 : :
234 : : /* Attach some metadata to coredumps via extended
235 : : * attributes. Just because we can. */
236 : :
237 [ # # ]: 0 : for (i = 0; i < _META_MAX; i++) {
238 : : int k;
239 : :
240 [ # # # # ]: 0 : if (isempty(context->meta[i]) || !xattrs[i])
241 : 0 : continue;
242 : :
243 : 0 : k = fsetxattr(fd, xattrs[i], context->meta[i], strlen(context->meta[i]), XATTR_CREATE);
244 [ # # # # ]: 0 : if (k < 0 && r == 0)
245 : 0 : r = -errno;
246 : : }
247 : :
248 : 0 : return r;
249 : : }
250 : :
251 : : #define filename_escape(s) xescape((s), "./ ")
252 : :
253 : 0 : static const char *coredump_tmpfile_name(const char *s) {
254 [ # # ]: 0 : return s ? s : "(unnamed temporary file)";
255 : : }
256 : :
257 : 0 : static int fix_permissions(
258 : : int fd,
259 : : const char *filename,
260 : : const char *target,
261 : : const Context *context,
262 : : uid_t uid) {
263 : :
264 : : int r;
265 : :
266 [ # # ]: 0 : assert(fd >= 0);
267 [ # # ]: 0 : assert(target);
268 [ # # ]: 0 : assert(context);
269 : :
270 : : /* Ignore errors on these */
271 : 0 : (void) fchmod(fd, 0640);
272 : 0 : (void) fix_acl(fd, uid);
273 : 0 : (void) fix_xattr(fd, context);
274 : :
275 [ # # ]: 0 : if (fsync(fd) < 0)
276 [ # # ]: 0 : return log_error_errno(errno, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename));
277 : :
278 : 0 : (void) fsync_directory_of_file(fd);
279 : :
280 : 0 : r = link_tmpfile(fd, filename, target);
281 [ # # ]: 0 : if (r < 0)
282 [ # # ]: 0 : return log_error_errno(r, "Failed to move coredump %s into place: %m", target);
283 : :
284 : 0 : return 0;
285 : : }
286 : :
287 : 0 : static int maybe_remove_external_coredump(const char *filename, uint64_t size) {
288 : :
289 : : /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
290 : :
291 [ # # ]: 0 : if (arg_storage == COREDUMP_STORAGE_EXTERNAL &&
292 [ # # ]: 0 : size <= arg_external_size_max)
293 : 0 : return 0;
294 : :
295 [ # # ]: 0 : if (!filename)
296 : 0 : return 1;
297 : :
298 [ # # # # ]: 0 : if (unlink(filename) < 0 && errno != ENOENT)
299 [ # # ]: 0 : return log_error_errno(errno, "Failed to unlink %s: %m", filename);
300 : :
301 : 0 : return 1;
302 : : }
303 : :
304 : 0 : static int make_filename(const Context *context, char **ret) {
305 : 0 : _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
306 : 0 : sd_id128_t boot = {};
307 : : int r;
308 : :
309 [ # # ]: 0 : assert(context);
310 : :
311 : 0 : c = filename_escape(context->meta[META_COMM]);
312 [ # # ]: 0 : if (!c)
313 : 0 : return -ENOMEM;
314 : :
315 : 0 : u = filename_escape(context->meta[META_ARGV_UID]);
316 [ # # ]: 0 : if (!u)
317 : 0 : return -ENOMEM;
318 : :
319 : 0 : r = sd_id128_get_boot(&boot);
320 [ # # ]: 0 : if (r < 0)
321 : 0 : return r;
322 : :
323 : 0 : p = filename_escape(context->meta[META_ARGV_PID]);
324 [ # # ]: 0 : if (!p)
325 : 0 : return -ENOMEM;
326 : :
327 : 0 : t = filename_escape(context->meta[META_ARGV_TIMESTAMP]);
328 [ # # ]: 0 : if (!t)
329 : 0 : return -ENOMEM;
330 : :
331 [ # # ]: 0 : if (asprintf(ret,
332 : : "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
333 : : c,
334 : : u,
335 : 0 : SD_ID128_FORMAT_VAL(boot),
336 : : p,
337 : : t) < 0)
338 : 0 : return -ENOMEM;
339 : :
340 : 0 : return 0;
341 : : }
342 : :
343 : 0 : static int save_external_coredump(
344 : : const Context *context,
345 : : int input_fd,
346 : : char **ret_filename,
347 : : int *ret_node_fd,
348 : : int *ret_data_fd,
349 : : uint64_t *ret_size,
350 : : bool *ret_truncated) {
351 : :
352 : 0 : _cleanup_free_ char *fn = NULL, *tmp = NULL;
353 : 0 : _cleanup_close_ int fd = -1;
354 : : uint64_t rlimit, process_limit, max_size;
355 : : struct stat st;
356 : : uid_t uid;
357 : : int r;
358 : :
359 [ # # ]: 0 : assert(context);
360 [ # # ]: 0 : assert(ret_filename);
361 [ # # ]: 0 : assert(ret_node_fd);
362 [ # # ]: 0 : assert(ret_data_fd);
363 [ # # ]: 0 : assert(ret_size);
364 : :
365 : 0 : r = parse_uid(context->meta[META_ARGV_UID], &uid);
366 [ # # ]: 0 : if (r < 0)
367 [ # # ]: 0 : return log_error_errno(r, "Failed to parse UID: %m");
368 : :
369 : 0 : r = safe_atou64(context->meta[META_ARGV_RLIMIT], &rlimit);
370 [ # # ]: 0 : if (r < 0)
371 [ # # ]: 0 : return log_error_errno(r, "Failed to parse resource limit '%s': %m",
372 : : context->meta[META_ARGV_RLIMIT]);
373 [ # # ]: 0 : if (rlimit < page_size()) {
374 : : /* Is coredumping disabled? Then don't bother saving/processing the
375 : : * coredump. Anything below PAGE_SIZE cannot give a readable coredump
376 : : * (the kernel uses ELF_EXEC_PAGESIZE which is not easily accessible, but
377 : : * is usually the same as PAGE_SIZE. */
378 [ # # ]: 0 : return log_info_errno(SYNTHETIC_ERRNO(EBADSLT),
379 : : "Resource limits disable core dumping for process %s (%s).",
380 : : context->meta[META_ARGV_PID], context->meta[META_COMM]);
381 : : }
382 : :
383 : 0 : process_limit = MAX(arg_process_size_max, storage_size_max());
384 [ # # ]: 0 : if (process_limit == 0)
385 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EBADSLT),
386 : : "Limits for coredump processing and storage are both 0, not dumping core.");
387 : :
388 : : /* Never store more than the process configured, or than we actually shall keep or process */
389 : 0 : max_size = MIN(rlimit, process_limit);
390 : :
391 : 0 : r = make_filename(context, &fn);
392 [ # # ]: 0 : if (r < 0)
393 [ # # ]: 0 : return log_error_errno(r, "Failed to determine coredump file name: %m");
394 : :
395 : 0 : (void) mkdir_p_label("/var/lib/systemd/coredump", 0755);
396 : :
397 : 0 : fd = open_tmpfile_linkable(fn, O_RDWR|O_CLOEXEC, &tmp);
398 [ # # ]: 0 : if (fd < 0)
399 [ # # ]: 0 : return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn);
400 : :
401 : 0 : r = copy_bytes(input_fd, fd, max_size, 0);
402 [ # # ]: 0 : if (r < 0) {
403 [ # # ]: 0 : log_error_errno(r, "Cannot store coredump of %s (%s): %m",
404 : : context->meta[META_ARGV_PID], context->meta[META_COMM]);
405 : 0 : goto fail;
406 : : }
407 : 0 : *ret_truncated = r == 1;
408 [ # # ]: 0 : if (*ret_truncated)
409 : 0 : log_struct(LOG_INFO,
410 : : LOG_MESSAGE("Core file was truncated to %zu bytes.", max_size),
411 : : "SIZE_LIMIT=%zu", max_size,
412 : : "MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR);
413 : :
414 [ # # ]: 0 : if (fstat(fd, &st) < 0) {
415 [ # # ]: 0 : log_error_errno(errno, "Failed to fstat core file %s: %m", coredump_tmpfile_name(tmp));
416 : 0 : goto fail;
417 : : }
418 : :
419 [ # # ]: 0 : if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
420 [ # # ]: 0 : log_error_errno(errno, "Failed to seek on %s: %m", coredump_tmpfile_name(tmp));
421 : 0 : goto fail;
422 : : }
423 : :
424 : : #if HAVE_XZ || HAVE_LZ4
425 : : /* If we will remove the coredump anyway, do not compress. */
426 [ # # # # ]: 0 : if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) {
427 : :
428 [ # # # # : 0 : _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
# # ]
429 [ # # # ]: 0 : _cleanup_close_ int fd_compressed = -1;
430 : :
431 : 0 : fn_compressed = strjoin(fn, COMPRESSED_EXT);
432 [ # # ]: 0 : if (!fn_compressed) {
433 : 0 : log_oom();
434 : 0 : goto uncompressed;
435 : : }
436 : :
437 : 0 : fd_compressed = open_tmpfile_linkable(fn_compressed, O_RDWR|O_CLOEXEC, &tmp_compressed);
438 [ # # ]: 0 : if (fd_compressed < 0) {
439 [ # # ]: 0 : log_error_errno(fd_compressed, "Failed to create temporary file for coredump %s: %m", fn_compressed);
440 : 0 : goto uncompressed;
441 : : }
442 : :
443 : 0 : r = compress_stream(fd, fd_compressed, -1);
444 [ # # ]: 0 : if (r < 0) {
445 [ # # ]: 0 : log_error_errno(r, "Failed to compress %s: %m", coredump_tmpfile_name(tmp_compressed));
446 : 0 : goto fail_compressed;
447 : : }
448 : :
449 : 0 : r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid);
450 [ # # ]: 0 : if (r < 0)
451 : 0 : goto fail_compressed;
452 : :
453 : : /* OK, this worked, we can get rid of the uncompressed version now */
454 [ # # ]: 0 : if (tmp)
455 : 0 : unlink_noerrno(tmp);
456 : :
457 : 0 : *ret_filename = TAKE_PTR(fn_compressed); /* compressed */
458 : 0 : *ret_node_fd = TAKE_FD(fd_compressed); /* compressed */
459 : 0 : *ret_data_fd = TAKE_FD(fd); /* uncompressed */
460 : 0 : *ret_size = (uint64_t) st.st_size; /* uncompressed */
461 : :
462 : 0 : return 0;
463 : :
464 : 0 : fail_compressed:
465 [ # # ]: 0 : if (tmp_compressed)
466 : 0 : (void) unlink(tmp_compressed);
467 : : }
468 : :
469 : 0 : uncompressed:
470 : : #endif
471 : :
472 : 0 : r = fix_permissions(fd, tmp, fn, context, uid);
473 [ # # ]: 0 : if (r < 0)
474 : 0 : goto fail;
475 : :
476 : 0 : *ret_filename = TAKE_PTR(fn);
477 : 0 : *ret_data_fd = TAKE_FD(fd);
478 : 0 : *ret_node_fd = -1;
479 : 0 : *ret_size = (uint64_t) st.st_size;
480 : :
481 : 0 : return 0;
482 : :
483 : 0 : fail:
484 [ # # ]: 0 : if (tmp)
485 : 0 : (void) unlink(tmp);
486 : 0 : return r;
487 : : }
488 : :
489 : 0 : static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
490 : 0 : _cleanup_free_ char *field = NULL;
491 : : ssize_t n;
492 : :
493 [ # # ]: 0 : assert(fd >= 0);
494 [ # # ]: 0 : assert(ret);
495 [ # # ]: 0 : assert(ret_size);
496 : :
497 [ # # ]: 0 : if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
498 [ # # ]: 0 : return log_warning_errno(errno, "Failed to seek: %m");
499 : :
500 : 0 : field = malloc(9 + size);
501 [ # # ]: 0 : if (!field) {
502 [ # # ]: 0 : log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
503 : 0 : return -ENOMEM;
504 : : }
505 : :
506 : 0 : memcpy(field, "COREDUMP=", 9);
507 : :
508 : 0 : n = read(fd, field + 9, size);
509 [ # # ]: 0 : if (n < 0)
510 [ # # ]: 0 : return log_error_errno((int) n, "Failed to read core data: %m");
511 [ # # ]: 0 : if ((size_t) n < size)
512 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EIO),
513 : : "Core data too short.");
514 : :
515 : 0 : *ret = TAKE_PTR(field);
516 : 0 : *ret_size = size + 9;
517 : :
518 : 0 : return 0;
519 : : }
520 : :
521 : : /* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
522 : : * 0:/dev/pts/23
523 : : * pos: 0
524 : : * flags: 0100002
525 : : *
526 : : * 1:/dev/pts/23
527 : : * pos: 0
528 : : * flags: 0100002
529 : : *
530 : : * 2:/dev/pts/23
531 : : * pos: 0
532 : : * flags: 0100002
533 : : * EOF
534 : : */
535 : 0 : static int compose_open_fds(pid_t pid, char **open_fds) {
536 : 0 : _cleanup_closedir_ DIR *proc_fd_dir = NULL;
537 : 0 : _cleanup_close_ int proc_fdinfo_fd = -1;
538 : 0 : _cleanup_free_ char *buffer = NULL;
539 : 0 : _cleanup_fclose_ FILE *stream = NULL;
540 : 0 : const char *fddelim = "", *path;
541 : 0 : struct dirent *dent = NULL;
542 : 0 : size_t size = 0;
543 : : int r;
544 : :
545 [ # # ]: 0 : assert(pid >= 0);
546 [ # # ]: 0 : assert(open_fds != NULL);
547 : :
548 [ # # # # : 0 : path = procfs_file_alloca(pid, "fd");
# # ]
549 : 0 : proc_fd_dir = opendir(path);
550 [ # # ]: 0 : if (!proc_fd_dir)
551 : 0 : return -errno;
552 : :
553 : 0 : proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo", O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
554 [ # # ]: 0 : if (proc_fdinfo_fd < 0)
555 : 0 : return -errno;
556 : :
557 : 0 : stream = open_memstream_unlocked(&buffer, &size);
558 [ # # ]: 0 : if (!stream)
559 : 0 : return -ENOMEM;
560 : :
561 [ # # # # : 0 : FOREACH_DIRENT(dent, proc_fd_dir, return -errno) {
# # ]
562 [ # # # ]: 0 : _cleanup_fclose_ FILE *fdinfo = NULL;
563 [ # # # ]: 0 : _cleanup_free_ char *fdname = NULL;
564 : : int fd;
565 : :
566 : 0 : r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
567 [ # # ]: 0 : if (r < 0)
568 : 0 : return r;
569 : :
570 : 0 : fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
571 : 0 : fddelim = "\n";
572 : :
573 : : /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
574 : 0 : fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
575 [ # # ]: 0 : if (fd < 0)
576 : 0 : continue;
577 : :
578 : 0 : fdinfo = fdopen(fd, "r");
579 [ # # ]: 0 : if (!fdinfo) {
580 : 0 : safe_close(fd);
581 : 0 : continue;
582 : : }
583 : :
584 : 0 : for (;;) {
585 [ # # # ]: 0 : _cleanup_free_ char *line = NULL;
586 : :
587 : 0 : r = read_line(fdinfo, LONG_LINE_MAX, &line);
588 [ # # ]: 0 : if (r < 0)
589 : 0 : return r;
590 [ # # ]: 0 : if (r == 0)
591 : 0 : break;
592 : :
593 : 0 : fputs(line, stream);
594 : 0 : fputc('\n', stream);
595 : : }
596 : : }
597 : :
598 : 0 : errno = 0;
599 : 0 : stream = safe_fclose(stream);
600 : :
601 [ # # ]: 0 : if (errno > 0)
602 : 0 : return -errno;
603 : :
604 : 0 : *open_fds = TAKE_PTR(buffer);
605 : :
606 : 0 : return 0;
607 : : }
608 : :
609 : 0 : static int get_process_ns(pid_t pid, const char *namespace, ino_t *ns) {
610 : : const char *p;
611 : : struct stat stbuf;
612 : 0 : _cleanup_close_ int proc_ns_dir_fd;
613 : :
614 [ # # # # : 0 : p = procfs_file_alloca(pid, "ns");
# # ]
615 : :
616 : 0 : proc_ns_dir_fd = open(p, O_DIRECTORY | O_CLOEXEC | O_RDONLY);
617 [ # # ]: 0 : if (proc_ns_dir_fd < 0)
618 : 0 : return -errno;
619 : :
620 [ # # ]: 0 : if (fstatat(proc_ns_dir_fd, namespace, &stbuf, /* flags */0) < 0)
621 : 0 : return -errno;
622 : :
623 : 0 : *ns = stbuf.st_ino;
624 : 0 : return 0;
625 : : }
626 : :
627 : 0 : static int get_mount_namespace_leader(pid_t pid, pid_t *container_pid) {
628 : 0 : pid_t cpid = pid, ppid = 0;
629 : : ino_t proc_mntns;
630 : 0 : int r = 0;
631 : :
632 : 0 : r = get_process_ns(pid, "mnt", &proc_mntns);
633 [ # # ]: 0 : if (r < 0)
634 : 0 : return r;
635 : :
636 : 0 : for (;;) {
637 : : ino_t parent_mntns;
638 : :
639 : 0 : r = get_process_ppid(cpid, &ppid);
640 [ # # ]: 0 : if (r < 0)
641 : 0 : return r;
642 : :
643 : 0 : r = get_process_ns(ppid, "mnt", &parent_mntns);
644 [ # # ]: 0 : if (r < 0)
645 : 0 : return r;
646 : :
647 [ # # ]: 0 : if (proc_mntns != parent_mntns)
648 : 0 : break;
649 : :
650 [ # # ]: 0 : if (ppid == 1)
651 : 0 : return -ENOENT;
652 : :
653 : 0 : cpid = ppid;
654 : : }
655 : :
656 : 0 : *container_pid = ppid;
657 : 0 : return 0;
658 : : }
659 : :
660 : : /* Returns 1 if the parent was found.
661 : : * Returns 0 if there is not a process we can call the pid's
662 : : * container parent (the pid's process isn't 'containerized').
663 : : * Returns a negative number on errors.
664 : : */
665 : 0 : static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) {
666 : 0 : int r = 0;
667 : : pid_t container_pid;
668 : : const char *proc_root_path;
669 : : struct stat root_stat, proc_root_stat;
670 : :
671 : : /* To compare inodes of / and /proc/[pid]/root */
672 [ # # ]: 0 : if (stat("/", &root_stat) < 0)
673 : 0 : return -errno;
674 : :
675 [ # # # # : 0 : proc_root_path = procfs_file_alloca(pid, "root");
# # ]
676 [ # # ]: 0 : if (stat(proc_root_path, &proc_root_stat) < 0)
677 : 0 : return -errno;
678 : :
679 : : /* The process uses system root. */
680 [ # # ]: 0 : if (proc_root_stat.st_ino == root_stat.st_ino) {
681 : 0 : *cmdline = NULL;
682 : 0 : return 0;
683 : : }
684 : :
685 : 0 : r = get_mount_namespace_leader(pid, &container_pid);
686 [ # # ]: 0 : if (r < 0)
687 : 0 : return r;
688 : :
689 : 0 : r = get_process_cmdline(container_pid, SIZE_MAX, 0, cmdline);
690 [ # # ]: 0 : if (r < 0)
691 : 0 : return r;
692 : :
693 : 0 : return 1;
694 : : }
695 : :
696 : 0 : static int change_uid_gid(const Context *context) {
697 : : uid_t uid;
698 : : gid_t gid;
699 : : int r;
700 : :
701 : 0 : r = parse_uid(context->meta[META_ARGV_UID], &uid);
702 [ # # ]: 0 : if (r < 0)
703 : 0 : return r;
704 : :
705 [ # # ]: 0 : if (uid <= SYSTEM_UID_MAX) {
706 : 0 : const char *user = "systemd-coredump";
707 : :
708 : 0 : r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
709 [ # # ]: 0 : if (r < 0) {
710 [ # # ]: 0 : log_warning_errno(r, "Cannot resolve %s user. Proceeding to dump core as root: %m", user);
711 : 0 : uid = gid = 0;
712 : : }
713 : : } else {
714 : 0 : r = parse_gid(context->meta[META_ARGV_GID], &gid);
715 [ # # ]: 0 : if (r < 0)
716 : 0 : return r;
717 : : }
718 : :
719 : 0 : return drop_privileges(uid, gid, 0);
720 : : }
721 : :
722 : 0 : static int submit_coredump(
723 : : Context *context,
724 : : struct iovec_wrapper *iovw,
725 : : int input_fd) {
726 : :
727 : 0 : _cleanup_close_ int coredump_fd = -1, coredump_node_fd = -1;
728 : 0 : _cleanup_free_ char *filename = NULL, *coredump_data = NULL;
729 : 0 : _cleanup_free_ char *stacktrace = NULL;
730 : : char *core_message;
731 : 0 : uint64_t coredump_size = UINT64_MAX;
732 : 0 : bool truncated = false;
733 : : int r;
734 : :
735 [ # # ]: 0 : assert(context);
736 [ # # ]: 0 : assert(iovw);
737 [ # # ]: 0 : assert(input_fd >= 0);
738 : :
739 : : /* Vacuum before we write anything again */
740 : 0 : (void) coredump_vacuum(-1, arg_keep_free, arg_max_use);
741 : :
742 : : /* Always stream the coredump to disk, if that's possible */
743 : 0 : r = save_external_coredump(context, input_fd,
744 : : &filename, &coredump_node_fd, &coredump_fd, &coredump_size, &truncated);
745 [ # # ]: 0 : if (r < 0)
746 : : /* Skip whole core dumping part */
747 : 0 : goto log;
748 : :
749 : : /* If we don't want to keep the coredump on disk, remove it now, as later on we
750 : : * will lack the privileges for it. However, we keep the fd to it, so that we can
751 : : * still process it and log it. */
752 : 0 : r = maybe_remove_external_coredump(filename, coredump_size);
753 [ # # ]: 0 : if (r < 0)
754 : 0 : return r;
755 [ # # ]: 0 : if (r == 0) {
756 : 0 : (void) iovw_put_string_field(iovw, "COREDUMP_FILENAME=", filename);
757 : :
758 [ # # ]: 0 : } else if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
759 [ # # ]: 0 : log_info("The core will not be stored: size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
760 : : coredump_size, arg_external_size_max);
761 : :
762 : : /* Vacuum again, but exclude the coredump we just created */
763 [ # # ]: 0 : (void) coredump_vacuum(coredump_node_fd >= 0 ? coredump_node_fd : coredump_fd, arg_keep_free, arg_max_use);
764 : :
765 : : /* Now, let's drop privileges to become the user who owns the segfaulted process
766 : : * and allocate the coredump memory under the user's uid. This also ensures that
767 : : * the credentials journald will see are the ones of the coredumping user, thus
768 : : * making sure the user gets access to the core dump. Let's also get rid of all
769 : : * capabilities, if we run as root, we won't need them anymore. */
770 : 0 : r = change_uid_gid(context);
771 [ # # ]: 0 : if (r < 0)
772 [ # # ]: 0 : return log_error_errno(r, "Failed to drop privileges: %m");
773 : :
774 : : #if HAVE_ELFUTILS
775 : : /* Try to get a stack trace if we can */
776 [ # # ]: 0 : if (coredump_size > arg_process_size_max) {
777 [ # # ]: 0 : log_debug("Not generating stack trace: core size %"PRIu64" is greater "
778 : : "than %"PRIu64" (the configured maximum)",
779 : : coredump_size, arg_process_size_max);
780 : : } else
781 : 0 : coredump_make_stack_trace(coredump_fd, context->meta[META_EXE], &stacktrace);
782 : : #endif
783 : :
784 : 0 : log:
785 [ # # # # : 0 : core_message = strjoina("Process ", context->meta[META_ARGV_PID],
# # # # #
# # # # #
# # # # #
# ]
786 : : " (", context->meta[META_COMM], ") of user ",
787 : : context->meta[META_ARGV_UID], " dumped core.",
788 : : context->is_journald && filename ? "\nCoredump diverted to " : NULL,
789 : : context->is_journald && filename ? filename : NULL);
790 : :
791 [ # # # # : 0 : core_message = strjoina(core_message, stacktrace ? "\n\n" : NULL, stacktrace);
# # # # #
# # # #
# ]
792 : :
793 [ # # ]: 0 : if (context->is_journald) {
794 : : /* We cannot log to the journal, so just print the message.
795 : : * The target was set previously to something safe. */
796 : 0 : log_dispatch(LOG_ERR, 0, core_message);
797 : 0 : return 0;
798 : : }
799 : :
800 : 0 : (void) iovw_put_string_field(iovw, "MESSAGE=", core_message);
801 : :
802 [ # # ]: 0 : if (truncated)
803 : 0 : (void) iovw_put_string_field(iovw, "COREDUMP_TRUNCATED=", "1");
804 : :
805 : : /* Optionally store the entire coredump in the journal */
806 [ # # ]: 0 : if (arg_storage == COREDUMP_STORAGE_JOURNAL) {
807 [ # # ]: 0 : if (coredump_size <= arg_journal_size_max) {
808 : 0 : size_t sz = 0;
809 : :
810 : : /* Store the coredump itself in the journal */
811 : :
812 : 0 : r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
813 [ # # ]: 0 : if (r >= 0) {
814 [ # # ]: 0 : if (iovw_put(iovw, coredump_data, sz) >= 0)
815 : 0 : TAKE_PTR(coredump_data);
816 : : } else
817 [ # # ]: 0 : log_warning_errno(r, "Failed to attach the core to the journal entry: %m");
818 : : } else
819 [ # # ]: 0 : log_info("The core will not be stored: size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
820 : : coredump_size, arg_journal_size_max);
821 : : }
822 : :
823 : 0 : r = sd_journal_sendv(iovw->iovec, iovw->count);
824 [ # # ]: 0 : if (r < 0)
825 [ # # ]: 0 : return log_error_errno(r, "Failed to log coredump: %m");
826 : :
827 : 0 : return 0;
828 : : }
829 : :
830 : 0 : static int save_context(Context *context, const struct iovec_wrapper *iovw) {
831 : 0 : unsigned n, i, count = 0;
832 : : const char *unit;
833 : : int r;
834 : :
835 [ # # ]: 0 : assert(context);
836 [ # # ]: 0 : assert(iovw);
837 [ # # ]: 0 : assert(iovw->count >= _META_ARGV_MAX);
838 : :
839 : : /* The context does not allocate any memory on its own */
840 : :
841 [ # # ]: 0 : for (n = 0; n < iovw->count; n++) {
842 : 0 : struct iovec *iovec = iovw->iovec + n;
843 : :
844 [ # # ]: 0 : for (i = 0; i < ELEMENTSOF(meta_field_names); i++) {
845 : : char *p;
846 : :
847 : : /* Note that these strings are NUL terminated, because we made sure that a
848 : : * trailing NUL byte is in the buffer, though not included in the iov_len
849 : : * count (see process_socket() and gather_pid_metadata_*()) */
850 [ # # ]: 0 : assert(((char*) iovec->iov_base)[iovec->iov_len] == 0);
851 : :
852 : 0 : p = startswith(iovec->iov_base, meta_field_names[i]);
853 [ # # ]: 0 : if (p) {
854 : 0 : context->meta[i] = p;
855 : 0 : count++;
856 : 0 : break;
857 : : }
858 : : }
859 : : }
860 : :
861 [ # # ]: 0 : if (!context->meta[META_ARGV_PID])
862 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
863 : : "Failed to find the PID of crashing process");
864 : :
865 : 0 : r = parse_pid(context->meta[META_ARGV_PID], &context->pid);
866 [ # # ]: 0 : if (r < 0)
867 [ # # ]: 0 : return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[META_ARGV_PID]);
868 : :
869 : 0 : unit = context->meta[META_UNIT];
870 [ # # # # ]: 0 : context->is_pid1 = streq(context->meta[META_ARGV_PID], "1") || streq_ptr(unit, SPECIAL_INIT_SCOPE);
871 : 0 : context->is_journald = streq_ptr(unit, SPECIAL_JOURNALD_SERVICE);
872 : :
873 : 0 : return 0;
874 : : }
875 : :
876 : 0 : static int process_socket(int fd) {
877 : 0 : _cleanup_close_ int input_fd = -1;
878 : 0 : Context context = {};
879 : 0 : struct iovec_wrapper iovw = {};
880 : : struct iovec iovec;
881 : : int i, r;
882 : :
883 [ # # ]: 0 : assert(fd >= 0);
884 : :
885 : 0 : log_setup_service();
886 : :
887 [ # # ]: 0 : log_debug("Processing coredump received on stdin...");
888 : :
889 : 0 : for (;;) {
890 : : union {
891 : : struct cmsghdr cmsghdr;
892 : : uint8_t buf[CMSG_SPACE(sizeof(int))];
893 : 0 : } control = {};
894 : 0 : struct msghdr mh = {
895 : : .msg_control = &control,
896 : : .msg_controllen = sizeof(control),
897 : : .msg_iovlen = 1,
898 : : };
899 : : ssize_t n;
900 : : ssize_t l;
901 : :
902 : 0 : l = next_datagram_size_fd(fd);
903 [ # # ]: 0 : if (l < 0) {
904 [ # # ]: 0 : r = log_error_errno(l, "Failed to determine datagram size to read: %m");
905 : 0 : goto finish;
906 : : }
907 : :
908 : 0 : iovec.iov_len = l;
909 : 0 : iovec.iov_base = malloc(l + 1);
910 [ # # ]: 0 : if (!iovec.iov_base) {
911 : 0 : r = log_oom();
912 : 0 : goto finish;
913 : : }
914 : :
915 : 0 : mh.msg_iov = &iovec;
916 : :
917 : 0 : n = recvmsg(fd, &mh, MSG_CMSG_CLOEXEC);
918 [ # # ]: 0 : if (n < 0) {
919 : 0 : free(iovec.iov_base);
920 [ # # ]: 0 : r = log_error_errno(errno, "Failed to receive datagram: %m");
921 : 0 : goto finish;
922 : : }
923 : :
924 : : /* The final zero-length datagram carries the file descriptor and tells us
925 : : * that we're done. */
926 [ # # ]: 0 : if (n == 0) {
927 : 0 : struct cmsghdr *cmsg, *found = NULL;
928 : :
929 : 0 : free(iovec.iov_base);
930 : :
931 [ # # # # ]: 0 : CMSG_FOREACH(cmsg, &mh) {
932 [ # # ]: 0 : if (cmsg->cmsg_level == SOL_SOCKET &&
933 [ # # ]: 0 : cmsg->cmsg_type == SCM_RIGHTS &&
934 [ # # ]: 0 : cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
935 [ # # ]: 0 : assert(!found);
936 : 0 : found = cmsg;
937 : : }
938 : : }
939 : :
940 [ # # ]: 0 : if (!found) {
941 [ # # ]: 0 : log_error("Coredump file descriptor missing.");
942 : 0 : r = -EBADMSG;
943 : 0 : goto finish;
944 : : }
945 : :
946 [ # # ]: 0 : assert(input_fd < 0);
947 : 0 : input_fd = *(int*) CMSG_DATA(found);
948 : 0 : break;
949 : : }
950 : :
951 : : /* Add trailing NUL byte, in case these are strings */
952 : 0 : ((char*) iovec.iov_base)[n] = 0;
953 : 0 : iovec.iov_len = (size_t) n;
954 : :
955 : 0 : r = iovw_put(&iovw, iovec.iov_base, iovec.iov_len);
956 [ # # ]: 0 : if (r < 0)
957 : 0 : goto finish;
958 : :
959 : 0 : cmsg_close_all(&mh);
960 : : }
961 : :
962 : : /* Make sure we got all data we really need */
963 [ # # ]: 0 : assert(input_fd >= 0);
964 : :
965 : 0 : r = save_context(&context, &iovw);
966 [ # # ]: 0 : if (r < 0)
967 : 0 : goto finish;
968 : :
969 : : /* Make sure we received at least all fields we need. */
970 [ # # ]: 0 : for (i = 0; i < _META_MANDATORY_MAX; i++)
971 [ # # ]: 0 : if (!context.meta[i]) {
972 [ # # ]: 0 : r = log_error_errno(SYNTHETIC_ERRNO(EINVAL),
973 : : "A mandatory argument (%i) has not been sent, aborting.",
974 : : i);
975 : 0 : goto finish;
976 : : }
977 : :
978 : 0 : r = submit_coredump(&context, &iovw, input_fd);
979 : :
980 : 0 : finish:
981 : 0 : iovw_free_contents(&iovw, true);
982 : 0 : return r;
983 : : }
984 : :
985 : 0 : static int send_iovec(const struct iovec_wrapper *iovw, int input_fd) {
986 : :
987 : : static const union sockaddr_union sa = {
988 : : .un.sun_family = AF_UNIX,
989 : : .un.sun_path = "/run/systemd/coredump",
990 : : };
991 : 0 : _cleanup_close_ int fd = -1;
992 : : size_t i;
993 : : int r;
994 : :
995 [ # # ]: 0 : assert(iovw);
996 [ # # ]: 0 : assert(input_fd >= 0);
997 : :
998 : 0 : fd = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0);
999 [ # # ]: 0 : if (fd < 0)
1000 [ # # ]: 0 : return log_error_errno(errno, "Failed to create coredump socket: %m");
1001 : :
1002 [ # # # # : 0 : if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
# # ]
1003 [ # # ]: 0 : return log_error_errno(errno, "Failed to connect to coredump service: %m");
1004 : :
1005 [ # # ]: 0 : for (i = 0; i < iovw->count; i++) {
1006 : 0 : struct msghdr mh = {
1007 : 0 : .msg_iov = iovw->iovec + i,
1008 : : .msg_iovlen = 1,
1009 : : };
1010 : : struct iovec copy[2];
1011 : :
1012 : : for (;;) {
1013 [ # # ]: 0 : if (sendmsg(fd, &mh, MSG_NOSIGNAL) >= 0)
1014 : 0 : break;
1015 : :
1016 [ # # # # ]: 0 : if (errno == EMSGSIZE && mh.msg_iov[0].iov_len > 0) {
1017 : : /* This field didn't fit? That's a pity. Given that this is
1018 : : * just metadata, let's truncate the field at half, and try
1019 : : * again. We append three dots, in order to show that this is
1020 : : * truncated. */
1021 : :
1022 [ # # ]: 0 : if (mh.msg_iov != copy) {
1023 : : /* We don't want to modify the caller's iovec, hence
1024 : : * let's create our own array, consisting of two new
1025 : : * iovecs, where the first is a (truncated) copy of
1026 : : * what we want to send, and the second one contains
1027 : : * the trailing dots. */
1028 : 0 : copy[0] = iovw->iovec[i];
1029 : 0 : copy[1] = IOVEC_MAKE(((char[]){'.', '.', '.'}), 3);
1030 : :
1031 : 0 : mh.msg_iov = copy;
1032 : 0 : mh.msg_iovlen = 2;
1033 : : }
1034 : :
1035 : 0 : copy[0].iov_len /= 2; /* halve it, and try again */
1036 : 0 : continue;
1037 : : }
1038 : :
1039 [ # # ]: 0 : return log_error_errno(errno, "Failed to send coredump datagram: %m");
1040 : : }
1041 : : }
1042 : :
1043 : 0 : r = send_one_fd(fd, input_fd, 0);
1044 [ # # ]: 0 : if (r < 0)
1045 [ # # ]: 0 : return log_error_errno(r, "Failed to send coredump fd: %m");
1046 : :
1047 : 0 : return 0;
1048 : : }
1049 : :
1050 : 0 : static int gather_pid_metadata_from_argv(struct iovec_wrapper *iovw, Context *context,
1051 : : int argc, char **argv) {
1052 : 0 : _cleanup_free_ char *free_timestamp = NULL;
1053 : : int i, r, signo;
1054 : : char *t;
1055 : :
1056 : : /* We gather all metadata that were passed via argv[] into an array of iovecs that
1057 : : * we'll forward to the socket unit */
1058 : :
1059 [ # # ]: 0 : if (argc < _META_ARGV_MAX)
1060 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1061 : : "Not enough arguments passed by the kernel (%i, expected %i).",
1062 : : argc, _META_ARGV_MAX);
1063 : :
1064 [ # # ]: 0 : for (i = 0; i < _META_ARGV_MAX; i++) {
1065 : :
1066 : 0 : t = argv[i];
1067 : :
1068 [ # # # ]: 0 : switch (i) {
1069 : 0 : case META_ARGV_TIMESTAMP:
1070 : : /* The journal fields contain the timestamp padded with six
1071 : : * zeroes, so that the kernel-supplied 1s granularity timestamps
1072 : : * becomes 1µs granularity, i.e. the granularity systemd usually
1073 : : * operates in. */
1074 : 0 : t = free_timestamp = strjoin(argv[i], "000000");
1075 [ # # ]: 0 : if (!t)
1076 : 0 : return log_oom();
1077 : 0 : break;
1078 : 0 : case META_ARGV_SIGNAL:
1079 : : /* For signal, record its pretty name too */
1080 [ # # # # ]: 0 : if (safe_atoi(argv[i], &signo) >= 0 && SIGNAL_VALID(signo))
1081 : 0 : (void) iovw_put_string_field(iovw, "COREDUMP_SIGNAL_NAME=SIG",
1082 : : signal_to_string(signo));
1083 : 0 : break;
1084 : 0 : default:
1085 : 0 : break;
1086 : : }
1087 : :
1088 : 0 : r = iovw_put_string_field(iovw, meta_field_names[i], t);
1089 [ # # ]: 0 : if (r < 0)
1090 : 0 : return r;
1091 : : }
1092 : :
1093 : : /* Cache some of the process metadata we collected so far and that we'll need to
1094 : : * access soon */
1095 : 0 : return save_context(context, iovw);
1096 : : }
1097 : :
1098 : 0 : static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
1099 : : uid_t owner_uid;
1100 : : pid_t pid;
1101 : : char *t;
1102 : : const char *p;
1103 : : int r;
1104 : :
1105 : : /* Note that if we fail on oom later on, we do not roll-back changes to the iovec
1106 : : * structure. (It remains valid, with the first iovec fields initialized.) */
1107 : :
1108 : 0 : pid = context->pid;
1109 : :
1110 : : /* The following is mandatory */
1111 : 0 : r = get_process_comm(pid, &t);
1112 [ # # ]: 0 : if (r < 0)
1113 [ # # ]: 0 : return log_error_errno(r, "Failed to get COMM: %m");
1114 : :
1115 : 0 : r = iovw_put_string_field_free(iovw, "COREDUMP_COMM=", t);
1116 [ # # ]: 0 : if (r < 0)
1117 : 0 : return r;
1118 : :
1119 : : /* The following are optional but we used them if present */
1120 : 0 : r = get_process_exe(pid, &t);
1121 [ # # ]: 0 : if (r >= 0)
1122 : 0 : r = iovw_put_string_field_free(iovw, "COREDUMP_EXE=", t);
1123 [ # # ]: 0 : if (r < 0)
1124 [ # # ]: 0 : log_warning_errno(r, "Failed to get EXE, ignoring: %m");
1125 : :
1126 [ # # ]: 0 : if (cg_pid_get_unit(pid, &t) >= 0)
1127 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_UNIT=", t);
1128 : :
1129 : : /* The next are optional */
1130 [ # # ]: 0 : if (cg_pid_get_user_unit(pid, &t) >= 0)
1131 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_USER_UNIT=", t);
1132 : :
1133 [ # # ]: 0 : if (sd_pid_get_session(pid, &t) >= 0)
1134 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_SESSION=", t);
1135 : :
1136 [ # # ]: 0 : if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
1137 : 0 : r = asprintf(&t, UID_FMT, owner_uid);
1138 [ # # ]: 0 : if (r > 0)
1139 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_OWNER_UID=", t);
1140 : : }
1141 : :
1142 [ # # ]: 0 : if (sd_pid_get_slice(pid, &t) >= 0)
1143 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_SLICE=", t);
1144 : :
1145 [ # # ]: 0 : if (get_process_cmdline(pid, SIZE_MAX, 0, &t) >= 0)
1146 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_CMDLINE=", t);
1147 : :
1148 [ # # ]: 0 : if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0)
1149 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_CGROUP=", t);
1150 : :
1151 [ # # ]: 0 : if (compose_open_fds(pid, &t) >= 0)
1152 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_OPEN_FDS=", t);
1153 : :
1154 [ # # # # : 0 : p = procfs_file_alloca(pid, "status");
# # ]
1155 [ # # ]: 0 : if (read_full_file(p, &t, NULL) >= 0)
1156 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_STATUS=", t);
1157 : :
1158 [ # # # # : 0 : p = procfs_file_alloca(pid, "maps");
# # ]
1159 [ # # ]: 0 : if (read_full_file(p, &t, NULL) >= 0)
1160 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_MAPS=", t);
1161 : :
1162 [ # # # # : 0 : p = procfs_file_alloca(pid, "limits");
# # ]
1163 [ # # ]: 0 : if (read_full_file(p, &t, NULL) >= 0)
1164 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_LIMITS=", t);
1165 : :
1166 [ # # # # : 0 : p = procfs_file_alloca(pid, "cgroup");
# # ]
1167 [ # # ]: 0 : if (read_full_file(p, &t, NULL) >=0)
1168 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_CGROUP=", t);
1169 : :
1170 [ # # # # : 0 : p = procfs_file_alloca(pid, "mountinfo");
# # ]
1171 [ # # ]: 0 : if (read_full_file(p, &t, NULL) >=0)
1172 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_MOUNTINFO=", t);
1173 : :
1174 [ # # ]: 0 : if (get_process_cwd(pid, &t) >= 0)
1175 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_CWD=", t);
1176 : :
1177 [ # # ]: 0 : if (get_process_root(pid, &t) >= 0) {
1178 : : bool proc_self_root_is_slash;
1179 : :
1180 : 0 : proc_self_root_is_slash = strcmp(t, "/") == 0;
1181 : :
1182 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_ROOT=", t);
1183 : :
1184 : : /* If the process' root is "/", then there is a chance it has
1185 : : * mounted own root and hence being containerized. */
1186 [ # # # # ]: 0 : if (proc_self_root_is_slash && get_process_container_parent_cmdline(pid, &t) > 0)
1187 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_CONTAINER_CMDLINE=", t);
1188 : : }
1189 : :
1190 [ # # ]: 0 : if (get_process_environ(pid, &t) >= 0)
1191 : 0 : (void) iovw_put_string_field_free(iovw, "COREDUMP_ENVIRON=", t);
1192 : :
1193 : : /* we successfully acquired all metadata */
1194 : 0 : return save_context(context, iovw);
1195 : : }
1196 : :
1197 : 0 : static int process_kernel(int argc, char* argv[]) {
1198 : 0 : Context context = {};
1199 : : struct iovec_wrapper *iovw;
1200 : : int r;
1201 : :
1202 [ # # ]: 0 : log_debug("Processing coredump received from the kernel...");
1203 : :
1204 : 0 : iovw = iovw_new();
1205 [ # # ]: 0 : if (!iovw)
1206 : 0 : return log_oom();
1207 : :
1208 : 0 : (void) iovw_put_string_field(iovw, "MESSAGE_ID=", SD_MESSAGE_COREDUMP_STR);
1209 : 0 : (void) iovw_put_string_field(iovw, "PRIORITY=", STRINGIFY(LOG_CRIT));
1210 : :
1211 : : /* Collect all process metadata passed by the kernel through argv[] */
1212 : 0 : r = gather_pid_metadata_from_argv(iovw, &context, argc - 1, argv + 1);
1213 [ # # ]: 0 : if (r < 0)
1214 : 0 : goto finish;
1215 : :
1216 : : /* Collect the rest of the process metadata retrieved from the runtime */
1217 : 0 : r = gather_pid_metadata(iovw, &context);
1218 [ # # ]: 0 : if (r < 0)
1219 : 0 : goto finish;
1220 : :
1221 [ # # ]: 0 : if (!context.is_journald) {
1222 : : /* OK, now we know it's not the journal, hence we can make use of it now. */
1223 : 0 : log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
1224 : 0 : log_open();
1225 : : }
1226 : :
1227 : : /* If this is PID 1 disable coredump collection, we'll unlikely be able to process
1228 : : * it later on.
1229 : : *
1230 : : * FIXME: maybe we should disable coredumps generation from the beginning and
1231 : : * re-enable it only when we know it's either safe (ie we're not running OOM) or
1232 : : * it's not pid1 ? */
1233 [ # # ]: 0 : if (context.is_pid1) {
1234 [ # # ]: 0 : log_notice("Due to PID 1 having crashed coredump collection will now be turned off.");
1235 : 0 : disable_coredumps();
1236 : : }
1237 : :
1238 [ # # # # ]: 0 : if (context.is_journald || context.is_pid1)
1239 : 0 : r = submit_coredump(&context, iovw, STDIN_FILENO);
1240 : : else
1241 : 0 : r = send_iovec(iovw, STDIN_FILENO);
1242 : :
1243 : 0 : finish:
1244 : 0 : iovw = iovw_free_free(iovw);
1245 : 0 : return r;
1246 : : }
1247 : :
1248 : 0 : static int process_backtrace(int argc, char *argv[]) {
1249 : 0 : Context context = {};
1250 : : struct iovec_wrapper *iovw;
1251 : : char *message;
1252 : : size_t i;
1253 : : int r;
1254 : 0 : _cleanup_(journal_importer_cleanup) JournalImporter importer = JOURNAL_IMPORTER_INIT(STDIN_FILENO);
1255 : :
1256 [ # # ]: 0 : log_debug("Processing backtrace on stdin...");
1257 : :
1258 : 0 : iovw = iovw_new();
1259 [ # # ]: 0 : if (!iovw)
1260 : 0 : return log_oom();
1261 : :
1262 : 0 : (void) iovw_put_string_field(iovw, "MESSAGE_ID=", SD_MESSAGE_BACKTRACE_STR);
1263 : 0 : (void) iovw_put_string_field(iovw, "PRIORITY=", STRINGIFY(LOG_CRIT));
1264 : :
1265 : : /* Collect all process metadata from argv[] by making sure to skip the
1266 : : * '--backtrace' option */
1267 : 0 : r = gather_pid_metadata_from_argv(iovw, &context, argc - 2, argv + 2);
1268 [ # # ]: 0 : if (r < 0)
1269 : 0 : goto finish;
1270 : :
1271 : : /* Collect the rest of the process metadata retrieved from the runtime */
1272 : 0 : r = gather_pid_metadata(iovw, &context);
1273 [ # # ]: 0 : if (r < 0)
1274 : 0 : goto finish;
1275 : :
1276 : : for (;;) {
1277 : 0 : r = journal_importer_process_data(&importer);
1278 [ # # ]: 0 : if (r < 0) {
1279 [ # # ]: 0 : log_error_errno(r, "Failed to parse journal entry on stdin: %m");
1280 : 0 : goto finish;
1281 : : }
1282 [ # # # # ]: 0 : if (r == 1 || /* complete entry */
1283 : 0 : journal_importer_eof(&importer)) /* end of data */
1284 : : break;
1285 : : }
1286 : :
1287 [ # # ]: 0 : if (journal_importer_eof(&importer)) {
1288 [ # # ]: 0 : log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter");
1289 : :
1290 [ # # # # : 0 : message = strjoina("Process ", context.meta[META_ARGV_PID],
# # # # #
# # # ]
1291 : : " (", context.meta[META_COMM], ")"
1292 : : " of user ", context.meta[META_ARGV_UID],
1293 : : " failed with ", context.meta[META_ARGV_SIGNAL]);
1294 : :
1295 : 0 : r = iovw_put_string_field(iovw, "MESSAGE=", message);
1296 [ # # ]: 0 : if (r < 0)
1297 : 0 : return r;
1298 : : } else {
1299 : : /* The imported iovecs are not supposed to be freed by us so let's store
1300 : : * them at the end of the array so we can skip them while freeing the
1301 : : * rest. */
1302 [ # # ]: 0 : for (i = 0; i < importer.iovw.count; i++) {
1303 : 0 : struct iovec *iovec = importer.iovw.iovec + i;
1304 : :
1305 : 0 : iovw_put(iovw, iovec->iov_base, iovec->iov_len);
1306 : : }
1307 : : }
1308 : :
1309 : 0 : r = sd_journal_sendv(iovw->iovec, iovw->count);
1310 [ # # ]: 0 : if (r < 0)
1311 [ # # ]: 0 : log_error_errno(r, "Failed to log backtrace: %m");
1312 : :
1313 : 0 : finish:
1314 : 0 : iovw->count -= importer.iovw.count;
1315 : 0 : iovw = iovw_free_free(iovw);
1316 : 0 : return r;
1317 : : }
1318 : :
1319 : 0 : static int run(int argc, char *argv[]) {
1320 : : int r;
1321 : :
1322 : : /* First, log to a safe place, since we don't know what crashed and it might
1323 : : * be journald which we'd rather not log to then. */
1324 : :
1325 : 0 : log_set_target(LOG_TARGET_KMSG);
1326 : 0 : log_open();
1327 : :
1328 : : /* Make sure we never enter a loop */
1329 : 0 : (void) prctl(PR_SET_DUMPABLE, 0);
1330 : :
1331 : : /* Ignore all parse errors */
1332 : 0 : (void) parse_config();
1333 : :
1334 [ # # ]: 0 : log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
1335 [ # # ]: 0 : log_debug("Selected compression %s.", yes_no(arg_compress));
1336 : :
1337 : 0 : r = sd_listen_fds(false);
1338 [ # # ]: 0 : if (r < 0)
1339 [ # # ]: 0 : return log_error_errno(r, "Failed to determine the number of file descriptors: %m");
1340 : :
1341 : : /* If we got an fd passed, we are running in coredumpd mode. Otherwise we
1342 : : * are invoked from the kernel as coredump handler. */
1343 [ # # ]: 0 : if (r == 0) {
1344 [ # # ]: 0 : if (streq_ptr(argv[1], "--backtrace"))
1345 : 0 : return process_backtrace(argc, argv);
1346 : : else
1347 : 0 : return process_kernel(argc, argv);
1348 [ # # ]: 0 : } else if (r == 1)
1349 : 0 : return process_socket(SD_LISTEN_FDS_START);
1350 : :
1351 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1352 : : "Received unexpected number of file descriptors.");
1353 : : }
1354 : :
1355 : 0 : DEFINE_MAIN_FUNCTION(run);
|