Package rekall :: Package plugins :: Package linux :: Module mount
[frames] | no frames]

Source Code for Module rekall.plugins.linux.mount

  1  # Rekall Memory Forensics 
  2  # 
  3  # Copyright 2013 Google Inc. All Rights Reserved. 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or (at 
  8  # your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, but 
 11  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 13  # General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License 
 16  # along with this program; if not, write to the Free Software 
 17  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 18   
 19  import math 
 20   
 21  from rekall.plugins.linux import common 
 22  from rekall.plugins.overlays.linux import vfs 
 23   
 24   
25 -class Container(object):
26 """A simple container."""
27 28
29 -class Mount(common.LinuxPlugin):
30 """Lists the mount points.""" 31 __name = "mount" 32 33 table_header = [ 34 dict(name="Device", width=50), 35 dict(name="Path", width=50), 36 dict(name="Type", width=14), 37 dict(name="flags", width=20), 38 ] 39
40 - def get_mount_points(self):
41 if self.profile.get_constant("set_mphash_entries"): 42 # Kernel 3.14 starts using an hlist_head instead of a list_head 43 mnttype = "mount" 44 mount_hashtable_target_type = "hlist_head" 45 elif self.profile.has_type("mount"): 46 # Kernel 3.3 makes mount_hashtable be a table of struct mount 47 mnttype = "mount" 48 mount_hashtable_target_type = "list_head" 49 else: 50 mnttype = "vfsmount" 51 mount_hashtable_target_type = "list_head" 52 53 if mount_hashtable_target_type == "list_head": 54 # From fs/namespace.c HASH_SIZE 55 # http://lxr.free-electrons.com/source/fs/namespace.c?v=3.13#L29 56 hashtable_head_len = self.profile.get_obj_size( 57 mount_hashtable_target_type) 58 page_size = self.kernel_address_space.PAGE_SIZE 59 hash_size = 1 << int(math.log(page_size/hashtable_head_len, 2)) 60 numentries = hash_size 61 62 else: 63 # TODO(nop): Finish writing the code 64 # 3.14 allows you to customize the number of entries. 65 # Note that we could potentially get this value by running the dmesg 66 # plugin and parsing the following printk: 67 # "Mount-cache hash table entries: XXX" 68 69 # http://lxr.free-electrons.com/source/fs/namespace.c?v=3.14#L2827 70 numentries = self.profile.get_constant_object( 71 "mhash_entries", 72 vm=self.kernel_address_space, 73 target="unsigned long").value 74 75 # The followinr code mimics alloc_large_system_hash 76 # http://lxr.free-electrons.com/source/mm/page_alloc.c?v=3.14#L5888 77 if not numentries: 78 nr_kernel_pages = self.profile.get_constant_object( 79 "nr_kernel_pages", 80 vm=self.kernel_address_space, 81 target="unsigned long") 82 # XXX Need to finish the calculation 83 numentries = 65536 84 85 self.session.logging.debug("numentries: %d", numentries) 86 87 mount_hashtable = self.profile.get_constant_object( 88 "mount_hashtable", 89 vm=self.kernel_address_space, 90 target="Pointer", 91 target_args=dict( 92 target="Array", 93 target_args=dict( 94 count=numentries, 95 target=mount_hashtable_target_type 96 ))) 97 98 init_task = self.session.profile.get_constant_object( 99 "init_task", "task_struct", vm=self.kernel_address_space) 100 if not init_task: 101 self.session.logging.debug( 102 "Unable to obtain the init task. Mounted paths may be incorrect.") 103 104 # Walk the hash table 105 for hash in mount_hashtable: 106 for mnt in hash.list_of_type(mnttype, "mnt_hash"): 107 108 # Fields have moved between the struct vfsmount and 109 # struct mount in different kernel versions. 110 vfsmount = mnt.mnt 111 112 # http://lxr.free-electrons.com/source/fs/proc_namespace.c#L92 113 # The name of the device is in mnt_devname except when 114 # mnt->mnt_sb->s_op->show_devname is defined, in which case 115 # the kernel calls it. We do not emulate this call so the 116 # device names may differ from those reported in a live system. 117 devname = mnt.mnt_devname.deref() 118 119 # A super_block instance 120 sb = vfsmount.mnt_sb 121 # The name of the filesystem 122 fs_type = sb.s_type.name.deref() 123 124 if (not devname.is_valid() or len(str(devname)) == 0 or 125 not fs_type.is_valid() or len(str(fs_type)) == 0): 126 continue 127 128 # http://lxr.free-electrons.com/source/fs/proc_namespace.c#L92 129 # Paths get resolved via 130 # show_vfsmnt()->seq_path()->d_path()->prepend_path() 131 # 132 # Note that d_path calls prepend_path only when 133 # dentry->d_op->d_name() is not defined. We do not emulate the 134 # d_name() codepath, so the resolved mount paths may be a 135 # different in rekall than on a live system in these cases. 136 137 path_struct = Container() 138 path_struct.dentry = mnt.mnt_root 139 path_struct.mnt = vfsmount 140 path = vfs.Linux3VFS(self.session.profile).prepend_path( 141 path_struct, init_task.fs.root) 142 143 yield vfs.MountPoint(device=devname, 144 mount_path=path, 145 superblock=sb, 146 flags=vfsmount.mnt_flags, 147 session=self.session)
148
149 - def collect(self):
150 for mountpoint in self.get_mount_points(): 151 flags_string = str(mountpoint.flags) 152 153 # A mountpoint has read-write permissions if it's not readonly. 154 if not mountpoint.flags.ro: 155 if mountpoint.sb.s_flags & 0x01: 156 additional_flag = "ro" 157 else: 158 additional_flag = "rw" 159 flags_string = ', '.join([additional_flag, flags_string]) 160 161 yield dict(Device=mountpoint.device, 162 Path=mountpoint.name, 163 Type=mountpoint.fstype, 164 flags=flags_string)
165