예제 #1
0
    def get_path(self, filp):
        """Resolve the dentry, vfsmount relative to this task's chroot.

        Returns:
          An absolute path to the global filesystem mount. (I.e. we do not
          truncate the path at the chroot point as the kernel does).
        """
        # The specific implementation depends on the kernel version.

        # Newer kernels have mnt_parent in the mount struct, not in the
        # vfsmount struct.
        if self.obj_profile.get_obj_offset("vfsmount", "mnt_parent"):
            return vfs.Linux26VFS(self.obj_profile).get_path(self, filp)

        else:
            return vfs.Linux3VFS(self.obj_profile).get_path(self, filp)
예제 #2
0
    def get_mount_points(self):
        if self.profile.get_constant("set_mphash_entries"):
            # Kernel 3.14 starts using an hlist_head instead of a list_head
            mnttype = "mount"
            mount_hashtable_target_type = "hlist_head"
        elif self.profile.has_type("mount"):
            # Kernel 3.3 makes mount_hashtable be a table of struct mount
            mnttype = "mount"
            mount_hashtable_target_type = "list_head"
        else:
            mnttype = "vfsmount"
            mount_hashtable_target_type = "list_head"

        if mount_hashtable_target_type == "list_head":
            # From fs/namespace.c HASH_SIZE
            # http://lxr.free-electrons.com/source/fs/namespace.c?v=3.13#L29
            hashtable_head_len = self.profile.get_obj_size(
                mount_hashtable_target_type)
            page_size = self.kernel_address_space.PAGE_SIZE
            hash_size = 1 << int(math.log(page_size / hashtable_head_len, 2))

        else:
            # TODO(nop): Finish writing the code
            # 3.14 allows you to customize the number of entries.
            # Note that we could potentially get this value by running the dmesg
            # plugin and parsing the following printk:
            # "Mount-cache hash table entries: XXX"

            # http://lxr.free-electrons.com/source/fs/namespace.c?v=3.14#L2827
            numentries = self.profile.get_constant_object(
                "mhash_entries",
                vm=self.kernel_address_space,
                target="unsigned long")

            # The followinr code mimics alloc_large_system_hash
            # http://lxr.free-electrons.com/source/mm/page_alloc.c?v=3.14#L5888
            if not numentries:
                nr_kernel_pages = self.profile.get_constant_object(
                    "nr_kernel_pages",
                    vm=self.kernel_address_space,
                    target="unsigned long")
                # XXX Need to finish the calculation
                numentries = 256

        logging.debug("mount_hashtable size: %d", hash_size)

        mount_hashtable = self.profile.get_constant_object(
            "mount_hashtable",
            vm=self.kernel_address_space,
            target="Pointer",
            target_args=dict(target="Array",
                             target_args=dict(
                                 count=hash_size,
                                 target=mount_hashtable_target_type)))

        init_task = self.session.profile.get_constant_object(
            "init_task", "task_struct", vm=self.kernel_address_space)
        if not init_task:
            logging.debug("Unable to obtain the init task. "
                          "Mounted paths may be incorrect.")

        # Walk the hash table
        for hash in mount_hashtable:
            for mnt in hash.list_of_type(mnttype, "mnt_hash"):

                # Fields have moved between the struct vfsmount and
                # struct mount in different kernel versions.
                vfsmount = mnt.mnt

                # http://lxr.free-electrons.com/source/fs/proc_namespace.c#L92
                # The name of the device is in mnt_devname except when
                # mnt->mnt_sb->s_op->show_devname is defined, in which case
                # the kernel calls it. We do not emulate this call so the
                # device names may differ from those reported in a live system.
                devname = mnt.mnt_devname.deref()

                # A super_block instance
                sb = vfsmount.mnt_sb
                # The name of the filesystem
                fs_type = sb.s_type.name.deref()

                if (not devname.is_valid() or len(str(devname)) == 0
                        or not fs_type.is_valid() or len(str(fs_type)) == 0):
                    continue

                # http://lxr.free-electrons.com/source/fs/proc_namespace.c#L92
                # Paths get resolved via
                # show_vfsmnt()->seq_path()->d_path()->prepend_path()
                #
                # Note that d_path calls prepend_path only when
                # dentry->d_op->d_name() is not defined. We do not emulate the
                # d_name() codepath, so the resolved mount paths may be a
                # different in rekall than on a live system in these cases.

                path_struct = session.Container()
                path_struct.dentry = mnt.mnt_root
                path_struct.mnt = vfsmount
                path = vfs.Linux3VFS(self.session.profile).prepend_path(
                    path_struct, init_task.fs.root)
                yield vfs.MountPoint(device=devname,
                                     mount_path=path,
                                     superblock=sb,
                                     flags=vfsmount.mnt_flags,
                                     session=self.session)