SELinux簡介和解決方法

lethe1203發表於2024-04-05
網路參考資料:
SEAndroid學習筆記 - 簡書 (jianshu.com)
Android系統SELinux簡單整理_android selinux 編譯除錯-CSDN部落格
【Android】Selinux許可權問題記錄_se許可權為啥type 不能加init-CSDN部落格
SELinux許可權問題分析與修改_violated by allow-CSDN部落格
Android O selinux違反Neverallow解決辦法-CSDN部落格
Android 使用者組許可權,SELinux心得總結_android android_ids[] 高版本-CSDN部落格
SELinux(Security-Enhanced Linux)是由美國國家安全域性(NSA)開發的一種強制訪問控制機制。它主要整合在 Linux 核心當中,是針對特定的程序與指定的檔案資源進行許可權控制的系統。主要是增強傳統 Linux 作業系統的安全性,並解決傳統 Linux 系統中自主訪問控制(DAC)系統中的各種許可權問題(如 root 許可權過高等)。

一、DAC(自主訪問控制)

DAC全稱為:Discretionary Access Control
DAC 是傳統 UNIX 和 Linux 系統的訪問控制模型,它基於使用者對資源的擁有權和許可權。在 DAC 模型下,使用者擁有對自己建立的檔案和目錄的完全控制權,可以自由設定檔案的訪問許可權(讀、寫、執行)以及共享許可權(使用者組、其他使用者)。
ls -l顯示檔案的屬性前面的10個字元就代表了Linux對改檔案的訪問控制

二、MAC(強制訪問控制)

MAC全稱為Mandatory Access Control
MAC 是在 DAC 模型之上的一個額外的安全層,它強制施加系統管理員定義的訪問策略,以確保系統資源的安全性。在 Android 中,SELinux 是實現 MAC 的主要機制之一。與 DAC 不同,MAC 不允許使用者或程序直接設定或修改物件的訪問策略,而是由系統管理員透過 SELinux 策略檔案來配置訪問規則。
Android系統SELinux的兩種工作模式:
1. Permissive工作模式(寬容模式)
2. Enforcing工作模式(強制模式)

三、基本概念

1、主體(subject)     基本等同於程序
2. 客體(object) 被主體訪問的資源:檔案(含可執行檔案),目錄,節點等
3. 安全上下文(secure context)
ls -Z      // 顯示檔案(如果是目錄則顯示其路徑下的檔案)的安全上下文
ps -eZ   // 顯示程序的安全上下文
Id -Z    // 可以顯示shell的安全上下文

安全上下文格式:
舉例:u:object_r:system_file:s0

user:role:type[:range] 
user:使用者;
role:角色,一個user可以有多個role,不通的role擁有不同的許可權
type:主體or客體的型別;
range:說是跟MLS有關,簡單點說,MLS將系統的    程序和檔案進行了分級,不同級別的資源需要對應級別的程序才能訪問。

四、策略規則語句格式

allow domains types:classes permissions;

- Domain - 一個程序或一組程序的標籤。也稱為域型別,因為它只是指程序的型別。
- Type - 一個物件(例如,檔案、套接字)或一組物件的標籤
- Class - 要訪問的物件(例如,檔案、套接字)的型別。
- Permission - 要執行的操作(例如,讀取、寫入)。跟~可以將兩個操作聯合起來 (如:allow unconfineddomain {fs_type dev_type file_type}:{ chr_file file }~{entrypoint relabelto};)

= allow : 允許主體對客體進行操作
= neverallow :拒絕主體對客體進行操作
= dontaudit : 表示不記錄某條違反規則的決策資訊
= auditallow :記錄某項決策資訊,通常 SElinux 只記錄失敗的資訊,應用這條規則後會記錄成功的決策資訊。

= class可見system/sepolicy/private/security_classes中的定義
# file-related classesclass filesystem
class file  #代表普通檔案
class dir   #代表目錄
class fd    #代表檔案描述符
class lnk_file  #代表連結檔案
class chr_file  #代表字元裝置檔案

# network-related classes
class socket   #socket
class tcp_socket
class udp_socket

......
class binder   #Android 平臺特有的 binder
class zygote   #Android 平臺特有的 zygote

= permissions可見system/sepolicy/private/access_vectors
其中inherits表示繼承了某個common定義的許可權

五、型別type

#type命令的完整格式為:type type_id [alias alias_id,] [attribute_id]

#其中,方括號中的內容為可選。alias指定了type的別名,可以指定多個別名。

#下面這個例子定義了一個名為shell的type,它和一個名為domain的屬性(attribute)關聯
type shell, domain; #本例來自shell.te,注意,可以關聯多個attribute
sepolicy 現在分為多個部分:
public - 非平臺策略開發人員可以在其上編寫的匯出策略附加政策。型別和屬性被版本化幷包含在下發非平臺政策,與平臺政策相結合。
private - 平臺功能所需的僅平臺策略,但不會匯出給供應商策略開發人員,因此可能不會假設存在。
vendor - 供應商功能所需的僅限供應商策略。這個政策可以參考公共政策,但不能參考私人政策。這策略適用於從核心/非供應商樹生成的元件,並且放入供應商分割槽。

SELinux解決辦法:

adb shell getenforce 可檢視裝置selinux模式
adb shell setenforce 可設定裝置selinux模式(0:permissive;1:enforcing)
te檔案一般存在於system/sepolicy/,device/qcom/sepolicy/,external/selinux以及某些三方廠商自己預置的te檔案(不好定位具體路徑),一般在device/qcom/sepolicy/(generic|legacy)/路徑下去新增selinux規則

1、可以關閉SELinux

修改system/core/init/selinux.cpp檔案:
b shell getenforce 可檢視裝置selinux模式
adb shell setenforce 可設定裝置selinux模式(0:permissive;1:enforcing)
 te檔案一般存在於system/sepolicy/,device/qcom/sepolicy/,external/selinux以及某些三方廠商自己預置的te檔案(不好定位具體路徑),一般我們在device/qcom/sepolicy/(generic|legacy)/路徑下去新增selinux規則

1、可以關閉SELinux
修改system/core/init/selinux.cpp檔案:
EnforcingStatus StatusFromCmdline() {
    EnforcingStatus status = SELINUX_PERMISSIVE;    // ******

    import_kernel_cmdline(false,
                          [&](const std::string& key, const std::string& value, bool in_qemu) {
                              if (key == "androidboot.selinux" && value == "permissive") {
                                  status = SELINUX_PERMISSIVE;
                              }
                          });

    return status;
}

bool IsEnforcing() { 
    return false;            // ******
    if (IsUserBuild()) {
        if (RootValueFromCmdline())
            return false;
        else
            return true;
    }

    if (ALLOW_PERMISSIVE_SELINUX) {
        return StatusFromCmdline() == SELINUX_ENFORCING;
    }
    return true;
}

2、手動新增許可權

一般許可權問題都會在log檔案中列印,可透過過濾avc關鍵字檢視,如下:
auditd  : type=1400 audit(0.0:1275): avc: denied { open } for comm="monitor-thread" 
path="/sys/devices/platform/soc/1c08000.qcom,pcie/pci0001:00/0001:00:00.0/0001:01:00.0/net/eth0/operstate" dev="sysfs" ino=63866 
scontext=u:r:system_app:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1
分析過程:
哪個程序缺少許可權:monitor-thread
缺少什麼許可權: { open}許可權,
誰缺少許可權: u:r:system_app:s0
對哪個檔案缺少許可權:u:object_r:sysfs:s0
什麼型別的檔案: file
完整的意思: monitor-thread(system_app)程序對sysfs型別的file缺少open許可權。
接下來只需要在system_app.te檔案中加入:
allow system_app sysfs:file open即可(全編譯會報錯,因為這句程式碼是給所有system_app程序開放了所有檔案的open許可權)

3、使用audit2allow工具新增規則

在ubuntu下執行:adb shell dmesg |grep avc > avc;audit2allow -i avc,例:
0
直接把規則複製貼上到對應的te檔案中(如上圖應該將規則貼上於system_app.te檔案中)
有時候avc denied的log不是一次性暴露所有許可權問題,要等解決一個許可權問題之後,才會暴露另外一個許可權問題。比如提示缺少某個目錄的read許可權,加入read之後,才顯示缺少write許可權,要一次次一次試,一次一次加,時間成本極大。
針對dir缺少的任何許可權,建議賦予create_dir_perms,基本涵蓋對dir的所有許可權,比如:{ open search write read rename create rmdir getattr }等等。
針對file缺少的任何許可權,建議賦予rwx_file_perms,基本涵蓋對file的所有許可權,比如:包含{ open read write open execute getattr create ioctl }等等。

4、自定義規則**

給節點加許可權,這類情況使用audit2allow工具一般就會給你一句:allow xxx sysfs:file {read getattr open},然後貼到對應的te檔案中,全編報錯:neverallow xxxvim
因為sysf:file 相當於我們開放了所有檔案的許可權,這是不被允許的,所以我們只能對節點單獨新增規則(如我給/sys/class/net/eth0/operate新增許可權):
在裝置內部執行ls -l /sys/class/net/eth0/ 發現他是個軟連結(給軟連結新增規則是無效的),

具體路徑是/sys/devices/platform/soc/1c08000.qcom,pcie/pci0001:00/0001:00:00.0/0001:01:00.0/net/eth0/operstate

然後在file_contexts中加上新的scontext,如下(sysfs_eth是自定義的型別):
/sys/devices/platform/soc/1c08000.qcom,pcie/pci0001:00/0001:00:00.0/0001:01:00.0/net/eth0/operstate          u:object_r:sysfs_eth:s0

之後在file.te中加上:
# eth0 statustype sysfs_eth, fs_type, sysfs_type;

最後去system_app.te檔案中新增規則:
allow system_app sysfs_eth:file { read getattr open };
allow system_app sysfs_eth:dir search;

常見編譯問題:

1、ERROR 'duplicate declaration of type/attribute' at token ';' on line 14430
解決方法:type的重定義,把你自定義的type給改了;
2、neverallow
原生selinux不允許賦予該許可權,如果專案無需過CTS,可以在system/sepolicy中去掉該項規則,如需過CTS,需找尋其他方式;

相關文章