修改Android10系統原始碼關閉selinux
技術標籤:Android系統核心ubuntuandroid作業系統app安全
一、seandroid簡介
SEAndroid是Google在Android4.4上正式推出的一套以SELinux為核心的系統安全機制。在Android原始碼中,系統預設的seandroid配置存放如下路徑:
/home/qiang/lineageOs/system/sepolicy
目錄中存放了比如adbd、system_server、系統app、第三方app等te配置檔案。
由於Android系統引進了seandroid策略。強化了app對資源的訪問限制。安全性大大提高。比如舉一個獲取wifi mac的例子為例說明:
在android app中很多app通過讀取/sys/class/net/wlan0/address來獲取手機的wifi mac地址。通過adb 命令檢視該檔案的許可權如下:
C:\Users\Qiang>adb shell ls -la /sys/class/net/wlan0/address
-r--r--r-- 1 root root 4096 2021-01-12 14:57 /sys/class/net/wlan0/address
以上說明手機的app都可以讀取訪問該檔案。但是在Android10中,系統配置了普通App不能讀取/sys/class/net/wlan0/address的seandroid策略許可權。導致Android 10 中讀取失敗,提示許可權拒絕。由於seandroid強化了系統安全性,要想一個App訪問訪問系統的某一個目錄或者路徑,需要專門去配置te檔案策略。對於不熟悉seandroid配置的開發者配置起來有點難度。那有沒有辦法不配置seandroid策略檔案,設定檔案或者目錄可讀許可權就能訪問的方法。答案就是全域性關閉seandroid
二、安卓中關閉seandroid的方式討論
1.使用setenforce命令臨時關閉
命令如下
adb shell setenforce 0
setenforce命令只能暫時關閉seandroid,如果手機重啟了會被恢復為正常狀態。
setenforce在安卓原始碼中的路徑如下:
external/toybox/toys/android/setenforce.c
setenforce實現程式碼如下:
#define FOR_setenforce
#include "toys.h"
void setenforce_main(void)
{
char *new = *toys.optargs;
int state, ret;
if (!is_selinux_enabled()) error_exit("SELinux is disabled");
else if (!strcmp(new, "1") || !strcasecmp(new, "enforcing")) state = 1;
else if (!strcmp(new, "0") || !strcasecmp(new, "permissive")) state = 0;
else error_exit("Invalid state: %s", new);
ret = security_setenforce(state);
if (ret == -1) perror_msg("Couldn't set enforcing status to '%s'", new);
}
從以上程式碼可知,setenforce最終呼叫的是函式security_setenforce完成selinux的控制。
2.在kernel 關閉 selinux
在核心中配置SECURITY_SELINUX設定為 false,重新編譯kernel刷機。可以永久關閉seandroid。
以下是測試的核心編譯中.config檔案中關閉selinux之後的配置資訊:
CONFIG_SECURITY_SELINUX=n
3.在init程序啟動的時候關閉selinux
安卓系統啟動過程中,init程序會進行selinux的初始化。通過讀取/proc/cmdline檔案,判斷androidboot.selinux的值是否需要開啟selinux。因此,我們可以init程序初始化selinux的時候強制執行關閉操作。
以下將討論第三種方案來實現全域性關閉selinux。
三、init程序中全域性關閉selinux
1.init程序中selinux的初始化流程分析
init程序中selinux初始化相關的檔案路徑如下:
system/core/init/selinux.cpp
system/core/init/main.cpp
大概的初始化流程如下:
a.main.cpp中的main函式呼叫selinux.cpp中的SetupSelinux:
intmain(intargc,char**argv){
...省略
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
...省略
}
b.selinux.cpp中SetupSelinux函式實現如下:
int SetupSelinux(char** argv) {
...省略
SelinuxInitialize();
...省略
return 1;
}
c.SetupSelinux呼叫了SelinuxInitialize方法。SelinuxInitialize方法程式碼如下:
//SelinuxInitialize中可以看到呼叫了IsEnforcing方法判斷
voidSelinuxInitialize(){
...省略
bool kernel_enforcing = (security_getenforce() == 1);
//判斷是否強制模式
boolis_enforcing=IsEnforcing();
if (kernel_enforcing != is_enforcing) {
//呼叫security_setenforce函式,和setenforce原理一樣
if (security_setenforce(is_enforcing)) {
PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
}
}
...省略
}
d.IsEnforcing方法實現如下:
//判斷是否需要強制模式
bool IsEnforcing() {
if (ALLOW_PERMISSIVE_SELINUX) {
return StatusFromCmdline() == SELINUX_ENFORCING;
}
return true;
}
從IsEnforcing中可以知道,如果一直返回false,那麼將會關閉selinux。
2.全域性強制關閉selinux修改
從以上init程序初始化selinux的流程可以提供兩種修改方案來全域性關閉。
-
第一種修改IsEnforcing函式永遠返回false。修改如下:
bool IsEnforcing() {
///ADDSTART
if(1>0)
{
//一直返回false
return false;
}
///ADD END
if (ALLOW_PERMISSIVE_SELINUX) {
return StatusFromCmdline() == SELINUX_ENFORCING;
}
return true;
}
-
第二種修改SelinuxInitialize方法,在函式中主動呼叫security_setenforce(false)。修改之後如下:
void SelinuxInitialize() {
Timer t;
LOG(INFO) << "Loading SELinux policy";
if (!LoadPolicy()) {
LOG(FATAL) << "Unable to load SELinux policy";
}
bool kernel_enforcing = (security_getenforce() == 1);
bool is_enforcing = IsEnforcing();
if (kernel_enforcing != is_enforcing) {
if (security_setenforce(is_enforcing)) {
PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
}
}
//直接呼叫security_setenforce方法來關閉
///ADD START
security_setenforce(false);
///ADD END
if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) {
LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
}
// init's first stage can't set properties, so pass the time to the second stage.
setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
}
修改之後編譯原始碼刷機,開機之後生效。
玩轉Android10系統原始碼開發定製更多文章:
玩轉Android10原始碼開發定製(二)刷機操作之fastboot刷機演示
玩轉Android10原始碼開發定製(二)刷機操作之Recovery刷機演示
玩轉Android10原始碼開發定製(三)原始碼中編譯手機刷機包
玩轉Android10原始碼開發定製(四)原始碼開發環境搭建
玩轉Android10原始碼開發定製(五)原始碼編譯開發中常用命令
玩轉Android10原始碼開發定製(六)修改核心原始碼繞過反除錯檢測
玩轉Android10原始碼開發定製(七)修改ptrace繞過反除錯
玩轉Android10原始碼開發定製(九)內建frida-gadget so檔案和frida-server可執行檔案到系統
玩轉Android10原始碼開發定製(十)增加獲取當前執行最頂層的Activity命令
玩轉Android10原始碼開發定製(11)核心篇之安卓核心模組開發編譯
玩轉Android10原始碼開發定製(12)核心篇之logcat輸出核心日誌
關注公眾號獲取更多最新文章