This file is indexed.

/usr/lib/python2.7/dist-packages/rekall/plugins/addrspaces/mips.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
# Rekall Memory Forensics
#
# Authors:
# Karl Vogel <karl.vogel@gmail.com>
#
# 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 struct

from rekall import addrspace
from rekall import config
from rekall.plugins.addrspaces import intel

class MIPS32PagedMemory(intel.IA32PagedMemory):
    '''
    Address space to handle the MIPS Linux memory layout, which is:

    0x0000 0000 - 0x7FFF FFFF  kuseg: User mapped pages
    0x8000 0000 - 0x9FFF FFFF  k0seg: Kernel non paged memory, this maps to
                                      address range 0x0000 0000 - 0x1FFF FFFF
    0xA000 0000 - 0xBFFF FFFF  k1seg: Kernel non paged, non cached memory,
                                      this maps to address range
                                      0x0000 0000 - 0x1FFF FFFF
    0xC000 0000 - 0xFFFF FFFF  k2seg: Kernel paged memory using init_mm.pgd

    See page 8 on:
      http://www.eecs.harvard.edu/~margo/cs161/notes/vm-mips.pdf

    Derives from IA32PagedMemory as the only major difference is the special
    layout as shown above and minor details like no large pages and a difference
    in the PTE to PFN translation, which is taken care of by the
    pte_paddr function.
    '''

    # MIPS32 doesn't have a valid flag on PDE's, they're always valid
    valid_mask = (1 << 32) - 1

    def _pa(self, x):
        '''
        Convert a physical address to the actual physical memory location.
        '''
        if x < 0x80000000:
            return x
        elif x >= 0xA0000000:
            return x - 0xA0000000
        else:
            return x - 0x80000000

    def page_size_flag(self, entry):
        '''
        MIPS32 doesn't have a page size flag, always return False
        '''
        return False

    def read_long_phys(self, addr):
        '''
        Returns an unsigned 32-bit integer from the address addr in
        physical memory. If unable to read from that location, returns None.
        '''
        string = self.base.read(self._pa(addr), 4)
        return struct.unpack('>I', string)[0]

    def vtop(self, vaddr):
        '''
        Translates virtual addresses into physical offsets.
        The function should return either None (no valid mapping)
        or the offset in physical memory where the address maps.
        '''
        if (vaddr >= 0x80000000) and (vaddr < 0xC0000000):
            return self._pa(vaddr)

        return super(MIPS32PagedMemory, self).vtop(vaddr)

    def pte_paddr(self, pte):
        '''
        Return the physical address for the given PTE.
        This should return:
           (pte >> pfn_shift) << page_shift

        On MIPS pfn_shift is 11, while page_shift is 12
        '''
        return pte << 1

    def get_phys_addr(self, vaddr, pte_value):
        '''
        Return the offset in a 4KB memory page from the given virtual
        address and Page Table Entry.

        Bits 31:12 are from the PTE
        Bits 11:0 are from the original linear address
        '''
        if pte_value & self.valid_mask:
            return (self.pte_paddr(pte_value) & 0xfffff000) | (vaddr & 0xfff)

    def get_available_addresses(self, start=0):
        """Enumerate all valid memory ranges.

        Yields:
          tuples of (starting virtual address, size) for valid the memory
          ranges.
        """
        # Need to find out if we're mapping for kernel space
        # or userspace
        sym = self._pa(self.session.profile.get_constant('swapper_pg_dir'))
        if self.dtb == sym:
            num_pde = 1024
        else:
            num_pde = 512

        # Pages that hold PDEs and PTEs are 0x1000 bytes each.
        # Each PDE and PTE is four bytes. Thus there are 0x1000 / 4 = 0x400
        # PDEs and PTEs we must test
        # On MIPS, the userspace PDEs are limited to 512 entries
        for pde in range(0, num_pde):
            vaddr = pde << 22
            next_vaddr = (pde+1) << 22
            if start > next_vaddr:
                continue

            if (vaddr >= 0x80000000) and (vaddr < 0xC0000000):
                yield (vaddr, self._pa(vaddr), 1 << 22)
                continue

            pde_value = self.get_pde(vaddr)

            # This reads the entire PTE table at once - On
            # windows where IO is extremely expensive, its
            # about 10 times more efficient than reading it
            # one value at the time - and this loop is HOT!
            pte_table_addr = ((pde_value & 0xfffff000) |
                              ((vaddr & 0x3ff000) >> 10))

            data = self.base.read(self._pa(pte_table_addr), 4 * 0x400)
            pte_table = struct.unpack(">" + "I" * 0x400, data)

            tmp1 = vaddr
            for i, pte_value in enumerate(pte_table):
                vaddr = tmp1 | i << 12
                next_vaddr = tmp1 | ((i+1) << 12)

                if start > next_vaddr:
                    continue

                if pte_value & self.valid_mask:
                    yield (vaddr,
                           self.get_phys_addr(vaddr, pte_value),
                           0x1000)