月度归档:2017年01月

how-to-root-android

如何实现Root管理(一)关于ROOT的几个问题

概述

本文将简单介绍CM里对Root权限的开放,关闭,对应用su授权管理进行介绍。内容将涉及init过程,System property的加载,AppOpsManager,Selinux的相关内容。

流程概述:

* 如何让usr版本拥有su的方法:在编译时把su打包到固件里

* 如何实现su的开关:我们期望在init.rc里添加一个service来实现开关su的权限。可以通过修改su.c,修改init相关

* 如何实现应用su的权限管理:修改AppOpsManager来进行管理

理解Root用户,UID和GID

在Linux里用户种类很简单,只有Root和非Root两种。每个进程都有自己的ID(UID),用户组ID(GID),而Root用户的UID和GID都是0。在Android里,每个应用是一个独立的用户运行在独立的虚拟机里,所以应用权限的大小是由它用户的身份决定的。

名称 功能
AID_ROOT 0 ROOT用户
AID_SYSTEM 1000 系统
AID_SHELL 2000 shell用户
AID_APP 10000 第一个app user

一般UID 10000以前都是系统预留用户ID,更多完整的定义可以查看 system/core/android_filesystem_config.h

为什么user版本的adb不能Root

我们可以先查看不同版本下adbd进程的信息,观察不同。

user版本下adb的运行信息

eng,userdebug下的adb

可以观察到在user版本下adb的用户是AID_SHELL,而在userdebug版本下adbd的用户是Root用户。所以这就导致了user版本下无法root。

Note,带root的shell的uid和gid虽然是0,但是它的安全上下文(context)u:r:shell:s0还是shell,所以从shell里生出的进程还是被shell的context所限制。之前android4.4的时候,selinux没有开启的时候。你如果从shell生出来,你就是root用户组了可以胡作非为了。

为什么现在android要root变得艰难

Android 4.3以后,system分区被挂起为nosuid,任何zygote生出来的进程都不能进行setuid的操作。Selinux在Android 5.0后默认开启为enforce模式了,很多操作都受到限制,在selinux打开的情况下修改root权限,用寸步难行来形容真不为过。

su.c

su可以简单的理解为一个类似命令行的程序,它的存放路径为android/platform/system/extras/su ,在编译的时候这个su会被编译为二进制文件存储在系统镜像里system/xbin下,这个文件只有在userdebug,eng下才会编译到系统镜像里,所以user版本的固件是不能调用su。

int main(int argc, char** argv) {
        uid_t current_uid = getuid();
        // 对调用su的身份做检查
        if (current_uid != AID_ROOT && current_uid != AID_SHELL) 
            error(1, 0, "not allowed");
        // 省略...
}

这也是其他进程无法调用su的原因,如果注释掉这一段su就不会对用户id进行检查了(风险很大这样做)。

如何打包su.c进入usr版本

观察su文件夹下的mk文件

发现大量debug的tag,所以在user版本下它不会被打包到固件里。需要把整个TAG的值改为optional。不过我记得当初我去掉以后还是没有打包进去,估计是还有其他地方还有限制。我是修改了产品的mk保证在编译时一定编译这个模块才行的

PRODUCT_PACKAGES += \
    su