Sunday, April 5, 2015

boot loop - Trying to flash a system.img I took with dd - failing


Long-time UNIX guy here, but relatively new to the world of Android. Read on.


EPISODE 1: A New Backup (I hoped)


I have recently purchased an Asus MemoPAD (ME103K) ; I then became root, and took a dd image of the read-only system partition to the external SD card:


$ su
# dd if=/dev/block/platform/msm_sdcc.1/by-name/system \
of=/storage/MicroSD/system.img bs=1M
# ls -l /storage/MicroSD/system.img
-rw-r--r-- 1 root root 2147483648 Sep 27 13:15 system.img


The size (exactly 2GiB) was a bit suspicious - could it be that this was because of the FAT32 partition on the SD card?


No, it was not - tune2fs -l revealed that this was indeed, a valid EXT4 image, exactly sized at 2GiB, which passed fsck -f with no errors at all. And fastboot (from the linux machine attached to the tablet) concurred, after an adb reboot bootloader:


linuxbox# fastboot getvar all
(bootloader) version-bootloader: 3.03
(bootloader) version-hardware: rev_c
(bootloader) variant: LEOPARDCAT 16G
(bootloader) version-baseband: H00_0.16.F_0521
(bootloader) serialno: 0a3dXXXX
...

(bootloader) partition-type:system: ext4
(bootloader) partition-size:system: 0x0000000080000000

That size, is indeed 2GB:


linuxbox# python2 -c 'print 0x0000000080000000'
2147483648

So, all is good - I have a backup of the image. Now to test restoring it.


I try to flash the system.img back to the tablet - to make sure I can recover from anything, the sort of bullet-proof backup we do in the Unix world (e.g. restore contents of a drive via dd if=backup.image of=/dev/sdXXX).


Everything related to adb and fastboot work flawlessly - so I try...



linux_box# fastboot devices
0a3dXXXX fastboot

linux_box# mount /dev/sdcard /mnt/sdcard
linux_box# cp /mnt/sdcard/system.img .
linux_box# fastboot flash system system.img
error: cannot load 'system.img'

Hmm. I download and build the android-tools-5.1.1 of my distribution from sources, adding debug information - and step in the debugger, to see this failure:


linuxbox# gdb --args fastboot flash system system.img

...

Failure due to negative size!


Interesting - even though I am in a 64bit machine, apparently there are issues that turn the file size "negative" (in a 32bit world, the file size of my image, 2^31, is indeed considered negative - to be exact, -2147483648.


OK, fine - how do they flash large image files in Android?


Googling, searching - turns out they use this make_ext4fs tool, that creates flashable images. In fact it is part of what I just compiled, so I might as well use it:


linuxbox# mkdir /system
linuxbox# mount -o loop,ro system.img /system
linuxbox# ls -l /system
total 208

drwxr-xr-x 106 root root 8192 Sep 17 22:24 app
drwxr-xr-x 3 root 2000 8192 Sep 26 21:08 bin
-rw-r--r-- 1 root root 6847 Sep 12 16:59 build.prop
drwxr-xr-x 19 root root 4096 Sep 26 21:08 etc
drwxr-xr-x 2 root root 4096 Aug 11 22:27 fonts
drwxr-xr-x 4 root root 4096 Sep 12 16:56 framework
drwxr-xr-x 10 root root 16384 Sep 12 16:59 lib
drwxr-xr-x 2 root root 4096 Jan 1 1970 lost+found
drwxr-xr-x 3 root root 4096 Aug 11 22:18 media
drwxr-xr-x 59 root root 4096 Aug 11 22:29 priv-app

-rw-r--r-- 1 root root 126951 Aug 1 2008 recovery-from-boot.p
drwxr-xr-x 3 root root 4096 Aug 11 21:02 scripts
drwxr-xr-x 3 root root 4096 Aug 11 21:02 tts
drwxr-xr-x 11 root root 4096 Sep 26 21:08 usr
drwxr-xr-x 8 root 2000 4096 Aug 11 22:29 vendor
drwxr-xr-x 2 root 2000 4096 Sep 26 21:09 xbin

linuxbox# ../extras/source/extras/ext4_utils/make_ext4fs \
-l 2048M new_system.img /system
Creating filesystem with parameters:

Size: 2147483648
Block size: 4096
Blocks per group: 32768
Inodes per group: 8192
Inode size: 256
Journal blocks: 8192
Label:
Blocks: 524288
Block groups: 16
Reserved block group size: 127

Created filesystem with 2666/131072 inodes and 375014/524288 blocks

Cool - so I can apparently build system images from plain old folders. The sky will be my limit - I'll be able to add anything I want to this image.


Let's burn it...


linuxbox# fastboot flash system new_system.img
erasing 'system'...
OKAY [ 0.064s]
sending 'system' (2088960 KB)...
^C


I waited for 1h before hitting that Ctrl-C. And had to power-cycle the tablet, which booted back in fastboot mode.


This is not looking good.


What if I build a smaller image? Maybe the 2GB are somehow an issue, and this partition is not used to full capacity - it has free space:


linuxbox# ../extras/source/extras/ext4_utils/make_ext4fs \
-l 1536M new_system.img /system

linuxbox# ./fastboot flash system system.img
erasing 'system'...
OKAY [ 0.065s]
sending 'system' (1572864 KB)...

OKAY [ 51.039s]
writing 'system'...
OKAY [235.080s]
finished. total time: 286.183s

OK, this looks very promising (and only took 5 min). I guess I can now reboot back and everything should be normal, yes?


No :-)


enter image description here


I don't mind a temporarily bricked device, as long as I do get to control it in the end (machines that I am not a master of, are machines I don't care to operate ;-)


Any ideas on what I did wrong and what I can do to fix this?



Thanks in advance.


P.S. I checked the Asus support page for my tablet - they only provide the sources for the kernel, and the Over-the-air .zip file. That in turn contains a file-system level backup from the root - i.e. the system folder exists in there as just a folder, not an image, not a system.img that I can flash - so that doesn't really help me.


EPISODE 2: Attack of the Custom Boots


In the absense of any sort of recovery.img from Asus (why would a manufacturer bother to publish a fastboot-flashable recovery.img? Why indeed...) and a similar absence on recovery images from the CWM and TWRP sites... I am left to battle all alone.


Thankfully, the Over-the-air update file from Asus includes inside it...


linuxbox# unzip -l /opt/Asus/firmware/UL-K01E-WW-12.16.1.12-user.zip |\
grep boot.img$
7368704 2011-03-22 11:21 boot.img

...my tablet's boot image. Now maybe - just maybe - I can do something with this.



linuxbox$ mkdir rootfs
linuxbox$ cd rootfs
linuxbox$ abootimg -x /path/to/boot.img
linuxbox$ ls -l
bootimg.cfg
initrd.img
zImage

Expanding the ramdisk...


linuxbox$ mkdir initrd

linuxbox$ cd initrd
linuxbox$ gzip -cd ../initrd.img | cpio -ivd
...
linuxbox$ vi default.prop

I set up default.prop to be root when the kernel boots:


ro.secure=0
ro.debuggable=1
ro.adb.secure=0
androidboot.selinux=disabled


I also copied /system/bin/sh (from the over-the-air Asus .zip file) into /sbin/sh. I did the same with busybox - quite handy tool.


And repacked the boot.img...


busybox$ find . | cpio --create --format='newc' | gzip -9 > ../initrd.custom.gz
busybox$ cd ..
busybox$ abootimg --create ../new_boot_busybox.img \
-f bootimg.cfg -k zImage -r initrd.custom.gz

abootimg actually failed the first time I run this, since bootimg.cfg had to be updated - the bootsize parameter had to be changed, since the package is bigger now. abootimg reports what it needs, so that's easy enough.


And now, I boot my custom image...



linuxbox# fastboot boot new_boot_busybox.img

...and witness the following...


linuxbox# adb logcat
- exec '/system/bin/sh' failed: Permission denied (13) -

linuxbox# adb shell
- exec '/system/bin/sh' failed: Permission denied (13) -

Hmm... Maybe adbd is not run as root?



linuxbox# adb root
restarting adbd as root

linuxbox# adb shell
- exec '/system/bin/sh' failed: Permission denied (13) -

Fine... I hexedit adbd, and patch /system/bin/sh to be /sbin/sh (I copied the /system/bin/sh from the OTA image to the rootfs of the initrd): Reboot, fastboot...


linuxbox# adb shell
- exec '/sbin/sh' failed: Permission denied (13) -


Darn. Is this thing able to do anything?


linuxbox# adb pull /proc/partitions
15 KB/s (1272 bytes in 0.079s)

It is... let's see:


linuxbox# adb pull /proc/mounts
16 KB/s (1358 bytes in 0.079s)

linuxbox# grep system mounts
/dev/block/platform/msm_sdcc.1/by-name/system /system ext4 rw,seclabel,relatime,data=ordered 0 0


OK, so /system is mounted. Can I see what's inside?


linuxbox# adb pull /system
remote object '/system' does not exist

What the... Maybe I can check what /proc/kmsg contains (what "dmesg" would output)


linuxbox# adb pull /proc/kmsg
failed to copy '/proc/kmsg' to './kmsg': Operation not permitted

Nah, I need to be root to do that.



linuxbox# adb push /sbin/sh /system/bin/sh
failed to copy '/sbin/sh' to '/system/bin/sh': Permission denied

And that, too.


This is turning out to be quite a puzzle...



Answer



Episode 3: Return of the Shell.


If I ever had any chance of solving this, I first had to figure out why the shell wasn't working. adbd itself was responding, so it was started on the tablet side - but it could not execute the shell, even when I hack-patched it to invoke a file (/sbin/sh) that I myself placed in the boot image - being 100% sure that it had the proper permissions and was accessible from the shell (id=2000) account that adbd uses.


Which left only one explanation - SELinux "cages".


So I checked how adbd was started from my boot image's init.rc:



# adbd is controlled via property triggers in init..usb.rc
service adbd /sbin/adbd --root_seclabel=u:r:su:s0
class core
socket adbd stream 660 system system
disabled
seclabel u:r:adbd:s0

...and tried an obvious change:


service adbd /sbin/adbd
class core

socket adbd stream 660 system system

I re-packed, and to my intense satisfaction, saw ...


linuxbox# adb shell
$

I finally got access to the tablet - from "inside".


Checking the mounted /system, it became clear that the flashing process - even though fastboot flash system ... reported that all was Ok - had failed spectacularly. It was a wonder that the partition was mounted in the first place.


That explained why the tablet was not booting, and gave me the final idea that solved the issue.


I needed to boot the tablet so that it used my pristine copy of the /system partition, but at this point, even though I had shell access, I was not root - (the changes I did in default.prop are apparently ignored by the Asus kernel - I'll have to recompile it soon...) so I could not mount the external sdcard and dd over my good copy.



But I did have my own boot image - which meant I could edit the /fstab.qcom inside it, and do this:


Original line that told the tablet how to mount /system


/dev/block/platform/msm_sdcc.1/by-name/system  /system  ext4 ro,barrier=1 wait

My edit


/dev/block/mmcblk1p2  /system ext4  rw,barrier=1 wait

...and back in my linux box, I dd-ed the pristine backup of the tablet's system partition to my external SD card's 2nd partition - which I created via gparted to be exactly 2GB.


That did it - the tablet booted from my external SD card.


EDIT: The journey continued - I eventually patched and compiled my own kernel and became root.



No comments:

Post a Comment

samsung galaxy s 2 - Cannot restore Kies backup after firmware upgrade

I backed up my Samsung Galaxy S2 on Kies before updating to Ice Cream Sandwich. After the upgrade I tried to restore, but the restore fails ...