http://www.gcd.org/blog/2010/12/682/#more-682
先週末 IS01 で root 権限が必要なアプリが使えるようになったばかりなのに、 そのわずか 4日後、スマートフォン@2ch掲示板に以下の書き込みがあり、 カーネル空間への侵入口が明らかにされてしまった。 一番乗りを果たした goroh_kun さんに敬意を表しつつも、 IS01 のプロテクトがこの程度だったことが残念でもある。 「root を取られても大丈夫な作りになっている」 と開発者が豪語し、 しかも IS01 の発売から 5ヶ月間も破られなかったのだから、 さぞかし鉄壁の守りなのだろうと思っていたのに、 こんな分かりやすい穴があったとわ... (負け惜しみ ^^;)。
【ROM焼き】au IS01 root2 〜わたくし達も未来へ〜
...
317 :goroh_kun:2010/12/01(水) 03:14:21 ID:LGLTLBmZ
自動起動仕込むところを大体見つけました。
どなたか協力お願いします。
/data/の直下にlocal.propを置く
ここで、内容をoverrideできます。
サービス起動時のおダイナミックライブラリがある
サービスプログラムを探す。
getpropしてみると、
rild.libpathが/system/lib/libril-qc-1.soといかにも起動時に使っていそう。
rildaemonから使われているプラグインと思われます。
そこで、
local.propの中身を
rild.libpath=/data/lib/libril-wrapper.so
rild.wrapper.cmd=/data/rootkit.boot.sh
rild.libpath2=/system/lib/libril-qc-1.so
で、このプラグインを/data配下から読み出されるようにして、
libril-wrapper.soにて、ダイナミックロード時に
自動実行したいプログラムを指定できるようにします。
で、自動実行したいプログラムをlibril-wrapper.soで実行後
本来のrild用のプラグインをロードして、rildに引き渡すようにします。
これでいけるのではないかと思っているのですが、やるよって方は
いらっしゃいますか?
rild.libpath プロパティは、 RIL (Radio Interface Layer) デーモン rild が参照している。 rild は rild.libpath の値をダイナミックライブラリのパス名として dlopen(3) に渡し、 dlsym(3) でライブラリ内の関数 RIL_Init 呼び出す。 つまり、 rild が起動される前に rild.libpath の値を書き換えておけば、 rild に任意のプログラムを起動時に実行させることが可能になる。
したがって守る側 (つまり開発者の立場) から考えると、 (1) rild.libpath が書き換えられないようにするか (2) 任意のプログラムの実行が脅威にならないよう、 rild 起動前に防御を固めてしまえばよい。
プロパティは、 以下の 4 つのファイルで設定できる。 どれか一つでも改変可能であれば、 (1) の方法は使えない。
- /default.prop
- /system/build.prop
- /system/default.prop
- /data/local.prop
IS01 の場合、 (たとえ root が奪取されても) /system ディレクトリ下は改変できないようになっている。 また、 /default.prop は initramfs 内のファイルなので、 改変しても再起動すれば揮発してしまう。 だから上記 4ファイルのうち /data/local.prop 以外は改変不可能。
Android では /system ディレクトリ下は read only でも構わないが、 /data ディレクトリ下は Android 動作中に書き換えることが前提となっている。 もちろん /data/local.prop だけは書き換え不可能にするとか、 あるいは再起動時に自動的に /data/local.prop を書き戻す、 という方法も考えられなくもないが、 そもそも論で言えば /data/local.prop は、 システムのプロパティをオーバーライドするための設定ファイルであって、 その本来の趣旨からいえば書き換え不可能にすることは望ましくない。
したがって守るなら (2) の方法が自然。 というか、 /data/local.prop で rild.libpath の値を変更されても、 rild はユーザ空間で動くデーモンなのだから、 本来は 「任意のプログラムの実行」 が可能でも脅威にはならないはず。
ところが IS01 の開発チームは致命的なミスを犯した。
IS01 の /init.rc から引用:
... on boot # basic network init ifup lo hostname localhost domainname localdomain ... setprop net.pppbtdg.servIp 1.2.3.4 setprop net.pppbtdg.clientIp 1.2.3.5 setprop net.pppbtdg.portspeed 115200 setprop net.bt.data.option 0 # 0 - eth0 ; 1 - gprs no dial required; 2 - gprs dial required ## SHARP_EXTEND MotionEmojiFactory 2009.10.14 Add-Start setprop ro.config.libmotionemoji libmotionemoji_impl.so ## SHARP_EXTEND MotionEmojiFactory 2009.10.14 Add-End class_start default # 2009.10.06 sbc H.Nozaki Add setprop wifi.interface wlan0 # SC Shirakawa 2010/03/10 <- prohibit insmod after start-up insmod /system/lib/modules/unifi_sdio.ko setprop wlan.driver.status loaded # SC Shirakawa 2010/03/10 -> prohibit insmod after start-up write /proc/sys/kernel/modules_disabled 1 ## Daemon processes to be run by init. ## service console /system/bin/sh console ... service ril-daemon /system/bin/rild socket rild stream 660 root radio socket rild-debug stream 660 radio system user root group radio cache inet misc ...
「on boot」 から始まる一連のブートスクリプトはデーモン類の起動前に実行される。 だから普通に init.rc を記述すれば 防御を完璧にした後に、 デーモン類を起動することになる。 そうしていれば、 デーモン類に多少のセキュリティホールがあっても問題にはならなかっただろう。
ところが、 何を血迷ったか sbc H.Nozaki さんは 「class_start default」 の後にスクリプト 「setprop wifi.interface wlan0」 を書いてしまった (2009年10月6日)。
「class_start default」 はデーモン類の起動命令である。 この行の後にスクリプトを書いても構わないが、 そのスクリプトとデーモンの処理と、 どちらが先に実行されるかはタイミング次第ということになる。 デーモンを起動する前に実行すべきブートスクリプトは 「class_start default」 の行より前に書かなければならない。
sbc H.Nozaki さんが書き加えたのは、 wifi.interface プロパティの値を 「wlan0」 に設定する処理で、 普通に考えればデーモン類の起動 「class_start default」 より前に書く方が素直だが、 wifi.interface プロパティを参照するタイミングはずっと後なので、 どこに書こうが大差ない。 なので特に問題視もされず、 そのままになってしまったのだろう。
しかしながら、 sbc H.Nozaki さんがこの変更を行なった結果、 2009年10月14日時点での init.rc は以下のようになってしまう:
... ## SHARP_EXTEND MotionEmojiFactory 2009.10.14 Add-Start setprop ro.config.libmotionemoji libmotionemoji_impl.so ## SHARP_EXTEND MotionEmojiFactory 2009.10.14 Add-End class_start default # 2009.10.06 sbc H.Nozaki Add setprop wifi.interface wlan0 ## Daemon processes to be run by init. ## service console /system/bin/sh console ...
「## Daemon processes to be run by init.」 というコメント行があることも相俟って、 その直前までがブートスクリプトであるかのように見えてしまう。 実際は 「class_start default」 の前に書かなければならないのに。
その 5ヶ月後、 IS01 発表 (3月30日) の直前、 SC Shirakawa さんが IS01 のプロテクトの最大の要 「write /proc/sys/kernel/modules_disabled 1」 を、 「## Daemon processes to be run by init.」 の直前に書いてしまったことを誰が責められるだろうか。 まあ、 ちょっと見渡せばすぐ上に 「class_start default」 と書いてあるのが見えただろうから、 この行の意味を少しでも考えていたらこのようなミスは避けられたかも。
「write /proc/sys/kernel/modules_disabled 1」 を実行することにより、 それ以降カーネルモジュールをロード (insmod) することが禁止される。 すなわちカーネル空間へ侵入することが格段に難しくなる。 OS に脆弱性が無ければ (そんなことはまず無いが) カーネル空間への侵入は不可能と言ってもいい。
ところが既にデーモン類の起動命令 「class_start default」 は発行してしまった。 後は野となれ山となれ、 一斉に走り出したデーモン類において任意のコードが実行可能であれば、 insmod が禁止される前に、 そのデーモンに任意のモジュールを insmod させてカーネル空間への侵入が果たせてしまう。
dmesg で見るとこんな感じ:
... <6>[ 0.008933] Memory: 232MB = 232MB total <5>[ 0.008960] Memory: 157824KB available (4828K code, 1499K data, 160K init) <6>[ 0.009273] Calibrating delay loop... 511.18 BogoMIPS (lpj=2555904) <6>[ 0.240166] Security Framework initialized <6>[ 0.240193] DECKARD LSM module initialized ... <6>[ 8.061633] init: command 'setprop' r=0 <6>[ 8.061666] init: command 'setprop' r=0 <6>[ 8.061699] init: command 'setprop' r=0 <6>[ 8.061739] init: command 'setprop' r=0 <6>[ 8.061759] init: command 'setprop' r=0 <3>[ 8.061773] init: service 'console' requires console <5>[ 8.086566] init: starting 'logd' <5>[ 8.088086] init: starting 'dgstmgrd' <5>[ 8.105699] init: starting 'servicemanager' <5>[ 8.108533] init: starting 'vold' <6>[ 8.109439] init: Created socket '/dev/socket/vold' with mode '660', user '0', group '1009' <5>[ 8.111886] init: starting 'usbmgrd' <6>[ 8.112773] init: Created socket '/dev/socket/usbmgrd' with mode '660', user '0', group '1009' <5>[ 8.163386] init: starting 'debuggerd' <5>[ 8.167306] init: starting 'fotad' <5>[ 8.170679] init: starting 'ril-daemon' <6>[ 8.171473] init: Created socket '/dev/socket/rild-debug' with mode '660', user '1001', group '1000' <6>[ 8.171753] init: Created socket '/dev/socket/rild' with mode '660', user '0', group '1001' ... <6>[ 13.184319] init: command 'class_start' r=0 <6>[ 13.184353] init: command 'setprop' r=0 ... <6>[ 13.653133] init: command 'insmod' r=0 <6>[ 13.653179] init: command 'setprop' r=0 <6>[ 13.653786] init: command 'write' r=0
8.061759秒の 「init: command 'setprop' r=0」 が 「class_start default」 直前の
「setprop ro.config.libmotionemoji libmotionemoji_impl.so」 を実行したときの出力。 その後、 デーモン類を次々と起動し、 「class_start default」 の実行が完了するのは 5秒以上たった 13.184319秒時点。 「write /proc/sys/kernel/modules_disabled 1」 を実行してようやく insmod が禁止できたのは、 さらに 0.5秒もたってからで、 その間に rild はカーネル空間への侵入口を提供してくれた。
goroh_kun さんの発表からわずか 2時間後の 5:28 (なんちゅー時間だ)、 goroh_kun さん自身によって、 mtd0 (カーネルイメージ), mtd2 (リカバリイメージ), mtd5 (/system) を変更可能にするカーネルモジュール msm_nand_ex.ko が発表され、 これを rild に insmod させることによってカーネルイメージ等の改変が可能になった。
なので早速 (といっても平日は時間が取れないので週末になってから) カーネルを再構築してみる。 SHARP が公開している IS01 のカーネルを menuconfig してビルドする:
% make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig ... % make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- ... LD vmlinux SYSMAP System.map SYSMAP .tmp_System.map OBJCOPY arch/arm/boot/Image Kernel: arch/arm/boot/Image is ready ... % cp -a arch/arm/boot/Image ~/tmp/IS01/kernel.bin
当然のことながら、 にっくき (Android とりわけ Nexus の敵) デッカードを消す。 勢い余って CONFIG_SECURITY=n にした。 また、kernel/drivers/mtd/devices/msm_nand.c に、 「#define CONFIG_ANDROID_ENGINEERING 1」 を追加して MTD protect を丸ごと消してしまう (12/9追記: menuconfig でも CONFIG_ANDROID_ENGINEERING を設定可能なので、 msm_nand.c を書き換えるよりは menuconfig にて設定した方がよい)。 これで IS01 特有のプロテクトは全て無くなる。 ついでに CONFIG_SWAP=y を設定した。
--- config 2010-11-24 07:40:41.051499180 +0900 +++ .config 2010-12-04 10:30:27.037625342 +0900 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.29 -# Mon Sep 20 04:09:00 2010 +# Sat Dec 4 10:30:27 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -36,7 +36,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="$(KERNEL_LOCAL_VERSION)-perf" # CONFIG_LOCALVERSION_AUTO is not set -# CONFIG_SWAP is not set +CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y # CONFIG_POSIX_MQUEUE is not set @@ -430,7 +430,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_TCP_MD5SIG is not set # CONFIG_IPV6 is not set -# CONFIG_NETLABEL is not set CONFIG_ANDROID_PARANOID_NETWORK=y # CONFIG_NETWORK_SECMARK is not set CONFIG_NETFILTER=y @@ -492,7 +491,6 @@ # CONFIG_IP_NF_TARGET_ULOG is not set # CONFIG_IP_NF_MANGLE is not set # CONFIG_IP_NF_RAW is not set -# CONFIG_IP_NF_SECURITY is not set # CONFIG_IP_NF_ARPTABLES is not set # CONFIG_IP_DCCP is not set # CONFIG_IP_SCTP is not set @@ -1661,14 +1659,9 @@ # Security options # # CONFIG_KEYS is not set -CONFIG_SECURITY=y +# CONFIG_SECURITY is not set # CONFIG_SECURITYFS is not set -# CONFIG_SECURITY_NETWORK is not set -CONFIG_SECURITY_PATH=y # CONFIG_SECURITY_FILE_CAPABILITIES is not set -CONFIG_SECURITY_DECKARD=y -CONFIG_SECURITY_DECKARD_SYSTEM_DEV_PATH="/dev/block/mtdblock5" -CONFIG_SECURITY_DECKARD_CHROOT_PATH="" CONFIG_CRYPTO=y #
カーネルの次は initramfs の改変。
/init.rc における防御の要をコメントアウト:
--- init.rc.org 1970-01-01 09:00:00.000000000 +0900 +++ init.rc 2010-12-04 11:24:53.943962272 +0900 @@ -361,7 +361,7 @@ insmod /system/lib/modules/unifi_sdio.ko setprop wlan.driver.status loaded # SC Shirakawa 2010/03/10 -> prohibit insmod after start-up -write /proc/sys/kernel/modules_disabled 1 +#write /proc/sys/kernel/modules_disabled 1 ## Daemon processes to be run by init. ##
ついでに /default.prop も書き換えてより使いやすく ;-)
--- default.prop.org 1970-01-01 09:00:00.000000000 +0900 +++ default.prop 2010-12-04 11:24:59.013753953 +0900 @@ -3,5 +3,5 @@ # ro.secure=1 ro.allow.mock.location=0 -ro.debuggable=0 -persist.service.adb.enable=0 +ro.debuggable=1 +persist.service.adb.enable=1
ビルドしたカーネル kernel.bin と、 initramfs を cpio で固めた ramdisk.bin から、 mkbootimg コマンドを使ってブートイメージ boot.img を作る:
senri:/home/sengoku % fg %su # find . | cpio -o -H newc > ~sengoku/tmp/IS01/ramdisk.bin 591 blocks # suspend senri:/home/sengoku % cd ~/tmp/IS01/ senri:/home/sengoku/tmp/IS01 % ls -l kernel.bin ramdisk.bin -rwxr-xr-x 1 sengoku wheel 5312864 Dec 4 10:40 kernel.bin -rw-r--r-- 1 root root 302592 Dec 4 10:44 ramdisk.bin senri:/home/sengoku/tmp/IS01 % mkbootimg --kernel kernel.bin --ramdisk ramdisk.bin --cmdline "console=ttyMSM2,115200n8 androidboot.hardware=qcom" --base 0x20000000 -o boot.img
ただし IS01 のブートイメージは、 Android Donut 標準の mkbootimg が作るブートイメージとは若干差異があった。 IS01 のブートイメージでは、 ramdisk_addr が 0x03000000 ほど後ろへずれていて、 かつ padding が 2048 バイト区切りではなく 4096 バイト区切りになっていた。 なので、 以下のようなパッチをあてる:
--- system/core/mkbootimg/mkbootimg.c.org 2010-11-27 09:46:55.000000000 +0900 +++ system/core/mkbootimg/mkbootimg.c 2010-12-04 10:13:46.381056328 +0900 @@ -71,7 +71,7 @@ -static unsigned char padding[2048] = { 0, }; +static unsigned char padding[4096] = { 0, }; int write_padding(int fd, unsigned pagesize, unsigned itemsize) { @@ -143,7 +143,7 @@ } else if(!strcmp(arg, "--base")) { unsigned base = strtoul(val, 0, 16); hdr.kernel_addr = base + 0x00008000; - hdr.ramdisk_addr = base + 0x01000000; + hdr.ramdisk_addr = base + 0x04000000; hdr.second_addr = base + 0x00F00000; hdr.tags_addr = base + 0x00000100; } else if(!strcmp(arg, "--board")) { @@ -229,10 +229,10 @@ } if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail; - if(write_padding(fd, pagesize, sizeof(hdr))) goto fail; + if(write_padding(fd, pagesize*2, sizeof(hdr))) goto fail; if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail; - if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail; + if(write_padding(fd, pagesize*2, hdr.kernel_size)) goto fail; if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail; if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
Android Donut 標準と異なる点はまだあって、 IS01 のブートイメージは UBI (Unsorted Block Images) 上にある。 なので ubinize コマンド (mtd-utils に含まれる) を使って 「UBI 化」 してからフラッシュに書込まねばならない。
senri:/home/sengoku/tmp/IS01 % ls -l boot.img -rw-r--r-- 1 sengoku user 5623808 Dec 4 10:48 boot.img senri:/home/sengoku/tmp/IS01 % ubinize -o ubi.img -p 128KiB -m 2048 -O 256 ubi.cfg
IS01 のブートイメージでは、 VID header offset として 256 を指定する必要があるので、 ubinize コマンドに 「-O 256」 オプションを指定している。 また、 ubinize は設定ファイルを引数に与える必要があるので、 以下のようなファイル ubi.cfg を作って ubinize を実行する。
[boot] mode=ubi image=boot.img vol_id=0 vol_size=200MiB vol_type=dynamic vol_name=boot vol_flags=autoresize
こうしてできた IS01 ブートイメージ ubi.img を、 adb push して IS01 に送り込み、 IS01 上で flash_image コマンドを使ってフラッシュへ書込む:
senri:/home/sengoku/tmp/IS01 % ls -l ubi.img -rw-r--r-- 1 sengoku user 6029312 Dec 4 10:48 ubi.img senri:/home/sengoku/tmp/IS01 % adb push ubi.img /sdcard/tmp/ 1937 KB/s (6029312 bytes in 3.038s) senri:/home/sengoku/tmp/IS01 % adb shell $ su # cat /proc/mtd dev: size erasesize name mtd0: 00b00000 00020000 "boot" mtd1: 00500000 00020000 "cache" mtd2: 00b00000 00020000 "recovery" mtd3: 00180000 00020000 "splash" mtd4: 00b40000 00020000 "ipl" mtd5: 10000000 00020000 "system" mtd6: 00300000 00020000 "log" mtd7: 06420000 00020000 "userdata" mtd8: 00b00000 00020000 "boot_wr" mtd9: 00b00000 00020000 "recovery_wr" mtd10: 10000000 00020000 "system_rw" # flash_image recovery_wr /sdcard/tmp/ubi.img # exit senri:/home/sengoku/tmp/IS01 % adb reboot recovery
すでに goroh_kun さんのカーネルモジュール msm_nand_ex.ko を insmod してあるので、 書込み可能な boot_wr および recovery_wr パーティションがある。 ブートイメージは boot_wr と recovery_wr どちらにも書込むことができるが、 まずは実験として recovery_wr へ書込んだ。 boot_wr (と system_rw) さえ変更しなければ、 失敗しても文鎮化は避けられる。 つまり何か問題が起きても、 リセットスイッチを押せば boot パーティションから起動する。
adb reboot recovery すれば recovery パーティションから起動する。
12/9 追記: IS01 を工場出荷状態に初期化する操作を行うと、 recovery パーティションから起動して初期化処理を行うらしい (未確認)。 つまり recovery パーティションに書き込んだイメージが期待されている処理 (つまり初期化処理) を行わずに、 通常のブートイメージの処理 (つまり IS01 の通常の起動) を行うと、 再び初期化処理に入ろうとして recovery パーティションから再起動させて無限ループに陥る恐れがある (憶測)。
もちろん、 「初期化」 しても書き換えたブートイメージは元には戻らないわけで、 いったん boot / recovery を書き換えたら、 決して 「初期化処理」 は行うべきではないし、 「初期化処理」 以外にも recovery パーティションを使用する処理があると思われる (おそらく、ケータイアップデートなど) ので、 実験目的での recovery 書き換えの後は、 なるべく速やかに元のイメージ (あるいは同等の処理を行うイメージ) に書き戻しておくほうが無難。
前述したように /default.prop を書き換えて 「ro.debuggable=1」 にしたので、 使い勝手が向上している ;-) 例えば、 以下のように 「adb root」 が可能になっている。
dmesg すると、 以前は 0.240193秒あたりに出ていた 「DECKARD LSM module initialized」 という出力が消えているのが分かる。 さよならデッカード!
senri:/home/sengoku/tmp/IS01 % adb root restarting adbd as root senri:/home/sengoku/tmp/IS01 % adb shell # dmesg <5>[ 0.000000] Linux version 2.6.29-perf (sengoku@senri.gcd.org) (gcc version 4.3.5 (GCC) ) #3 PREEMPT Sat Dec 4 10:40:33 JST 2010 <4>[ 0.000000] CPU: ARMv7 Processor [510f00f2] revision 2 (ARMv7), cr=10c5387f <4>[ 0.000000] CPU: VIPT nonaliasing data cache, VIVT ASID tagged instruction cache <4>[ 0.000000] Machine: SHARP DECKARD ... <6>[ 0.008700] Memory: 232MB = 232MB total <5>[ 0.008720] Memory: 157952KB available (4792K code, 1480K data, 160K init) <6>[ 0.009040] Calibrating delay loop... 511.18 BogoMIPS (lpj=2555904) <4>[ 0.240286] Mount-cache hash table entries: 512 <6>[ 0.240753] CPU: Testing write buffer coherency: ok <6>[ 0.242906] net_namespace: 444 bytes <6>[ 0.243606] NET: Registered protocol family 16 <6>[ 0.245393] socinfo_init: v2, id=30, ver=2.0, raw_id=640, raw_ver=2 <3>[ 0.245406] qsd8x50_cfg_smc91x: invalid machine type <6>[ 0.245433] Max ACPU freq from efuse data is 998400 KHz <6>[ 0.246006] ACPU running at 768000 KHz <6>[ 0.246020] 5 scaling frequencies supported. <4>[ 0.267433] bio: create slab <bio-0> at 0 <5>[ 0.268873] SCSI subsystem initialized <6>[ 0.269166] msm_i2c_probe <6>[ 0.269206] msm_i2c_probe: clk_ctl 317, 369230 Hz <6>[ 0.273240] Bluetooth: Core ver 2.15 <6>[ 0.273493] NET: Registered protocol family 31 <6>[ 0.273506] Bluetooth: HCI device and connection manager initialized <6>[ 0.273526] Bluetooth: HCI socket layer initialized <6>[ 0.275353] NET: Registered protocol family 2 <6>[ 0.275533] IP route cache hash table entries: 2048 (order: 1, 8192 bytes) <6>[ 0.275873] TCP established hash table entries: 8192 (order: 4, 65536 bytes) <6>[ 0.276046] TCP bind hash table entries: 8192 (order: 3, 32768 bytes) <6>[ 0.276126] TCP: Hash tables configured (established 8192 bind 8192) <6>[ 0.276140] TCP reno registered <6>[ 0.276320] NET: Registered protocol family 1 <6>[ 0.276713] checking if image is initramfs... it is <6>[ 0.278820] Freeing initrd memory: 292K ... # dd if=/dev/zero of=/data/swapfile bs=1048576 count=64 64+0 records in 64+0 records out 67108864 bytes transferred in 11.703 secs (5734330 bytes/sec) # mkswap /data/swapfile Setting up swapspace version 1, size = 67104768 bytes # swapon /data/swapfile # free free total used free shared buffers Mem: 158576 155480 3096 0 1184 Swap: 64620 0 64620 Total: 223196 155480 67716 #
ついでに有効にした SWAP が使えるようになっている。 フラッシュの損耗を考えると、 常用はしないほうが無難?
0 件のコメント:
コメントを投稿