temporaryなめも帳

だらだらと備忘録とか。誰かの為になることをねがって。

Androidのsuコマンドの実装

suコマンド(user-debugでビルドするとついてくる子)がどう実装されているのか、気になったので調べました。

suが実際にやっていることは、setuid/setgidを0/0で呼び出すことです。 呼び出す前にセキュリティチェックを行なっており、AID_ROOTかAID_SYSTEM以外のUIDからは実行できないように弾いています。

/* Until we have something better, only root and the shell can use su. */
myuid = getuid();
if (myuid != AID_ROOT && myuid != AID_SHELL) {
    fprintf(stderr,"su: uid %d not allowed to sun", myuid);
    return 1;
}

treeのソースを読んでみて、だいたいの流れが分かったので、真似てsuモドキを作ってみました。

Android.mk

ポイントはLOCAL_FORCE_STATIC_EXECUTABLEのあたり。 静的リンクとしないとsetuid/setgidがsegfaultします。

include $(CLEAR_VARS)

LOCAL_MODULE := susample
LOCAL_SRC_FILES := susample.c
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_STATIC_LIBRARIES := libc

include $(BUILD_EXECUTABLE) 

setuid/setgid

このツールでは、setuid/setgidした後、rootのshを立ち上げるだけとしました。 権限チェックも無し!危険!

int main(int argc, char *argv[])
{
    uid_t uid = 0, myuid;
    gid_t gid = 0;

    myuid = getuid();
    printf("myuid = %dn", myuid);

    if(setgid(gid) || setuid(uid)){
        printf("su: permission denied");
        return 1;
    }

    printf("su: exec shn");
    execlp("/system/bin/sh", "sh", NULL);
    return 1;
}

Permissionを整える

最後に、AndroidへPushした後、バイナリに権限をつけるのを忘れてハマりました。 setuid/setgidを利用するため、パーミッションの4桁目を設定する必要があります。(Ubuntuなどでは u+s とかするやつですね。) setuid(4)/setgid(2)/stiky(1)となっているので、6755あたりをひとまず設定しておくとよさげ。

# chmod 6755 susample
# ls -la
-rwsrwsrwx root     root       182440 2014-06-24 02:20 susample