]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
coredump: save process container parent cmdline 3858/head
authorJakub Filak <jfilak@redhat.com>
Wed, 27 Apr 2016 13:23:49 +0000 (15:23 +0200)
committerJakub Filak <jfilak@redhat.com>
Tue, 2 Aug 2016 14:01:18 +0000 (16:01 +0200)
Process container parent is the process used to start processes with a new
user namespace - e.g systemd-nspawn, runc, lxc, etc.

There is not standard way how to find such a process - or I do not know
about it - hence I have decided to find the first process in the parent
process hierarchy with a different mount namespace and different
/proc/self/root's inode.

I have decided for this criteria because in ABRT we take special care
only if the crashed process runs different code than installed on the
host. Other processes with namespaces different than PID 1's namespaces
are just processes running code shipped by the OS vendor and bug
reporting tools can get information about the provider of the code
without the need to deal with changed root and so on.

src/coredump/coredump.c

index 953f04e205c4253ce1ece52fad08a34d5dec982d..e3d17c864db5630a4034f1dbaeec4762f6fbc45d 100644 (file)
@@ -558,6 +558,89 @@ static int compose_open_fds(pid_t pid, char **open_fds) {
         return 0;
 }
 
+static int get_process_ns(pid_t pid, const char *namespace, ino_t *ns) {
+        const char *p;
+        struct stat stbuf;
+        _cleanup_close_ int proc_ns_dir_fd;
+
+        p = procfs_file_alloca(pid, "ns");
+
+        proc_ns_dir_fd = open(p, O_DIRECTORY | O_CLOEXEC | O_RDONLY);
+        if (proc_ns_dir_fd < 0)
+                return -errno;
+
+        if (fstatat(proc_ns_dir_fd, namespace, &stbuf, /* flags */0) < 0)
+                return -errno;
+
+        *ns = stbuf.st_ino;
+        return 0;
+}
+
+static int get_mount_namespace_leader(pid_t pid, pid_t *container_pid) {
+        pid_t cpid = pid, ppid = 0;
+        ino_t proc_mntns;
+        int r = 0;
+
+        r = get_process_ns(pid, "mnt", &proc_mntns);
+        if (r < 0)
+                return r;
+
+        while (1) {
+                ino_t parent_mntns;
+
+                r = get_process_ppid(cpid, &ppid);
+                if (r < 0)
+                        return r;
+
+                r = get_process_ns(ppid, "mnt", &parent_mntns);
+                if (r < 0)
+                        return r;
+
+                if (proc_mntns != parent_mntns)
+                        break;
+
+                if (ppid == 1)
+                        return -ENOENT;
+
+                cpid = ppid;
+        }
+
+        *container_pid = ppid;
+        return 0;
+}
+
+/* Returns 1 if the parent was found.
+ * Returns 0 if there is not a process we can call the pid's
+ * container parent (the pid's process isn't 'containerized').
+ * Returns a negative number on errors.
+ */
+static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) {
+        int r = 0;
+        pid_t container_pid;
+        const char *proc_root_path;
+        struct stat root_stat, proc_root_stat;
+
+        /* To compare inodes of / and /proc/[pid]/root */
+        if (stat("/", &root_stat) < 0)
+                return -errno;
+
+        proc_root_path = procfs_file_alloca(pid, "root");
+        if (stat(proc_root_path, &proc_root_stat) < 0)
+                return -errno;
+
+        /* The process uses system root. */
+        if (proc_root_stat.st_ino == root_stat.st_ino) {
+                *cmdline = NULL;
+                return 0;
+        }
+
+        r = get_mount_namespace_leader(pid, &container_pid);
+        if (r < 0)
+                return r;
+
+        return get_process_cmdline(container_pid, 0, false, cmdline);
+}
+
 static int change_uid_gid(const char *context[]) {
         uid_t uid;
         gid_t gid;
@@ -934,11 +1017,12 @@ static int process_kernel(int argc, char* argv[]) {
         _cleanup_free_ char
                 *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_environ = NULL,
-                *core_proc_mountinfo = NULL;
+                *core_proc_mountinfo = NULL, *core_container_cmdline = NULL;
 
         _cleanup_free_ char *exe = NULL, *comm = NULL;
         const char *context[_CONTEXT_MAX];
-        struct iovec iovec[26];
+        bool proc_self_root_is_slash;
+        struct iovec iovec[27];
         size_t n_iovec = 0;
         uid_t owner_uid;
         const char *p;
@@ -1129,9 +1213,20 @@ static int process_kernel(int argc, char* argv[]) {
 
         if (get_process_root(pid, &t) >= 0) {
                 core_root = strjoina("COREDUMP_ROOT=", t);
-                free(t);
 
                 IOVEC_SET_STRING(iovec[n_iovec++], core_root);
+
+                /* If the process' root is "/", then there is a chance it has
+                 * mounted own root and hence being containerized. */
+                proc_self_root_is_slash = strcmp(t, "/") == 0;
+                free(t);
+                if (proc_self_root_is_slash && get_process_container_parent_cmdline(pid, &t) > 0) {
+                        core_container_cmdline = strappend("COREDUMP_CONTAINER_CMDLINE=", t);
+                        free(t);
+
+                        if (core_container_cmdline)
+                                IOVEC_SET_STRING(iovec[n_iovec++], core_container_cmdline);
+                }
         }
 
         if (get_process_environ(pid, &t) >= 0) {