SELinux 和 chroot 系統呼叫
TL; DR:這是一個關於最後一步的問題,在一個可移植的、面向開發人員的生根過程中,它適用於所有 Android 機器。它不是基於任何漏洞利用——這是法律和道德上允許我們作為開發人員對我們自己的機器做的事情。如果我得到答案並設法在我的 Debian 中進行 chroot,我將撰寫一篇簡明的博文,詳細介紹此過程的所有步驟,供所有希望 root 訪問其平板電腦且不想信任 dubious-origin 的開發人員使用對他們的機器(殭屍網路成員?)做上帝知道什麼的“一鍵根”……唯一的依賴項將是機器的核心源(製造商有法律義務提供)和引導分區映像(
boot.img
),這是 99% 的時間在製造商提供的無線更新中,或者作為獨立的可快閃記憶體映像單獨下載。所以,一周過去了,我把所有的空閒時間都花在了我的新 Android 平板電腦上。
而且我幾乎完全成功 - 創建了一個可移植的、面向開發人員的流程,以便在我的 Android 5.0.2 平板電腦中實現 root。
但是還缺少一件事——我不能做 chroot(我需要執行我的
debootstrap
-ed Debian!)到目前為止我做了什麼
- 首先,我在平板電腦的(製造商提供的)核心原始碼中做了一個小更新檔,然後編譯了我自己的核心——我在其中禁用了更改SELINUX 強制模式的檢查。具體來說…
在
security/selinux/selinuxfs.c
:... if (new_value != selinux_enforcing) { /* Commented out by ttsiodras. length = task_has_security(current, SECURITY__SETENFORCE); if (length) goto out; */ audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, "enforcing=%d old_enforcing=%d auid=%u ses=%u", new_value, selinux_enforcing,
- 然後我將我的 initrd 圖像更改
/default.prop
為包含:ro.secure=0
和ro.debuggable=1
- 由於我的製造商
initrd.img
缺少它,我還su.c
從https://android.googlesource.com/platform/system/extras/+/master/su/編譯並將生成的二進製文件放在 下/sbin
,確保將其設置為 SUID root (chmod 04755 /sbin/su
) .之後,我打包了新核心和新 initrd,正如我在上一篇文章的第 2 集中解釋的那樣- 並從我自己的映像啟動:
adb reboot boot-loader ; fastboot boot myboot.img
那麼,你是root嗎?
是的,它最初似乎是成功的:
$ adb shell shell@K01E_2:/ $ id uid=2000(shell) gid=2000(shell) groups=1004(input),1007(log),1011(adb), 1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt), 3003(inet),3006(net_bw_stats) context=u:r:shell:s0 shell@K01E_2:/ $ ls -l /sbin/su /sbin/_su -rwxr-xr-x root root 131 2015-10-03 10:44 su -rwsr-xr-x root root 9420 2015-10-03 01:31 _su (the _su is the binary I compiled, set to SUID root, and "su" is a script I wrote to tell "su" to add me to all these groups...) shell@K01E_2:/ $ cat /sbin/su #!/system/bin/sh export PATH=/system/bin:$PATH exec /sbin/_su 0,0,1000,1028,2000,2001,1004,1007,1011,1015,\ 1028,3001,3002,3003,3006
我現在已經獲得了root權限:
shell@K01E_2:/ $ su root@K01E_2:/ # id uid=0(root) gid=0(root) groups=1000(system),1004(input),1007(log),1011(adb), 1015(sdcard_rw),1028(sdcard_r),1028(sdcard_r),2000(shell),2001(cache), 3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats) context=u:r:shell:s0
我 100% 確定我是 root - 不僅因為
id
這樣說,而且因為我還可以做正常流程絕對不能做的事情:root@K01E_2:/ # ls -l /dev/block/platform/msm_sdcc.1/by-name/boot lrwxrwxrwx root root 2015-10-03 10:47 boot -> /dev/block/mmcblk0p16 root@K01E_2:/ # dd if=/dev/block/mmcblk0p16 of=/dev/null bs=1M 16+0 records in 16+0 records out 16777216 bytes transferred in 0.569 secs (29485441 bytes/sec)
瞧——我終於可以從我的平板電腦中讀取原始分區了!
SELinux 確實處於“down, dog” 模式:
root@K01E_2:/ # getenforce Permissive
但是……還有一些我不能做的事情:
root@K01E_2:/ # mkdir /my_mnt root@K01E_2:/ # mount -t ext4 /dev/block/mmcblk1p2 /my_mnt mount: Operation not permitted
也就是說,我無法掛載我的外部 SD 卡的 EXT4-fs 格式的第二個分區。
我也無法 chroot 到我可愛的
debootstrap
-ed Debian:root@K01E_2:/ # chroot /data/debian/ /bin/bash chroot() fail Operation not permitted
是因為 SELinux 嗎?
我不知道 - 我是 SELinux 的新手(非常新 - 一周大)。我認為當你讓它進入睡眠狀態時(
getenforce
報告“許可”)它不再乾擾……顯然,我錯了。我們又去了兔子洞……
可能是因為我的流程上下文嗎?
請記住,
id
返回… “uid=0(root) gid=0(root)… context=u:r:shell:s0 "我可以改變那個上下文嗎?作為根和所有,我可以離開
shell
嗎?如果是這樣,移動到什麼?第一個問題的答案是
runcon
:shell@K01E_2:/ $ runcon u:r:debuggerd:s0 /sbin/su root@K01E_2:/ # id uid=0(root) gid=0(root)... context=u:r:debuggerd:s0
好的。但是什麼上下文將允許我
mount
和chroot
?閱讀更多關於 SELinux 的資訊,回到我的主機中,我解析
/sepolicy
了根目錄下的文件initrd.img
:linuxbox$ $ sesearch -A sepolicy | grep chroot allow init_shell init_shell : capability { chown sys_chroot ... allow init init : capability { chown dac_read_search sys_chroot ... allow kernel kernel : capability { chown dac_override sys_chroot ... allow asus-dbug-d asus-dbug-d : capability { chown sys_chroot ... ...
好的,有多種可能性!尤其是那個
kernel
看起來很有希望的:shell@K01E_2:/ $ runcon u:r:kernel:s0 /sbin/su root@K01E_2:/ # id uid=0(root) gid=0(root)... context=u:r:kernel:s0 root@K01E_2:/ # chroot /data/debian/ /bin/bash chroot() fail Operation not permitted
該死。
到底是誰在阻止我
chroot
?歡迎任何建議…
誰在阻止我chroot?
這不是 SELinux - 那是一場瘋狂的追逐(
getenforce
返回“Permissive”意味著 SELinux 確實不再出現在圖片中)。罪魁禍首——在核心的原始碼中添加了相當多
printk
的程式碼來跟踪兩者的故障之後chroot
——mount
結果是能力。更具體地說,Android 的“能力邊界集”——你可以通過你的man
(man 7 capabilities
) 閱讀所有關於它們的資訊,我承認我以前從未費心研究它們——我的日常 UNIX 任務依賴於它們,我不知道……試試這個你的 linux 盒子自己看看:$ getfattr -d -m - /sbin/ping getfattr: Removing leading '/' from absolute path names # file: sbin/ping security.capability=0s......
看?Ping 不再是 SUID root - 它使用儲存在文件系統擴展屬性中的資訊來知道它可以訪問原始套接字層(因此它可以做 ICMP 的事情 - 在 IP 級別)。
無論如何,我離題了——我的核心中的手術點,我停止了“放棄我的能力集”——以一種可以說是令人作嘔的“讓他們都前進”的方式——這是(
security/commoncap.c
):static long cap_prctl_drop(struct cred *new, unsigned long cap) { if (!capable(CAP_SETPCAP)) return -EPERM; if (!cap_valid(cap)) return -EINVAL; // ttsiodras: come in, everyone, the water's fine! //cap_lower(new->cap_bset, cap); return 0; }
這意味著功能永遠不會被丟棄 - 確實是一個非常安全的配置:-)
$ adb shell shell@K01E_2:/ $ su root@K01E_2:/ # chroot /data/debian/ /bin/bash root@localhost:/# export PATH=/bin:/sbin:/usr/bin:/usr/sbin:\ /usr/local/bin:$PATH root@localhost:/# cat /etc/issue Debian GNU/Linux 8 \n \l
你好,我親愛的 Debian :-)
哦,“Root checker”也可以工作——我剪掉了“su.c”,所以我平板電腦中的每個人都可以成為root:
int main(int argc, char **argv) { struct passwd *pw; uid_t uid, myuid; gid_t gid, gids[50]; /* Until we have something better, only root and shell can use su. */ myuid = getuid(); // // ttsiodras - Oh no, you don't :-) // //if (myuid != AID_ROOT && myuid != AID_SHELL) { // fprintf(stderr,"su: uid %d not allowed to su\n", myuid); // return 1; //}
現在它工作了,我必須讓它正常工作 - 即只允許我
termux
和Terminal Emulator
使用者呼叫su
andchroot
,而不是讓每個人和他們的祖母進入:-)