沒有setuid怎麼實現su程序?

現在的安卓手機root需要的su程序,已經不再需要setuid許可權了,下圖是我的酷派大神的su,755沒有setuid,

下圖是mount命令的輸出,很多掛載點都加了nosuid選項,

還用了分離掛載命名空間(好像是這麼叫),

在安卓app上/data和/system都是nosuid,在adb shell里沒有,

也就是說就算設置了setuid許可權,在安卓app上也用不了,

那麼這種情況,這個su程序是怎麼實現的呢?完全無法想像,

我只知道有root賬戶的setuid許可權可以簡單的通過setuid函數改id,

沒有setuid許可權的話該怎麼讓普通許可權賬戶改id呢?

這個su程序的源代碼上哪裡能得到?

----------------2015/10/25----------

確實如馬宏菩所說,有個root許可權的守護進程用來提權,

那麼新的問題來了,一個root許可權進程怎麼把別人提成root許可權,貌似sudo就是干這個的,

----------------2015/12/10--------------

sudo並不是這樣的,sudo也是利用setuid,

問題已經基本解決了,還有點小問題,

shell里執行su命令,把自己的tty信息發給root許可權的守護程序deamon,關閉文件描述符012,然後阻塞,

然後deamon只要用fork得到一個後台進程,把文件描述符012都改成和那個shell一樣的,再運行新的sh,

這樣就可以,在那個shell看來,就是su命令得到一個root許可權的sh,

再讓這個sh死掉的時候帶上那個su一起死,就可以和正常的su一樣退出後回到原來的shell,

一切順利,都能寫出來,

但是在deamon產生新的sh的時候,雖然能用的,但總會報個錯,

就是那兩行,搞不懂,


我對現在新版安卓的 root 並不熟悉,只是提出幾點猜想,並且提供一些驗證手段。

一、使用了 mount namespace ,初始(系統) namespace 應該是沒有設置 nosuid ,但是所有的應用都是跑在一個設置了 nosuid 的 mount namespace 里。

可以看到 adb shell 里的 /system 是沒有設置 nosuid 的(順帶一提,印象中 su 的 binary 應該是在 /system 下面的來著)。然而以 app 形式運行的 terminal 里卻看到 /system 也有 nosuid 。要驗證的話還可以去 /proc/[PID]/ns 里看看([PID]可以是 self 來表示當前進程)。

然而, setns 切換 namespace 也是需要 root 許可權的……這樣一來普通應用使用 root 許可權時就陷入了一個死循環……我能想到的辦法,就是下面這個:

二、有某個 su daemon 長期運行。

如果在開機的時候,從初始的 namespace 里啟動一個 su daemon ,來處理各個 su call 的話(即應用調用 su 時其實並不是直接提升到 root ,而是 IPC 轉發給了這個 daemon ),一切就變得容易了很多。至少有兩條路可走:1. 這個 daemon 本身就是 root 用戶,這樣一來也就無所謂 setuid 了;2. 這個 daemon 以非特權用戶運行,然而是有 setuid 的。

至於這個 daemon 本身,可以是和 su 本身是同一個 binary (通過 args[0] 或者命令行參數來區別),也可以是 patch 某一個本來就會開機自動運行的程序,等等……

更新:翻了一下 SuperSU 的 zip 刷機包,果然看到了這個東西:

# Launches SuperSU in daemon mode only on Android 4.3+.
# Nothing will happen on 4.2.x or older, unless SELinux+Enforcing.
# If you want to force loading the daemon, use "--daemon" instead

/system/xbin/daemonsu --auto-daemon

利用的是 install-recovery.sh 之類的會開機自動運行的腳本來調用的。而且果然是因為新版安卓更強的安全策略才引入的這個 daemon 。 zip 包里沒看到 daemonsu 這個文件,我猜是安裝的時候創建一個符號鏈接(感謝 @Ourd Nant ,是直接拷貝的)。


@馬宏菩說的對,就是有個daemon,而且 Supersu 確實是和 su 本身是同一個 binary

以下討論僅限 Supersu

啟動方式是 /system/etc/init.d/99SuperSUDaemon

daemonsu 就是 su

需要用 daemon 的原因倒不是 nosuid,主要是 SELinux 的問題。不使用 daemon ,沒什麼好方法可以獲得許可權更大的 context (daemon 是 init)

安裝過程在 update-binary

IPC 的方式不記得了。。


APP想要執行"su -c cmdxxx",如果su是setuid的,owner是root,運行是root許可權的這句就跑起來了,但是沒有setuid,所以su是普通許可權的,這樣這句運行失敗。

操作系統有很多daemon service,它們是開機自動運行的。有的是以root許可權跑起來再自行降許可權到應有許可權,有的是直接以應有許可權啟動。當拿到臨時root後,可以用腳本替換掉某個第一種daemon service,然後這個腳本再把應啟動的service啟動。這時腳本是root許可權運行,可以做很多事,比如額外啟動daemonsu,daemonsu就是以root許可權啟動的了。

APP請求su時,還是請求的普通許可權su,su把命令傳給daemon su運行即可


推薦閱讀:

為什麼手機有root,而計算機卻沒有?
手機root後對手機有什麼影響?
安卓手機root有很多功能但不穩定,不root的話又處處受限,這是個無奈的悖論么?

TAG:Linux | Android開發 | RootAndroid | Android | 許可權 |