Getting a Debian chroot on Android with Multistrap

Executive Summary and Motivation

This article is currently a mess and a work in progress. I'm trying to iterate on it quickly so check back soon.

Pre-requisites

  • a rooted Android device
  • a terminal application like jackpal
  • the busybox command installed
  • a Debian based system

Installing Multistrap on the Debian based machine

Installing Multistrap

sudo apt-get install multistrap

What we're doing is pretty much the Embedded Debian multistrap instructions [2].

  • Installing the Debian 'archive' keys for apt
  • Creating a Multistrap config

For the exhaustive Debian multistrap documentation see [1].

Entering the Chroot

Need to mount some virtual filesystems and the devices internal storage:

  • /sys (virtual filesystem of your computers hardware)
  • /dev (filesystem of device files for hardware devices)
  • /proc (virtual filesystem of processes, stats and settings)
  • /dev/pts (virtual filesystem of allocated terminals)
  • /dev/bus (found I needed this for USB device access)
  • /sdcard (mount internal storage of the device)
MOUNT=<path to root of the chroot>
mount -t sysfs sysfs $MOUNT/sys
mount -o bind  /dev $MOUNT/dev
mount -t devpts devpts $MOUNT/dev/pts
mount -o bind /dev/bus $MOUNT/dev/bus
mount -o bind /sdcard $MOUNT/mnt

Also basic environment variables need to be set to make your life easier:

HOME=/root
PATH=/bin:/sbin:/usr/bin:/usr/sbin
SHELL=/bin/sh
export HOME PATH SHELL

# And finally enter the chroot
/system/bin/chroot $MOUNT $SHELL

This step must be done the first time entering the chroot to setup many packages.

export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true
export LC_ALL=C LANGUAGE=C LANG=C
/var/lib/dpkg/info/dash.preinst install
dpkg --configure -a

Setting up a User Account in the Chroot

Android generates user accounts for each application that is installed, counting up from 10000, the name of the account is 'app_#' where the # is the remainder from the 10000 base (uid % 10000).

Inside of the chroot we can use the UID of the terminal application for our user account UID. This way we can piggyback on the terminal apps permissions and avoid running everything as root.

Another easy, and fun, way to do this is to take the running process ID of the Android shell currently running, and look at the UID of the owner in the /proc filesystem. It is important to remember this must be done outside the chroot, we're just gathering information for the chroot.

# Below $$ evaluates to the process ID of whatever calls it, here the shell.
# You must run the below code as the terminal application user, not root.

app_88@android:/ $ cat /proc/$$/status | grep Uid
Uid:    10088   10088   10088   10088

# Take the UID, 10088 in this case, and save it for later.
# To use this variable in the chroot enter it using this same terminal.
export TERM_UID=10088  # no spaces in the variable declaration

Android controls access to system calls by group membership, the same way access to a sound card is often controlled in GNU/Linux. The twist is the every application is a "user" that applies for group memberships, at installation time (when Google Play, or another market, asks you to confirm the permissions).

Anyway to have any fun with our renamed terminal user inside the chroot, we're going to want to be able to open network sockets, so we need to make a group inside the chroot matching the Android 'socket' group outside the chroot.

groupadd --gid 3003 sockets
useradd --uid $TERM_UID -m -G sockets --shell /bin/bash debian

# Boom! From root you can now change to a regular user in the shell, with
# sufficient but not excessive permissions--for IRC, VNC or other purposes.

su debian
whoami

TODO: add bit explaining sockets group and source of GID.

Bibliography

TODO: Sources still need to be cited here. They are forthcoming.

[1]Debian Multistrap
[2]EmDebian Cross Debbootstrap