鳥人的Android揭祕(11)——Init進程源代碼分析(二)

      前面一節咱們已經講解了init進程對目錄生成和掛載、日誌初始化和設置,接下來init進程將初始化SELinux[1]並設置policy文件,以下面代碼所示。若要詳細瞭解SELinux的設計原理和工做機制,須要用一整本書來說解,因爲篇幅所限,在此咱們不過多涉及這方面的內容。init進程運行在用戶空間,主要涉及對SELinux的掛載和配置,下面咱們把重點放在這個過程上。linux

static void selinux_initialize(bool in_kernel_domain) {
    selinux_callback cb;            
    cb.func_log = selinux_klog_callback;
    selinux_set_callback(SELINUX_CB_LOG, cb);                         <---(1)
    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
    if (in_kernel_domain) {
        INFO("Loading SELinux policy...\n");
        if (selinux_android_load_policy() < 0) {                      <--- (2)
            ERROR("failed to load policy: %s\n", strerror(errno));
            security_failure();
        }
        bool kernel_enforcing = (security_getenforce() == 1);
        bool is_enforcing = selinux_is_enforcing();
        if (kernel_enforcing != is_enforcing) {                       <--- (3)
            if (security_setenforce(is_enforcing)) {
                ERROR("security_setenforce(%s) failed: %s\n",
                      is_enforcing ? "true" : "false", strerror(errno));
                security_failure();
            }
        }
        if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) {  <--- (4)
            security_failure();
        }
    ...
}
int main(int argc, char** argv) {
    ...
    selinux_initialize(is_first_stage);
    ...
}

(1) selinux_initialize()函數調用selinux_set_callback()函數設置兩個全局的回調函數指針「selinux_log」和「selinux_audit」。android

(2) 調用selinux_android_load_policy()[2]函數加載並向內核設置策略,selinux_initialize()函數的主要做用就是從文件中讀取SELinux的配置文件,而後把它設置到內核中,這樣SELinux才能開始工做。數組

(3) 檢查是否強制使用用SELinux,有兩種方法能夠配置,一是SELinux掛載目錄下的enforce文件,其中只有一個數字值表示SELinux的當前狀態,0表示不強制使用(permissive[3]),1則表示強制使用(enforcing);其次是/proc/cmdline文件,在其中加入「androidboot.selinux= permissive」字段表示不強制使用(permissive),不然強制使用(enforcing),這種方法主要用於開發或調試版本。安全

(4) 在「/sys/fs/selinux/checkreqprot」文件中寫入校驗結果,若是寫入成功,則SELinux設置完畢,可正常使用。dom

      上述代碼的(2)所示selinux_android_load_policy()函數是加載SELinux的主要邏輯代碼,以下面的代碼所示,selinux_android_load_policy()函數嘗試將SELinux的虛擬文件系統selinuxfs掛載到「/sys/fs/selinux」節點上,造成下面的圖所示的層次結構。函數

rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);

      若是內核沒有啓用SELinux,則「/sys/fs/selinux」掛載失敗,selinux_android_load_policy()函數繼續嘗試在根目錄下建立「/selinux」節點並掛載,若是再次失敗則SELinux初始化失敗。工具

掛載SELinux節點

      在SELinux掛載成功後,調用selinux_android_load_policy_helper()函數裝載policy文件。selinux_android_load_policy_helper()函數首先調用set_policy_index()函數設置policy文件的索引,目的是爲了打開在sepolicy_file數組中定義的policy文件,而後調用mmap()函數把它映射到內存中,最後調用函數security_load_policy()把policy設置到內核中。policy文件的文件名保存在數組sepolicy_file中,定義以下面的代碼所示。測試

static const char *const sepolicy_file[] = {
    "/sepolicy",
    "/data/security/current/sepolicy",
    NULL };

      至此,SELinux的初始化就講解完了。如前一篇鳥人的Android揭祕(10)——Init進程源代碼分析(一)所說,init進程將切換到第二階段的初始化過程。下一節咱們將講解init進程對屬性的初始化和屬性服務的啓動。.net

 

 

 

[1] SELinuxSecurity-Enhanced Linux)是由美國國家安全局(NSA)實現的一種基於「域-類型」模型(domain-type)的強制訪問控制(MAC)安全系統,在這種訪問控制體系的限制下,進程只能訪問它的任務中所須要文件。Linux內核在2.6版本中引入了SELinux,並提供一個可定製的安全策略,同時也提供了不少用戶層的庫和工具。SELinux是目前爲止功能最全面、測試最充分的Linux安全模塊,相應的某些安全相關的應用也被打了SELinux的補丁。設計

[2] 該函數定義在external/libselinux/src/android.c中。

[3] permissive模式表示即便違反了安全策略,也只是會發出警告,而不會真的拒絕執行。

相關文章
相關標籤/搜索