#include <sys/types.h>
#include <sys/xattr.h>
+#ifdef HAVE_ELFUTILS
+# include <dwarf.h>
+# include <elfutils/libdwfl.h>
+#endif
+
#include "systemd/sd-journal.h"
#include "systemd/sd-login.h"
#include "log.h"
#include "util.h"
+#include "fileio.h"
#include "strv.h"
#include "macro.h"
#include "mkdir.h"
}
r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
- if (r == -E2BIG) {
+ if (r == -EFBIG) {
log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
goto fail;
} else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
return 0;
}
+/* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
+ * 0:/dev/pts/23
+ * pos: 0
+ * flags: 0100002
+ *
+ * 1:/dev/pts/23
+ * pos: 0
+ * flags: 0100002
+ *
+ * 2:/dev/pts/23
+ * pos: 0
+ * flags: 0100002
+ * EOF
+ */
+static int compose_open_fds(pid_t pid, char **open_fds) {
+ _cleanup_fclose_ FILE *stream = NULL;
+ size_t ignored_size;
+ const char *fddelim = "", *path;
+ struct dirent *dent = NULL;
+ _cleanup_closedir_ DIR *proc_fd_dir = NULL;
+ _cleanup_close_ int proc_fdinfo_fd = -1;
+ int r = 0;
+
+ assert(pid >= 0);
+ assert(open_fds != NULL);
+
+ path = procfs_file_alloca(pid, "fd");
+ proc_fd_dir = opendir(path);
+ if (!proc_fd_dir)
+ return -errno;
+
+ proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo",
+ O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
+ if (proc_fdinfo_fd < 0)
+ return -errno;
+
+ stream = open_memstream(open_fds, &ignored_size);
+ if (!stream)
+ return -ENOMEM;
+
+ for (dent = readdir(proc_fd_dir); dent != NULL; dent = readdir(proc_fd_dir)) {
+ _cleanup_free_ char *fdname = NULL;
+ int fd;
+ _cleanup_fclose_ FILE *fdinfo = NULL;
+ char line[LINE_MAX];
+
+ if (dent->d_name[0] == '.' || strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
+ if (r < 0)
+ return r;
+
+ fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
+ fddelim = "\n";
+
+ /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
+ fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
+ if (fd < 0)
+ continue;
+
+ fdinfo = fdopen(fd, "re");
+ if (fdinfo == NULL) {
+ close(fd);
+ continue;
+ }
+
+ while(fgets(line, sizeof(line), fdinfo) != NULL)
+ fprintf(stream, "%s%s",
+ line, strchr(line, '\n') == NULL ? "\n" : "");
+ }
+
+ return 0;
+}
+
int main(int argc, char* argv[]) {
_cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
*core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
*core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
- *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
+ *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL, *core_open_fds = NULL,
+ *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL,
+ *core_cwd = NULL, *core_root = NULL, *core_environ = NULL,
*exe = NULL, *comm = NULL, *filename = NULL;
const char *info[_INFO_LEN];
_cleanup_close_ int coredump_fd = -1;
- struct iovec iovec[18];
+ struct iovec iovec[26];
off_t coredump_size;
int r, j = 0;
uid_t uid, owner_uid;
gid_t gid;
pid_t pid;
char *t;
+ const char *p;
/* Make sure we never enter a loop */
prctl(PR_SET_DUMPABLE, 0);
}
if (get_process_comm(pid, &comm) < 0) {
- log_warning("Failed to get COMM, falling back to the commandline.");
+ log_warning("Failed to get COMM, falling back to the command line.");
comm = strv_join(argv + INFO_COMM + 1, " ");
}
IOVEC_SET_STRING(iovec[j++], core_cgroup);
}
+ if (compose_open_fds(pid, &t) >= 0) {
+ core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
+ free(t);
+
+ if (core_open_fds)
+ IOVEC_SET_STRING(iovec[j++], core_open_fds);
+ }
+
+ p = procfs_file_alloca(pid, "status");
+ if (read_full_file(p, &t, NULL) >= 0) {
+ core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
+ free(t);
+
+ if (core_proc_status)
+ IOVEC_SET_STRING(iovec[j++], core_proc_status);
+ }
+
+ p = procfs_file_alloca(pid, "maps");
+ if (read_full_file(p, &t, NULL) >= 0) {
+ core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
+ free(t);
+
+ if (core_proc_maps)
+ IOVEC_SET_STRING(iovec[j++], core_proc_maps);
+ }
+
+ p = procfs_file_alloca(pid, "limits");
+ if (read_full_file(p, &t, NULL) >= 0) {
+ core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
+ free(t);
+
+ if (core_proc_limits)
+ IOVEC_SET_STRING(iovec[j++], core_proc_limits);
+ }
+
+ p = procfs_file_alloca(pid, "cgroup");
+ if (read_full_file(p, &t, NULL) >=0) {
+ core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
+ free(t);
+
+ if (core_proc_cgroup)
+ IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
+ }
+
+ if (get_process_cwd(pid, &t) >= 0) {
+ core_cwd = strappend("COREDUMP_CWD=", t);
+ free(t);
+
+ if (core_cwd)
+ IOVEC_SET_STRING(iovec[j++], core_cwd);
+ }
+
+ if (get_process_root(pid, &t) >= 0) {
+ core_root = strappend("COREDUMP_ROOT=", t);
+ free(t);
+
+ if (core_root)
+ IOVEC_SET_STRING(iovec[j++], core_root);
+ }
+
+ if (get_process_environ(pid, &t) >= 0) {
+ core_environ = strappend("COREDUMP_ENVIRON=", t);
+ free(t);
+
+ if (core_environ)
+ IOVEC_SET_STRING(iovec[j++], core_environ);
+ }
+
core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
if (core_timestamp)
IOVEC_SET_STRING(iovec[j++], core_timestamp);
/* Now, let's drop privileges to become the user who owns the
* segfaulted process and allocate the coredump memory under
- * his uid. This also ensures that the credentials journald
- * will see are the ones of the coredumping user, thus making
- * sure the user himself gets access to the core dump. */
+ * the user's uid. This also ensures that the credentials
+ * journald will see are the ones of the coredumping user,
+ * thus making sure the user gets access to the core dump. */
if (setresgid(gid, gid, gid) < 0 ||
setresuid(uid, uid, uid) < 0) {
log_error("Failed to drop privileges: %m");
r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
if (r >= 0)
core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
+ else if (r == -EINVAL)
+ log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
else
log_warning("Failed to generate stack trace: %s", strerror(-r));
}