Monday, May 17, 2010

Introduction to Droid hacking.

One of the more interesting topics with embedded systems is where to store the data; it's important to understand that often there is no concept of a partition table. To understand what I mean by that it helps to look at the way the Droid boots up.
If you look at dmesg shortly after boot you'll see the following lines:
[    7.875122] 8 cmdlinepart partitions found on MTD device omap2-nand.0
[    7.881866] Creating 8 MTD partitions on "omap2-nand.0":
[    7.887451] 0x0000001c0000-0x000000340000 : "pds"
[    7.894714] 0x000000620000-0x000000680000 : "misc"
[    7.900939] 0x000000680000-0x000000a00000 : "boot"
[    7.907989] 0x000000a00000-0x000000e80000 : "recovery"
[    7.915740] 0x000000e80000-0x000009ae0000 : "system"
[    7.956878] 0x000009ae0000-0x00000f780000 : "cache"
[    7.986053] 0x00000f780000-0x00001fd40000 : "userdata"
[    8.057373] 0x00001fd40000-0x00001ff40000 : "kpanic"
While this is a a set of partitions, it's not actually read from a partition table, the keyword cmdlineparts indicates that the kernel parsed this from the mtdparts variable passed on boot up; essentially the kernel is just using a set of hardcoded values. The hex values represent the byte offsets for the given partition; since the droid uses a 512M flash chip, the offsets are from 0x00000000-0x1fffffff.

Notice how the first partition doesn't start until 0x1c0000 nor does it end at 0x1fffffff; that's not to say that there isn't data at these offsets, it's simply that they aren't accessed from within Linux.

It helps to create a chart:

To understand where the partitions are used you really don't need to look any further than the output of the mount command and line up the MTD numbers with /proc/mtd.

pdsyaffs2 filesystem.
mounted as /config
bootkernel + ramdisk.
used for normal bootup
recoverykernel + ramdisk.
used for recovery mode
systemyaffs2 filesystem.
mounted as /system
cacheyaffs2 filesystem.
mounted as /cache
userdatayaffs2 filesystem.
mounted as /data
kpanickernel panic logs

Some of the gaps can be filled in by booting into recovery mode:
[    7.609527] Creating 10 MTD partitions on "omap2-nand.0":
[    7.615173] 0x000000020000-0x0000000c0000 : "mbm"
[    7.622253] 0x000000160000-0x0000001c0000 : "cdt"
[    7.628448] 0x000000340000-0x0000003a0000 : "lbl"
[    7.634613] 0x000000620000-0x000000680000 : "misc"
[    7.640838] 0x000000680000-0x000000a00000 : "boot"
[    7.648071] 0x000000a00000-0x000000e80000 : "recovery"
[    7.655792] 0x000000e80000-0x000009ae0000 : "system"
[    7.696990] 0x000009ae0000-0x00000f780000 : "cache"
[    7.726287] 0x00000f780000-0x00001fd40000 : "userdata"
[    7.797546] 0x00001fd40000-0x00001ff40000 : "kpanic"

Since recovery mode is also used as as part of the software update mechanism, extra partitions have been added to provide write access.

mbmmotorola boot manager (aka bootloader)
cdt(explained later)
lbllinux boot loader

For now it'll suffice to say that the boot up begins with mbm which then transfers control over to lbl and then either the boot or recovery kernels.

The hardware is initialized by mbm which then displays the motorola logo; booting while holding the up button on the keyboard interrupts the boot up process and drops to a bootloader screen, allowing a new firmware to be flashed.

The sources to the lbl can be found on the motorola's opensource site; it's basically just a thin wrapper for converting the atags format passed by mbm into kernel arguments.

It's interesting to stop here and point out that there's a disconnect between how Linux and mbm view the flash.

To explain what I mean by that, consider a software update that replaces boot. The upgrade process reboots into recovery and the update writes to the partition the recovery kernel identifies as boot. Suppose I modified the recovery kernel to in essence, blatantly lie about which partition is boot; the upgrade will still write to the fake partition but it would have no impact on actual boot up since mbm -- unaware of my lies -- would continue to boot the real partition.

While it sounds trivial, you have to remember that the upgrade's entire view of the world is through the information provided by the kernel, which means there's no way to detect the misdirection; any attempt can be thwarted by another lie.

I think Ken Thompson covered it best in Reflections on Trusting Trust.

Stay tuned; more to come.