前面一節咱們已經講解了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_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] SELinux(Security-Enhanced Linux)是由美國國家安全局(NSA)實現的一種基於「域-類型」模型(domain-type)的強制訪問控制(MAC)安全系統,在這種訪問控制體系的限制下,進程只能訪問它的任務中所須要文件。Linux內核在2.6版本中引入了SELinux,並提供一個可定製的安全策略,同時也提供了不少用戶層的庫和工具。SELinux是目前爲止功能最全面、測試最充分的Linux安全模塊,相應的某些安全相關的應用也被打了SELinux的補丁。設計
[2] 該函數定義在external/libselinux/src/android.c中。
[3] permissive模式表示即便違反了安全策略,也只是會發出警告,而不會真的拒絕執行。