/usr/lib/python2.7/dist-packages/rekall/plugins/linux/mount.py is in python-rekall-core 1.6.0+dfsg-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | # Rekall Memory Forensics
#
# Copyright 2013 Google Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import math
from rekall.plugins.linux import common
from rekall.plugins.overlays.linux import vfs
class Container(object):
"""A simple container."""
class Mount(common.LinuxPlugin):
"""Lists the mount points."""
__name = "mount"
table_header = [
dict(name="Device", width=50),
dict(name="Path", width=50),
dict(name="Type", width=14),
dict(name="flags", width=20),
]
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))
numentries = hash_size
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").value
# 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 = 65536
self.session.logging.debug("numentries: %d", numentries)
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=numentries,
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:
self.session.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 = 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)
def collect(self):
for mountpoint in self.get_mount_points():
flags_string = str(mountpoint.flags)
# A mountpoint has read-write permissions if it's not readonly.
if not mountpoint.flags.ro:
if mountpoint.sb.s_flags & 0x01:
additional_flag = "ro"
else:
additional_flag = "rw"
flags_string = ', '.join([additional_flag, flags_string])
yield dict(Device=mountpoint.device,
Path=mountpoint.name,
Type=mountpoint.fstype,
flags=flags_string)
|