July 21, 2014

Hacklog #2: Filesystem fun

The Virtual Filesystem

As of the last post, I have the means to open an interactive shell on the phone and move around the filesystem to the extent allowed by the permissions granted to this user:

$ id
id
uid=2000(shell) gid=2000(shell) groups=1003(graphics),1004(input),1007(log),1009(mount),1011(adb),1015(sdcard_rw),3001(net_bt_admin),3002(net_bt),3003(inet)

$ ls -l /
ls -l /
dr-x------ root     root              2014-07-15 20:38 config
drwxrwx--- system   cache             2014-07-15 20:38 cache
lrwxrwxrwx root     root              2014-07-15 20:38 sdcard -> /mnt/sdcard
drwxr-xr-x root     root              2014-07-15 20:38 acct
drwxrwxr-x root     system            2014-07-15 20:38 mnt
lrwxrwxrwx root     root              2014-07-15 20:38 vendor -> /system/vendor
lrwxrwxrwx root     root              2014-07-15 20:38 d -> /sys/kernel/debug
lrwxrwxrwx root     root              2014-07-15 20:38 etc -> /system/etc
-rw-r--r-- root     root         4494 1970-01-01 01:00 ueventd.rc
-rw-r--r-- root     root            0 1970-01-01 01:00 ueventd.goldfish.rc
drwxr-xr-x root     root              2012-06-01 01:00 system
drwxr-xr-x root     root              2014-07-15 20:38 sys
drwxr-x--- root     root              1970-01-01 01:00 sbin
lrwxrwxrwx root     root              1970-01-01 01:00 res -> /system/res
dr-xr-xr-x root     root              1970-01-01 01:00 proc
-rw-r--r-- root     root         7451 1970-01-01 01:00 meta_init.rc
-rwxr-x--- root     root        27852 1970-01-01 01:00 init.rc
-rwxr-x--- root     root         1677 1970-01-01 01:00 init.goldfish.rc
-rwxr-x--- root     root        12110 1970-01-01 01:00 init.factory.rc
-rwxr-x--- root     root          134 1970-01-01 01:00 init.aee.customer.rc
-rwxr-x--- root     root        98396 1970-01-01 01:00 init
-rw-r--r-- root     root          141 1970-01-01 01:00 default.prop
drwxrwx--x system   system            2014-07-15 20:38 data
-rw-r--r-- root     root        26646 1970-01-01 01:00 advanced_meta_init.rc
drwx------ root     root              2013-04-03 07:17 root
drwxr-xr-x root     root              2014-07-15 20:38 dev

I'd very much like to inspect the contents of init.goldfish.rc for instance since it has an unusual name, but the user I'm logged in as is neither root nor a member of group root, so I'm SOL.

As I mentioned in the first post, two of my objectives are to access the full filesystem and to obtain superuser privileges on the phone. If I can achieve the latter then I get the former "for free". Unfortunately, I'll need to know a lot about the software running on the phone to become root and there are areas of the filesystem I can't access using adb shell. It follows that I need another way to access the filesystem, unconstrained by permissions.

From messing around with portable electronics over the last ten years, I'm aware that modern phones typically have the capability to receive firmware updates independently of the operating system. This is usually implemented by a standalone program accessed through a key combo early in the boot process - that program would talk over USB to a specialised piece of software running on a Windows PC and read/write a ROM image from/to the onboard flash storage. If you're really lucky, you might even get some basic debug output on the screen.

I dug around and found that such tools do indeed exist for that family of MediaTek systems, so I decided to spend some time investigating the storage configuration on this device.

Storage configuration

Let's have a look at what's mounted where:

$ mount
mount
rootfs / rootfs ro,relatime 0 0
tmpfs /dev tmpfs rw,relatime,mode=755 0 0
devpts /dev/pts devpts rw,relatime,mode=600 0 0
proc /proc proc rw,relatime 0 0
sysfs /sys sysfs rw,relatime 0 0
none /acct cgroup rw,relatime,cpuacct 0 0
tmpfs /mnt/asec tmpfs rw,relatime,mode=755,gid=1000 0 0
tmpfs /mnt/obb tmpfs rw,relatime,mode=755,gid=1000 0 0
none /dev/cpuctl cgroup rw,relatime,cpu 0 0
/dev/block/mtdblock11 /system yaffs2 ro,noatime 0 0
/dev/block/mtdblock13 /data yaffs2 rw,nosuid,nodev,relatime 0 0
/dev/block/mtdblock12 /cache yaffs2 rw,nosuid,nodev,relatime 0 0
/dev/block/mtdblock7 /system/secro yaffs2 ro,relatime 0 0
  • tmpfs is a volatile FS backed by memory, so it's not really relevant to my interests here.

  • rootfs is also backed by memory, but unlike tmpfs it's populated at boot time from the contents of an archive passed to the kernel by the bootloader.

That archive probably lives alongsides the kernel image in an area of flash ROM accessible to the bootloader. This may or may not be available once Linux is up and running on the phone. Anyway, that's something else to investigate.

  • devpts, proc, sysfs and cgroup are artifacts of the kernel and not used for actual data storage.

  • This leaves us with 4 yaffs2 filesystems backed by what looks like good, honest block devices.

MTD block devices

Let's find out more about these block devices.

$ ls -l /dev/block
ls -l /dev/block
drwxr-xr-x root     root              2014-07-19 22:26 vold
brw------- root     root      31,  13 2014-07-19 22:26 mtdblock13
brw------- root     root      31,  12 2014-07-19 22:26 mtdblock12
brw------- root     root      31,  11 2014-07-19 22:26 mtdblock11
brw------- root     root      31,  10 2014-07-19 22:26 mtdblock10
brw------- root     root      31,   9 2014-07-19 22:26 mtdblock9
brw------- root     root      31,   8 2014-07-19 22:26 mtdblock8
brw------- root     root      31,   7 2014-07-19 22:26 mtdblock7
brw------- root     root      31,   6 2014-07-19 22:26 mtdblock6
brw------- root     root      31,   5 2014-07-19 22:26 mtdblock5
brw------- root     root      31,   4 2014-07-19 22:26 mtdblock4
brw------- root     root      31,   3 2014-07-19 22:26 mtdblock3
brw------- root     root      31,   2 2014-07-19 22:26 mtdblock2
brw------- root     root      31,   1 2014-07-19 22:26 mtdblock1
brw------- root     root      31,   0 2014-07-19 22:26 mtdblock0
brw------- root     root       7,   7 2014-07-19 22:26 loop7
brw------- root     root       7,   6 2014-07-19 22:26 loop6
brw------- root     root       7,   5 2014-07-19 22:26 loop5
brw------- root     root       7,   4 2014-07-19 22:26 loop4
brw------- root     root       7,   3 2014-07-19 22:26 loop3
brw------- root     root       7,   2 2014-07-19 22:26 loop2
brw------- root     root       7,   1 2014-07-19 22:26 loop1
brw------- root     root       7,   0 2014-07-19 22:26 loop0

The filesystems that are used for persistent data storage on the phone are backed by Memory Technology Devices. The FAQ I just linked to points out that MTD are neither character nor block devices, yet for the purpose of data storage they are accessed as block devices.

We can see that there's a grand total of 14 MTD block devices in /dev/block, of which only four are used for mounted filesystems. Major device number 31 is indeed claimed by the mtdblock driver:

$ cat /proc/devices
cat /proc/devices
Character devices:
  1 mem
  2 pty
  3 ttyp
  4 /dev/vc/0
  4 tty
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 29 fb
 90 mtd
108 ppp
128 ptm
136 pts
160 MT6575_VCodec
169 ttyC
176 drvb
178 ccci_fs
179 ccci_fs_util
180 usb
182 sec
183 CCCI_IPC_DEV
184 ccci
188 M4U_device
189 usb_device
190 mtk_stp_wmt
191 mtk_stp_GPS_chrdev
192 mtk_stp_BT_chrdev
193 fm
204 ttyMT
231 mtkbc
232 pvrsrvkm
233 ttyGS
234 Res_Mgr
235 DumChar
236 mt6575-SYSRAM
237 mt6575-eis
238 mt6575-isp
239 kd_camera_hw
240 mt6575-MDP
241 MTK_MAU
242 dummy_eeprom
243 kd_camera_flashlight
244 btn
245 mem_dummy
246 spc
247 MT_pmic_adc_cali
248 mt6575_jpeg
249 accdet
250 watchdog
251 mtk-adc-cali
252 BOOT
253 mt6575-fdvt
254 rtc

Block devices:
259 blkext
  7 loop
  8 sd
 31 mtdblock
 65 sd
 66 sd
 67 sd
 68 sd
 69 sd
 70 sd
 71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
254 device-mapper

The kernel has a mtdblock driver which exposes allows access to these MTD as if they were rgular block devices, but it also has a mtd driver used for character devices.

The mtdblock driver

The phone is running version 2.6.35.7 (Yokohama) of the kernel...

$ cat /proc/version
cat /proc/version
Linux version 2.6.35.7 (android@ubuntu) (gcc version 4.4.3 (GCC) ) #1 PREEMPT Wed Apr 3 14:18:40 CST 2013

...so let's have a look at the mtd driver's source for that version of the kernel. Of course, I don't know what patches may or may not have been applied at build-time but it's a good place to start.

After a bit of digging around, it emerges that:

  • mtdblock exposes a /proc/mtd file through procfs:

    $ cat /proc/mtd
    cat /proc/mtd
    dev:    size   erasesize  name
    mtd0: 00040000 00020000 "preloader"
    mtd1: 000c0000 00020000 "dsp_bl"
    mtd2: 00300000 00020000 "nvram"
    mtd3: 00020000 00020000 "seccnfg"
    mtd4: 00060000 00020000 "uboot"
    mtd5: 00500000 00020000 "boot"
    mtd6: 00500000 00020000 "recovery"
    mtd7: 00120000 00020000 "secstatic"
    mtd8: 00060000 00020000 "misc"
    mtd9: 00300000 00020000 "logo"
    mtd10: 000a0000 00020000 "expdb"
    mtd11: 12700000 00020000 "system"
    mtd12: 03c00000 00020000 "cache"
    mtd13: 07f20000 00020000 "userdata"
    
  • mtdblock can partition a MTD into smaller block devices

    $ cat /proc/partitions
    cat /proc/partitions
    major minor  #blocks  name
    
      31        0        256 mtdblock0
      31        1        768 mtdblock1
      31        2       3072 mtdblock2
      31        3        128 mtdblock3
      31        4        384 mtdblock4
      31        5       5120 mtdblock5
      31        6       5120 mtdblock6
      31        7       1152 mtdblock7
      31        8        384 mtdblock8
      31        9       3072 mtdblock9
      31       10        640 mtdblock10
      31       11     302080 mtdblock11
      31       12      61440 mtdblock12
      31       13     130176 mtdblock13
    
  • mtdblockcan read partitioning information from the kernel's command line arguments. Too bad I can't see what arguments were given:

    $ ls -l /proc/cmdline
    ls -l /proc/cmdline
    -r--r----- root     radio           0 2014-07-20 10:11 cmdline
    

Where we at

At this point, I know that the files I'm interested in live on YAFFS filesystems (more on those in a later post) backed by various partitions of presumably a single Flash ROM device. Furthermore, I know how big each partition is. If we assume that there are no gaps between partitions on the MTD, we can infer the start offsets of each partition in the 'raw' MTD:

MTD Partition Name Start Offset Size Mountpoint
mtd0 preloader 0x00000000 0x00040000 N/A
mtd1 dsp_bl 0x00040000 0x000c0000 N/A
mtd2 nvram 0x00100000 0x00300000 N/A
mtd3 seccnfg 0x00400000 0x00020000 N/A
mtd4 uboot 0x00420000 0x00060000 N/A
mtd5 boot 0x00480000 0x00500000 N/A
mtd6 recovery 0x00980000 0x00500000 N/A
mtd7 secstatic 0x00e80000 0x00120000 /system/secro
mtd8 misc 0x00fa0000 0x00060000 N/A
mtd9 logo 0x01000000 0x00300000 N/A
mtd10 expdb 0x01300000 0x000a0000 N/A
mtd11 system 0x013a0000 0x12700000 /system
mtd12 cache 0x13aa0000 0x03c00000 /cache
mtd13 userdata 0x176a0000 0x07f20000 /data

I used this information to dump the relevant sections of the flash ROM - I'll cover that in a future post.