Android/SELinux 添加 AVC 權限


Android/SELinux 添加 AVC 權限

背景

在Android應用層中編寫c/c++應用時,發現接口調用出現問題,logcat才知道是因為:權限不夠。

type=1400 audit(0.0:4): avc: denied { create } for scontext=u:r:bootanim:s0 tcontext=u:r:bootanim:s0 tclass=netlink_socket permissive=0

參考:

介紹

安全增強型 Linux(Security-Enhanced Linux)簡稱 SELinux,它是 Linux 的一個安全子系統。SELinux 主要作用是最大限度地減小系統中服務進程可訪問的資源(最小權限原則)。對資源的訪問控制分為兩類: DAC和MAC

SELinux工作模式

SELinux 有三種工作模式,分別為:

  • enforcing: 強制模式, 執行SELinux規則, 違反的行為會被阻止
  • permissive: 寬容模式, 執行SELinux規則, 違反的行不會被阻止
  • disabled: 關閉SELinux

avc denied

在Android系統開發中, 可能會遇到SELinux的權限不足而引起的各種問題;可以嘗試將SELinux工作模式臨時改為寬容模式看問題是否解決, 來判定是否是SELinux引起的問題

標志性 log: avc: denied { 操作權限 } for pid=7201 comm=“進程名” scontext=u:r:源類型:s0 tcontext=u:r:目標類型:s0 tclass=訪問類型 permissive=0

  • 源類型:授予訪問的類型,通常是進程的域類型
  • 目標類型:客體的類型,它被授權可以訪問的類型
  • 訪問類型
  • 操作權限:表示主體對客體訪問時允許的操作類型(也叫做訪問向量)。

舉例

打開三方apk出問題,其中錯誤log如下:

03-28 10:18:07.990 11883 11883 W re-initialized>: type=1400 audit(0.0:2918): 
avc: denied { read } for name="u:object_r:mtk_amslog_prop:s0" 
dev="tmpfs" ino=7544 scontext=u:r:system_app:s0 
tcontext=u:object_r:mtk_amslog_prop:s0 
tclass=file permissive=0

解釋:

  • read:表示沒有 read 權限
  • system_app:system_app 中缺少權限
  • mtk_amslog_prop:mtk_amslog_prop 文件系統缺少權限
  • file:file 類型的文件
  • 分析:adb shell setenforce 0。設置SELinux 成為permissive模式。若apk可正常使用,則進行規避此權限問題

修改selinux規則

type=1400 audit(0.0:4): avc: denied { create } for 
scontext=u:r:bootanim:s0 
tcontext=u:r:bootanim:s0 
tclass=netlink_socket 
permissive=0

type=1400 audit(0.0:41): avc: denied { read } for 
name="u:object_r:media_prop:s0" 
dev="tmpfs" ino=11511 
scontext=u:r:mediacodec:s0 
tcontext=u:object_r:media_prop:s0 
tclass=file 
permissive=0
節點 尋找點 結果
缺少的權限 denied { 權限 } create
誰(哪個進程)缺少權限 scontext=u:r:進程:s0 bootanim
對哪個節點缺少權限 tcontext=u:r:節點:s0 bootanimself
缺少要訪問的對象 tclass=被訪問對象 netlink_socket

技巧:

  • 如果tcontext中的節點與scontext中的進程名相同,則可以寫成self
  • 因為有時候avc denied 的log不是一次性顯示所有問題,要等解決一個權限問題后,才會顯示另外一個權限問題,比如顯示缺失某個目錄的read權限。所以建議是先參考其他可能出現訪問權限的問題的有關接口關鍵字,進行多次添加。
  • 要加入的權限很多時,可以用中括號,比如:allow untrusted_app vfat:dir { search write }

由於,scontext對應的是我們要修改的文件(這里是bootanim),根據type=1400 audit(0.0:4): avc: denied { create } for scontext=u:r:bootanim:s0 tcontext=u:r:bootanim:s0 tclass=netlink_socket permissive=0的提示;因此,需要在bootanim.te最后面中添加所對應的權限是:

# file : bootanim.te
allow bootanim self:netlink_socket {create};

再看一個例子:

# type=1400 audit(0.0:41): avc: denied { read } for 
# name="u:object_r:media_prop:s0" 
# dev="tmpfs" ino=11511 
# scontext=u:r:mediacodec:s0 
# tcontext=u:object_r:media_prop:s0 
# tclass=file permissive=0

# file: mediacodec.te
allow mediacodec media_prop:file {read}

修改系統selinux模式

臨時修改

adb shell setenforce 0 #設置SELinux 成為permissive模式
adb shell setenforce 1 #設置SELinux 成為enforcing模式
adb shell getenforce #獲取SELinux狀態(permissive,enforcing,disabled)

永久修改

安卓7

路徑:system/core/init/init.cpp

static selinux_enforcing_status selinux_status_from_cmdline() {
    selinux_enforcing_status status = SELINUX_ENFORCING;   // 強制模式, 執行SELinux規則, 違反的行為會被阻止
    //selinux_enforcing_status status = SELINUX_PERMISSIVE;// 寬容模式, 執行SELinux規則, 違反的行不會被阻止
    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;
}

安卓9/10

路徑:system/core/init/selinux.cpp

EnforcingStatus StatusFromCmdline() {
    // EnforcingStatus status = SELINUX_ENFORCING;// 強制模式, 執行SELinux規則, 違反的行為會被阻止
    EnforcingStatus status = SELINUX_PERMISSIVE;  // 寬容模式, 執行SELinux規則, 違反的行不會被阻止
    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;
}

附錄A:在permissive模式下,有些app仍然無法訪問具體節點

敏感權限的特征:log中帶有c512,c768字樣

試着在untrusted_app.te 中添加了allow untrusted_app audio_device:chr_file { open write read };還是報如下權限錯誤:

[ 141.935275] type=1400 audit(1546939304.786:43): avc: denied { write } for 
pid=1836 comm="Thread-4"
name="pcmC0D1c"
dev="tmpfs"
ino=11947
scontext=u:r:untrusted_app:s0:c512,c768
tcontext=u:object_r:audio_device:s0
tclass=chr_file
permissive=1

先確認需要訪問的節點是否為audio_device,這個節點屬於敏感權限,可以的話請修改訪問的目錄和文件,縮小audio_device的范圍

方法為:

1、確定訪問的節點位置,通過源碼或者log確定到底訪問的哪一個具體的節點, 例如 /dev/pcmc00xx

2、在相應的te文件中新聲明一個節點名稱, 如 file.te: type test_audio_device, dev_type;

3、在file_context中將具體節點綁定新的節點名稱, 如: file_context: /dev/pcmc00xx test_audio_device

4、增加或修改需要的權限: allow untrusted_app test_audio_device:chr_file { open write read };

如果不過GMS認證,敏感權限(c512,c768)可以直接把對象關聯mlstrustedobject, 但不推薦這樣修改,會造成嚴重的安全問題。 例如: typeattribute audio_device mlstrustedobject;

附錄B:DAC和MAC有什么區別?

DAC

DAC(Discretionary Access Control,自主訪問控制)

  • DAC是傳統的Linux的訪問控制方式,DAC可以對文件、文件夾、共享資源等進行訪問控制。
  • 在DAC這種模型中,文件客體的所有者(或者管理員)負責管理訪問控制。
  • DAC使用了ACL(Access Control List,訪問控制列表)來給非管理者用戶提供不同的權限,而root用戶對文件系統有完全自由的控制權。

MAC

MAC(Mandatory Access Control,強制訪問控制)

  • SELinux在內核中使用MAC檢查操作是否允許。
  • 在MAC這種模型中,系統管理員管理負責訪問控制,用戶不能直接改變強制訪問控制屬性。
  • MAC可以定義所有的進程(稱為主體)對系統的其他部分(文件、設備、socket、端口和其它進程等,稱為客體)進行操作的權限或許可。

DAC和MAC的其它區別

① DAC的主體是真實有效的用戶和組ID,MAC的主體是安全上下文,兩者的UID是各自獨立的。

② DAC的訪問控制模式是rwxrwxrwx,MAC的訪問控制模式是user:role:type。

附錄C:高通平台修改selinux權限路徑

Android 7 :device/qcom/sepolicy/common/

Android 9:其中的某一個

  • device/qcom/sepolicy/vendor/common/
  • device/sprd/sharkl3/common/sepolicy/

Android 10:其中的某一個

  • device/qcom/sepolicy/vendor/common/
  • device/qcom/sepolicy/legacy/vendor/common/
  • device/sprd/sharkl3/common/sepolicy/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM