Debian noroot 環境の動作原理について

  • 9
    いいね
  • 5
    コメント

はじめに

Debian noroot とは、 Android OS 上において root 権限を取ることなく Debian 環境を構築するためのアプリケーションです。
CPU の性能とメモリ容量が潤沢にある Android 端末であれば、 Debian noroot の導入によって Android 端末上で非常に軽快な Debian 環境を実現することができます。

Debian noroot 環境は Android OS 上で動作する X Windows System サーバアプリである Xserver XSDL と、 root 権限を取得すること無く chroot 環境の構築と mount --bind の実現等を行うソフトウェアである proot を用いて実現されています。

また、 Android OS から Debian noroot 環境を起動するまでの過程を Debian noroot アプリ及び Xserver XSDL アプリのソースコード等を参照して調査した結果、最初に Xserver XSDL サーバが起動された後、 Android OS ネイティブ環境下において、 Debian noroot 環境において使用する chroot 環境を構築するシェルスクリプトである proot.sh が実行され、続いて、 proot.sh シェルスクリプトで構築した chroot 環境下において、デスクトップマネージャの起動等を行うシェルスクリプトである startx.sh が実行されることにより、 Debian noroot 環境が起動されることが判明しました。

本稿では、 Debian noroot 環境を実現するソフトウェア及び Debian noroot 環境の一連の動作過程を通じて、 Debian noroot 環境の動作原理について記述します。

本稿では最初に、 "Debian noroot に関連する各種ソフトウェアの概要" の章において、 Debian noroot 環境を実現するために使用されている各種ソフトウェアに関する概要について述べます。
次に "Debian noroot 環境の起動過程" の章において、 Android OS 上より Debian noroot アプリを起動してから、 Debian noroot 環境上のウィンドウマネージャが起動されるまでの一連の起動過程について述べます。
最後に、 "結論" の章において、本稿の結論について述べます。

Debian noroot 環境に関連する各種ソフトウェアの概要

本章では、 Debian noroot 環境を実現するために使用されているソフトウェアである Xserver XSDL 及び proot の概要について述べます。

本章では最初に、 "Xserver XSDL について" の節において、 Android OS 上の X Windows System サーバアプリケーションである Xserver XSDL の概要について述べます。
次に、 "proot について" の節において、 Android OS 及び Linux をカーネルとする各種ディストリビューションにおいて、 root 権限を取ること無く chroot 環境の構築と mount --bind の実現等を行うソフトウェアである proot の概要について述べます。

Xserver XSDL について

Xserver XSDL とは、 Debian noroot の開発者である pelya 氏によって開発された Android OS 上において動作する X Windows System のサーバアプリケーションです。

Xserver XSDL は、 X Windows System の完全な互換性を持つ実装であるので、 X.Org の様な他の UNIX 互換 OS で動作する X Windows System サーバプログラムと同様に、リモートの Linux PC 端末や Xserver XSDL アプリがインストールされている Android OS 端末自身等で動作する X Windows System クライアントプログラムの GUI を画面上に表示させることが可能です。

Xserver XSDL は、 Android OS 上に移植された画像描画や音声再生の API を持つマルチメディアライブラリである SDL を使用して実装されています。

ここで、 Android OS 端末より Xserver XSDL アプリを起動すると、以下の画像のように、 Xserver XSDL アプリの起動画面が表示されます。

(Xserver XSDL...)

次に、以下の画像のように画面の解像度等の変更を促す画面が表示されます。ここで解像度等を変更する必要が無ければ、 3 秒後に X Windows System サーバの画面が自動的に表示されます。

(Tap the screen change...)

最後に、以下の画像のような X Windows System サーバの画面が表示されます。

(Launch these commands on your Linux PC...)

ここで Android OS 端末に上記の画面が表示されている状態から、リモートで動作する Linux PC 端末上で以下のコマンドを実行すると、上記の画像で示した X Windows system サーバ画面上に X Windows system で動作するターミナルエミュレータである xterm が表示されます。

 $ env DISPLAY=192.168.20.33:0 xterm

また、Android OS 端末の別のアプリケーション上に chroot 環境で動作する Linux ディストリビューションが構築されている場合、 Linux ディストリビューション上から以下のコマンドを実行すると、上記の画像で示した X Windows system サーバ画面上に、軽量ウィンドウマネージャである twm が動作します。

 $ env DISPLAY=:0 twm

なお本稿では、以降特に断りのない限り、 Xserver XSDL アプリによって起動する X Windows system サーバを "Xserver XSDL サーバ" と記述します。

proot について

proot とは、 Android OS 及び Linux をカーネルとする各種ディストリビューションにおいて、 root 権限を取ること無く chroot 環境や mount --bind コマンドに基づくディレクトリのバインド及び QEMU のユーザモードを利用した binfmt_misc を擬似的に実現するプログラムです。

proot は、 chroot 環境等の実現に、プロセスの監視とシステムコールのトレース等を行うための Linux のシステムコールである ptrace を使用しています。

proot は、 proot の子プロセスの実行中において、ファイルのアクセス関連のシステムコールが発生すると、 ptrace を用いてこれらのシステムコームをフックします。そして、ファイルのアクセス先のパス名を適切なものに書き換えることにより、擬似的な chroot 環境等の実現を行います。

ここで、 proot コマンドに -h オプションをつけて起動すると、以下のようなヘルプドキュメントが表示されます。

 $ proot -h
proot v5.0.0-24-gf393b4da-dirty: chroot, mount --bind, and binfmt_misc without privilege/setup.

Usage:
  proot [option] ... [command]


Regular options:
  -r *path*, --rootfs=*path*
    Use *path* as the new guest root file-system, default is /.
...(略)...
  -b *path*, --bind=*path*, -m *path*, --mount=*path*
    Make the content of *path* accessible in the guest rootfs.
...(略)...
  -w *path*, --pwd=*path*, --cwd=*path*
    Set the initial working directory to *path*.
...(略)...

 $

以上のヘルプドキュメントの内容より、 proot コマンドが取る主なコマンドオプションは以下の通りであることが判ります。

  • -r … -r オプションで示されたパス以下をルートディレクトリとして chroot 環境を構築する。
  • -b … -b オプションで示されたパス以下を chroot 環境のディレクトリにバインドし、 chroot 環境から参照できるようにする。
  • -w … chroot 環境の構築後のカレントディレクトリを指定する。
  • [command] … chroot 環境の構築後の実行コマンドを指定する。

例えば、ディレクトリ /mnt/img 以下をルートディレクトリとして chroot 環境を構築し、 bash シェルコマンドを実行する場合は以下のコマンドを起動します。

 $ proot -r /mnt/img /bin/bash
 user@localhost:~$

また、 /mnt/img 以下をルートディレクトリとして chroot 環境を構築し、 chroot 環境の構築後はカレントディレクトリを /root に移動する場合は以下のコマンドを起動します。

 $ proot -r /mnt/img -w /root /bin/bash
 user@localhost:/root$ pwd
 /root
 user@localhost:/root$

そして、 /mnt/img 以下をルートディレクトリとして chroot 環境を構築し、ディレクトリ /dev 及び /proc を chroot 環境のルートディレクトリにバインドして chroot 環境から参照できるようにする場合は以下のコマンドを実行します。

 $ proot -r /mnt/img -b /dev -b /proc /bin/bash
 user@localhost:~$ ls /dev
...
shmem               ptyp5  ptyyf                ttya5    ttytf
binder              ptyp6  ptyz0                ttya6    ttyu0
block               ptyp7  ptyz1                ttya7    ttyu1
...
 user@localhost:~$ 

以上のように、 proot コマンドを用いることにより、 Android OS 及び Linux をカーネルとする各種ディストリビューションにおいて root 権限を取得すること無く、 chroot コマンド及び mount --bind コマンドに基づいた chroot 環境を擬似的に構築することが可能になります。

Debian noroot 環境の起動過程

本章では、 Android OS 上より Debian noroot アプリを起動してから、 Debian noroot 環境に関する各種初期化を行い、 Debian noroot 環境上のウィンドウマネージャが起動されるまでの一連の起動過程について述べます。

本章では最初に、 "Xserver XSDL サーバの起動" の節において、 Android OS 上からの Debian noroot アプリの起動時における Xserver XSDL サーバの起動過程について述べます。
次に、 "proot.sh スクリプトの実行" の節において、 Android OS ネイティブ環境上から Debian noroot 環境において使用する各種環境設定等と Debian noroot 環境の起動のための chroot 環境の構築を行うシェルスクリプトである proot.sh の実行過程について述べます。
最後に、 "startx.sh スクリプトの実行" の節において、 proot.sh スクリプトにおいて構築された chroot 環境上から、 Debian noroot 環境において使用するデスクトップマネージャを起動するためのシェルスクリプトである startx.sh の実行過程について述べます。

Xserver XSDL サーバの起動

本節では、 Debian noroot アプリの起動時における Xserver XSDL サーバの起動コマンドラインの解析を通じて、 Xserver XSDL サーバの一連の起動過程について述べます。

本節では最初に、 "Xserver XSDL サーバの起動コマンドラインを表示する" の項において、Android OS より Debian noroot アプリを起動した時に Xserver XSDL サーバの起動コマンドラインを表示させる手法について述べます。
次に、 "Xserver XSDL サーバの起動コマンドラインの引数の概要" の項において、 Debian noroot のソースコード等の解析等と通じて、 Xserver XSDL サーバの起動コマンドラインの取るオプション及び引数の概要について述べます。
最後に、 "Xserver XSDL サーバの起動過程" の項において、 Android OS から Debian noroot アプリを起動した時の Xserver XSDL サーバの一連の起動過程について述べます。

Xserver XSDL サーバの起動コマンドラインを表示する

最初に Android OS より Debian noroot アプリを起動すると、以下の画像のように Debian noroot アプリの起動画面が表示されます。

(Debian noroot...)

この状態から、Debian noroot アプリの起動画面が表示された直後に画面上部の "Change device config" ボタンをクリックすると、以下の画像のような "Device configuration" なるタイトルのメニューが表示されます。

なお、 "Device configurtion" メニューから、 Debian noroot 環境において使用する Xserver XSDL サーバに関する各種設定を行うことが出来ます。

(Device configuration)

次に、この状態から "Device Configuration" メニューより "Data installation location" を選択すると、以下の画像のように "Data installation location" メニューが表示されます。

(Data installation location)

そして、この状態から "Data install location" メニューより "Specify directory" を選択すると、以下の画像のように "Specify directory" メニューが表示され、ディレクトリの変更を促されますが、このまま何もせずに "OK" ボタンを押します。

(Specify directory)

すると、以下の画像のように "Specify command line parameters" メニューとコマンドラインが表示されます。

(Specify command line parameter)

Xserver XSDL サーバの起動コマンドラインの引数の概要

ここで、 Debian noroot アプリのソースコードより、 "Specify command line parameters" メニューが実装されている箇所を調査すると、 "Specify command line parameters" メニューの実装は CommandlineConfig クラスに存在し、 "Specify command line parameters" メニューにおいて設定されるコマンドラインは Globals クラスのメンバ変数 Globals.CommandLine に格納されることが判ります。

また、 Globals.CommandLine の値は、DemoRenderer クラスのメソッド nativeInit() を介して Android OS ネイティブ環境上の関数 main() に渡され、この関数より android_main() 関数を介して Xserver XSDL サーバのコマンドである XSDL が起動されているので、 "Specify command line parameters" メニューで設定されるコマンドラインが Xserver XSDL サーバのコマンド XSDL に渡されるオプション及び引数であることが判ります。

ここで、 Debian noroot アプリにおける関数 main() 及び Xserver XSDL サーバのコマンド XSDL のソースコードを参照すると、 "Specify command line parameters" メニューのコマンドラインが取る主なオプションの意味は以下の通りであると判ります。

  • -nohelp … Xserver XSDL サーバ画面起動後にヘルプ画面を表示せず、全体を黒い画面のままにする。
  • -screenbuttons … Xserver XSDL サーバ画面上に "Ctrl", "Shift", "Alt" キーの働きをするボタンを表示する。
  • -warndiskspacemb [n] … Debian noroot 環境の最初の起動時において、ストレージ領域の残りが [n] MB 以下の状態ならば警告を表示する。
  • -exec-exec オプション以降の引数を Xserver XSDL サーバの子プロセスとして実行する。

また、 Debian noroot アプリのソースコードより、 "Data installation location" メニュー及び "Specify directory" メニューが実装されている箇所を調査すると、 "Data installation location" メニュー及び "Specify directory" メニューの設定値が Globals クラスのメンバ変数 Globals.DataDir に格納されているが判ります。

上記のことと、Settings クラスの setEnvVars() メソッドの内容から、環境変数 UNSECURE_STORAGE_DIR, SECURE_STORAGE_DIR の値はそれぞれ、 Globals クラスのメンバ変数 Globals.DataDir の値 (通常は /sdcard/Android/data/com.cuntubuntu/files) 及び Debian noroot アプリ内データの永続化領域の絶対パス (通常は /data/data/com.cuntubuntu/files) であることも判ります。

Xserver XSDL サーバの起動過程

以上のことより、 Android OS 上から Debian noroot アプリを起動すると、 Xserver XSDL サーバのヘルプ画面の表示を抑止し、 Xserver XSDL サーバの画面上に "Ctrl", "Shift", "Alt" キーの働きをするボタンを表示した状態で Xserver XSDL サーバを起動することが判りました。

そして、 Xserver XSDL サーバを起動した後は、 Xserver XSDL サーバの画面中央に "Loading Please wait This may take up to one minute." と書かれた画像を表示し、最後に、 Android OS のネイティブ環境上において、シェルスクリプト /data/data/com.cuntubuntu/files/img/proot.sh./startx.sh を引数にして実行する事が判りました。

proot.sh スクリプトの実行

本節では、 Android OS のネイティブ環境において、 Debian noroot 環境上での各種環境の初期設定及び Debian noroot 環境の起動のための chroot 環境の構築を行うシェルスクリプトである proot.sh の一連の実行過程について述べます。

前節の "Xserver XSDL サーバの起動過程" の項において述べたとおり、シェルスクリプト proot.sh の実体は、 /data/data/com.cuntubuntu/files/img/proot.sh に存在し、 Debian noroot 環境上においては、 /proot.sh に存在しています。ここで、 /proot.sh の内容は以下の通りです。

/proot.sh
#!/system/bin/sh

case x$SDCARD in x ) SDCARD=/sdcard;; esac

case x$SECURE_STORAGE_DIR in x ) echo > /dev/null;; * ) cd $SECURE_STORAGE_DIR/img;; esac

case x$SDCARD in x ) export SDCARD=$EXTERNAL_STORAGE;; esac

SDCARD=`../busybox realpath $SDCARD`
STORAGE="-b $SDCARD"
for F in 0 1 2 3 4 5 6 7 8 9; do
    DIR=`eval echo \\$UNSECURE_STORAGE_DIR_$F`
    case x$DIR in x ) echo > /dev/null;; * ) STORAGE="$STORAGE -b $DIR" ; mkdir -p $DIR ;; esac
done
echo "STORAGE $STORAGE"

export HOME=/home/$USER
export SHELL=/bin/bash
export LD_LIBRARY_PATH=
# Java doesn't work in PRoot when started from /usr/bin/java symlink, so we have to put a path to java binary into PATH, and Java 6 fails on Samsung devices
JAVA_PATH=/usr/lib/jvm/default-java/jre/bin:/usr/lib/jvm/default-java/bin
ls usr/lib/jvm/java-7-openjdk-*/bin > /dev/null 2>&1 && JAVA_PATH=/`echo usr/lib/jvm/java-7-openjdk-*/jre/bin`:/`echo usr/lib/jvm/java-7-openjdk-*/bin`
export PATH=/usr/local/sbin:/usr/local/bin:$JAVA_PATH:/usr/sbin:/usr/bin:/sbin:/bin
export "LD_PRELOAD=/libdisableselinux.so /libandroid-shmem.so"
export PROOT_TMPDIR=`pwd`/tmp
export PROOT_TMP_DIR=$PROOT_TMPDIR
export TZ="`getprop persist.sys.timezone`"
./proot -r `pwd` -w / -b /dev -b /proc -b /sys -b /system $STORAGE "$@"

ここで、 前節の "Xserver XSDL サーバの起動コマンドラインの引数の概要" の項より、Settings クラスの setEnvVars() メソッドの内容から、環境変数 SDCARD の値は, Android OS 端末の外部ストレージ領域の絶対パスであり、環境変数 UNSECURE_STORAGE_DIR_[0-9] の値は、 Debian noroot アプリ固有の外部ストレージ領域の絶対パスであることが判ります。

また、環境変数 USER, EXTERNAL_STORAGE はそれぞれ、 Android OS 上のネイティブ環境においてそれぞれ Debian noroot アプリでのユーザ名及び外部ストレージ領域のパス名であることが判ります。

以上のことから、シェルスクリプト proot.sh は、最初に Android OS 端末の外部ストレージ領域の絶対パスを Debian noroot 環境のための chroot 環境にバインドするためのオプションを生成して、 Debian noroot 環境のルートディレクトリ (即ち、 $SECURE_STORAGE_DIR/img = /data/data/com.cuntubuntu/files/img) にカレントディレクトリを移動していることが判りました。

次に、アプリ固有の外部ストレージ領域の絶対パスを chroot 環境にバインドするためのオプションを生成した後、 Debian noroot 環境全体に関連する各種環境変数 HOME、SHELL, PATH, LD_PRELOAD 等の初期化を行っていることが判りました。

最後に、 proot コマンドを用いて、 /data/data/com.cuntubuntu/files/img をルートディレクトリとし、ルートディレクトリを chroot 環境における初期のカレントディレクトリとして、ルートディレクトリに Android OS のネイティブ環境上の /dev, /proc, /sys, /system ディレクトリ及び Android OS 端末の外部ストレージ領域と Debian noroot アプリ固有の外部ストレージ領域の絶対パスをバインドした chroot 環境を構築し、 proot.sh に渡された引数である ./startx.sh を実行することが判りました。

startx.sh スクリプトの実行

本節では、前節で述べたシェルスクリプト proot.sh の実行によって構築された chroot 環境上から、 Debian noroot 環境において使用するデスクトップマネージャを起動し、デスクトップマネージャの終了後にユーザプロセスの終了処理を行うためのシェルスクリプトである startx.sh の一連の実行過程について述べます。

前節で述べたシェルスクリプト proot.sh に引数として渡されるシェルスクリプト ./startx.sh は、 Debian noroot 環境では /startx.sh に存在しています。ここで、シェルスクリプト /startx.sh の内容は以下の通りです。

/startx.sh
#!/bin/sh

rm -f /var/run/dbus/pid
fakeroot-tcp /usr/bin/env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin dbus-daemon --system

sleep 1
dbus-launch --exit-with-session sh -c 'xfce4-session ; setsid sh -c "cd /proc/ ; for f in [0-9]* ; do [ \$f = \$\$ ] || kill -9 \$f ; done"' &

wait

上記のシェルスクリプトの内容より、 startx.sh は最初に、 fakeroot-tcp コマンドを使用した fakeroot 権限に基づいて dbus-daemon デーモンを起動していることが判りました。

そして、 dbus-launch 経由で、デスクトップマネージャの起動コマンドである xfce4-session を実行して、軽量デスクトップマネージャである xfce4 を起動し、 xfce4 の GUI を Xserver XSDL サーバに表示させることで一連の Debian noroot 環境の起動が完了することが判りました。

最後に、 Debian noroot 環境をログアウトして xfce4 を終了した後は、 Android OS 上で起動しているプロセスにシグナル SIGKILL を送信して Debian noroot 環境の子プロセスを強制終了させて、 Debian noroot アプリを終了することが判りました。

結論

本稿では、前々章において、 Debian noroot 環境は、 Debian noroot アプリの開発者である pelya 氏によって開発され、Android OS 上に移植された画像描画や音声再生の API を持つマルチメディアライブラリである SDL を用いて実装された完全な互換性を持つ X Windows System のサーバアプリケーションである Xserver XSDL と、 Android OS 及び Linux をカーネルとする各種ディストリビューションにおいて、 root 権限を取ること無く chroot 環境や mount --bind コマンドに基づくディレクトリのバインドを擬似的に実現するためのプログラムである proot によって実現されていることを述べました。

そして、前章において、 Debian noroot アプリ及び Xserver XSDL のソースコードの解析等を行った結果、 Debian noroot 環境は以下に述べるプロセスに基づいて起動及び終了していることが判明しました。

  • Android OS より Debian noroot アプリを起動した時に、以下の設定に基づいて Xserver XSDL サーバを起動する。
    • Xserver XSDL サーバ画面中央におけるヘルプメッセージの表示を抑止する。
    • Xserver XSDL サーバ画面上に "Ctrl", "Shift", "Alt" キーの働きをするボタンを表示する。
  • Xserver XSDL サーバの起動後に、画面中央に "Loading Please wait This may take up to one minute." のメッセージが書かれた画像を表示する。
  • Android OS のネイティブ環境下でシェルスクリプト /data/data/com.cuntubuntu/files/img/proot.sh./startx.sh を引数にして実行し、以下の処理を行う。
    • Android OS 端末の外部ストレージ領域及び Debian noroot アプリ固有の外部ストレージ領域のバインドオプションの生成を行う。
    • Debian noroot 環境全体に関連する主な環境変数 HOME, SHELL, PATH, LD_PRELOAD 等の設定を行う。
    • /data/data/com.cuntubuntu/files/img をルートディレクトリとして Android OS のネイティブ環境上の /dev, /proc, /sys, /system ディレクトリ及び Android OS 端末の外部ストレージ領域と Debian noroot アプリ固有の外部ストレージ領域の絶対パスをバインドした chroot 環境を構築する。
    • シェルスクリプト proot.sh の引数として渡された ./startx.sh を実行し、 chroot 環境におけるシェルスクリプト startx.sh に制御を移す。
  • /data/data/com.cuntubuntu/files/img をルートディレクトリとした chroot 環境において /startx.sh を実行し、以下の処理を行う。
    • fakeroot-tcp コマンドを用いた fakeroot 権限で dbus-daemon を起動する。
    • dbus-launch 経由で、 xfce4-session コマンドを実行して軽量デスクトップマネージャである xfce4 を起動し、 xfce4 の GUI を Xserver XSDL サーバに表示させることで一連の Debian noroot 環境の起動プロセスが完了する。
  • Debian noroot 環境をログアウトして xfce4 を終了した後は、 Android OS 上で起動しているプロセスにシグナル SIGKILL を送信して Debian noroot 環境の子プロセスを強制終了させて、 Debian noroot アプリを終了する。

以上のことから、 Debian noroot 環境を実現するためのソフトウェアの概要及び Debian noroot 環境の一連の動作過程の解析を通じて、 Debian noroot 環境の動作原理が明らかになりました。

謝辞

本稿の記述に当たって、 Android OS 端末上で非常に軽快な Debian 環境を実現することを可能にした Debian noroot 環境の開発者である pelya 氏に心より感謝致します。本稿における Debian noroot 環境の起動過程の解析に当たっては、 pelya 氏の開発による Debian noroot アプリのソースコード及び Xserver XSDL サーバのコマンド XSDL のソースコードを参考にしました。

また、 Xserver XSDL サーバの起動過程及び proot.sh の実行過程の解析にあたっては、 kakueki61 氏の投稿による "[Android] データの永続化領域について -getFilesDir() vs getExternalFilesDirs()-(アプリ内で取得した画像の置き場所に迷ったので" も併せて参考にしました。 kakueki61 氏に心より感謝致します。

最後に、 Debian noroot 環境と Android OS 及び Debian 環境の全ての事に関わる全ての皆様に心より感謝致します。