深刻理解SELinux/SEAndroid(最後部分)

接第二部分的內容(http://blog.csdn.net/innost/article/details/19641487html

SEAndroid最後一部分java

全文PDF下載地址爲:http://vdisk.weibo.com/s/z68f8l0xZUS9wlinux

 

     深刻理解SELinux/SEAndroid(結局)

 

 

二  SEAndroid源碼分析

有了上文的SELinux的基礎知識,本節再來看看Google是如何在Android平臺定製SELinux的。如前文所示,Android平臺中的SELinuxSEAndroidandroid

先來看SEAndroid安全策略文件的編譯。web

 

1.  編譯sepolicy

Android平臺中:shell

  • external/sepolicy:提供了Android平臺中的安全策略源文件。同時,該目錄下的tools還提供了諸如m4,checkpolicy等編譯安全策略文件的工具。注意,這些工具運行於主機(即不是提供給Android系統使用的)
  • external/libselinux:提供了Android平臺中的libselinux,供Android系統使用。
  • external/libsepol:提供了供安全策略文件編譯時使用的一個工具checkcon

對咱們而言,最重要的仍是external/sepolicy。因此先來看它。安全

讀者還記得上文提到的如何查看make命令的執行狀況嗎?經過:app

mmm external/sepolicy  --just-printdom

,咱們能夠看到sepolicy編譯時都幹了些什麼。socket

#之後用SEPOLICY_TEMP代替

#     out/target/product/generic/obj/ETC/sepolicy_intermediates字符串

 

#建立臨時目錄

mkdir -p out/target/product/generic/obj/ETC/sepolicy_intermediates/

 

#----->處理一堆輸入源文件,最終輸出爲policy.conf

#執行m4命令,用來生成plicy.conf文件。m4命令將擴展SEAndroid定義的一些宏

m4 -D mls_num_sens=1 -D mls_num_cats=1024 -s

#m4的輸入文件。下面標黑體的是SEAndroid一些系統相關的文件,通常不會修改它

security_classes   initial_sids access_vectors

global_macros mls_macros mls

policy_capabilities te_macros attributes

#Android系統中的te文件。

adbd.te app.te bluetoothd.te  bluetooth.te   clatd.te dbusd.te debuggerd.te device.te dhcp.te dnsmasq.te domain.te drmserver.te file.te gpsd.te hci_attach.te healthd.te hostapd.te init_shell.te init.te installd.te isolated_app.te kernel.te keystore.te media_app.te mediaserver.te mtp.te netd.te net.te nfc.te ping.te platform_app.te ppp.te property.te qemud.te racoon.te radio.te release_app.te rild.te runas.te sdcardd.te servicemanager.te shared_app.te shell.te surfaceflinger.te su.te system.te tee.te ueventd.te unconfined.te untrusted_app.te vold.te watchdogd.te wpa_supplicant.te zygote.te

#其餘文件

roles  users initial_sid_contexts fs_use genfs_contexts port_contexts

#m4:將上述源文件處理完後,生成policy.conf

> SEPOLICY_TEMP/policy.conf

 

 

#下面這個命令將根據policy.conf中的內容,再生成一個policy.conf.dontaudit文件

sed '/dontaudit/d'

           SEPOLICY_TEMP/policy.conf >

           SEPOLICY_TEMP/policy.conf.dontaudit

 

mkdir -p SEPOLICY_TEMP/

#------>根據policy.conf文件,生成二進制文件。SEAndroid中,它叫sepolicy

#執行checkpolicy,輸入是policy.conf,輸出是sepolicy

#-M選項表示支持MLS

checkpolicy -M -c 26 -o SEPOLICY_TEMP/sepolicy

                             SEPOLICY_TEMP/policy.conf

#執行checkpolicy,輸入是policy.conf.dontaudit,輸出是sepolicy.dontaudit

checkpolicy -M -c 26 -o

            SEPOLICY_TEMP/sepolicy.dontaudit    

           SEPOLICY_TEMP/policy.conf.dontaudit

 

#--->將sepolicy拷貝到對應目標平臺的root目錄下

echo "Install: out/target/product/generic/root/sepolicy"

acp -fp SEPOLICY_TEMP/sepolicy

                  out/target/product/generic/root/sepolicy

 

#---->生成file_context文件

#用FILE_CONTEXT_TEMP代替

#    out/target/product/generic/obj/ETC/file_contexts_intermediates字符串

mkdir -p FILE_CONTEXT_TEMP/

m4 -s  external/sepolicy/file_contexts  > FILE_CONTEXT_TEMP/file_contexts

checkfc  SEPOLICY_TEMP/sepolicy

                  FILE_CONTEXT_TEMP/file_contexts

echo "Install: out/target/product/generic/root/file_contexts"

acp -fp FILE_CONTEXT_TEMP/file_contexts

                     out/target/product/generic/root/file_contexts

 

#--->生成seapp_context文件,這個是Android平臺特有的,其做用咱們下文再介紹

#用SEAPP_CONTEXT_TEMP代替

#     out/target/product/generic/obj/ETC/seapp_contexts_intermediates

mkdir -p SEAPP_CONTEXT_TEMP/

checkseapp -p SEPOLICY_TEMP /sepolicy

-o SEAPP_CONTEXT_TEMP/seapp_contexts SEAPP_CONTEXT_TEMP/seapp_contexts.tmp

echo "Install: out/target/product/generic/root/seapp_contexts"

acp -fp SEAPP_CONTEXT_TEMP/seapp_contexts

                        out/target/product/generic/root/seapp_contexts

 

#---->和Android平臺中的屬性相關。SEAndroid中,設置屬性也須要相關權限

#用PROPERTY_CONTEXT_TMP代替:

#         out/target/product/generic/obj/ETC/property_contexts_intermediates

mkdir -p PROPERTY_CONTEXT_TMP/

m4 -s  external/sepolicy/property_contexts  >

                         PROPERTY_CONTEXT_TMP/property_contexts

checkfc -p TARGET_SEPOLICY_TEMP/sepolicy

               PROPERTY_CONTEXT_TMP/property_contexts

echo "Install: out/target/product/generic/root/property_contexts"

acp -fp PROPERTY_CONTEXT_TMP/property_contexts

                      out/target/product/generic/root/property_contexts

上面展現了sepolicy編譯的執行狀況,讀者最好本身嘗試一下。注意,checkfccheckseapp等都是SEAndroid編譯時使用的工具,它們用來作策略檢查,看看是否有規則不符合的地方。

總結:

  • sepolicy的重頭工做是編譯sepolicy安全策略文件。這個文件來源於衆多的te文件,初始化相關的文件(initial_sid,initial_sid_context,users,roles,fs_context等)。
  • file_context:該文件記載了不一樣目錄的初始化SContext,因此它和死貨打標籤有關。
  • seapp_context:和Android中的應用程序打標籤有關。
  • property_contexts:和Android系統中的屬性服務(property_service)有關,它爲各類不一樣的屬性打標籤。

下面咱們來看看和SEAndroid相關的代碼,故事從init開始。

2.  initSEAndroid定製

Android平臺中,SEAndroid的初始化由進程的祖先initmain函數完成,相關代碼以下所示:

[-->init.c:main]

 

  process_kernel_cmdline();

  //向SELinux設置兩個回調函數,主要是打印log

 union selinux_callback cb;

 cb.func_log = klog_write;

 selinux_set_callback(SELINUX_CB_LOG, cb);

  cb.func_audit = audit_callback;

  //selinux_set_callback由libselinux提供。讀者可google libselinux各個API

  //的做用

  selinux_set_callback(SELINUX_CB_AUDIT, cb);

   //①初始化SEAndroid

    selinux_initialize(); 

   //②給下面幾個目錄打標籤!

   restorecon("/dev"); 

   restorecon("/dev/socket");

   restorecon("/dev/__properties__");

   restorecon_recursive("/sys");

上述代碼中的兩個重要函數:

  • selinux_initialize:初始化SEAndroid
  • 一堆的restoercon,全稱應該是restore context:就是根據file_contexts中的內容給一些目錄打標籤。

先來看selinux_initialize

2.1  selinux_initialize分析

[-->init.c:: selinux_initialize]

static void selinux_initialize(void)

{

   /*判斷selinux功能是否啓用。方法是:

   1) /sys/fs/selinux 是否存在。或者

   2)  ro.boot.selinux 屬性不爲disabled

  */

   if (selinux_is_disabled()) return;

 

      //加載sepolicy文件

    if (selinux_android_load_policy() < 0) {......}

 

    selinux_init_all_handles();

   /*selinux有兩種工做模式

    「permissive」:全部操做都被容許(即沒有MAC),可是若是有違反權限的話,會記錄日誌

    「enforcing」:全部操做都會進行權限檢查

    */

    bool is_enforcing = selinux_is_enforcing();

    //設置SELinux的模式

    security_setenforce(is_enforcing);

}

來看上述代碼中的兩個函數:

  • selinux_android_load_policy:加載sepolicy文件。
  • selinux_init_all_handles:初始化file_contextseapp_contextproperty_context相關內容。
(1)  selinux_android_load_policy

來看selinux_android_load_policy,其代碼以下所示:

[-->external/libselinux/src/android.c:: selinux_android_load_policy]

int selinux_android_load_policy(void)

{

    char *mnt = SELINUXMNT;// 值爲/sys/fs/selinux

    int rc;//掛載/sys/fs/selinux,SELINUXFS值爲"selinuxfs"

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

     ......

    // /sys/fs/selinux爲userpace和kernel中的SELinux模塊交互的通道

    set_selinuxmnt(mnt);//此函數定義在selinux.h中,屬於libselinux API.

 

    return selinux_android_reload_policy(); //加載SEAndroid中的policy文件

}

11展現了Nexus 7/sys/fs/selinux的內容:

11  /sys/fs/selinux的內容

用戶空間進程可同讀寫/sys/fs/selinux的各個文件或其中的子目錄來通知Kernel中的SELinux完成相關的操做。

咱們此處此處舉一個例子,如圖11下方紅框中的booleans文件夾:

  • 咱們能夠SELinux的安全配置文件中寫一些相似if/else的語句。if中的是布爾判斷條件。好比booleans文件夾下有一個in_qemu文件,這個就是sepolicy安全配置文件中的一個布爾變量。in_qemu定義在domain.te文件中,關鍵詞是bool
  • cat booleans/in_qemu:打印in_qemu布爾變量的取值。讀者會發現它的值爲「0 0」。爲何有兩個零呢,這第一個0是它的當前值,第二個零表明pending取值。即尚未賦值給當前值的一箇中間變量。若是咱們經過 echo "1" > booleans/in_qemu的話,第二個零將變成1
  • 爲何須要有中間變量呢?讀者注意圖11的右上方有一個commit_pending_bools文件。原來,經過在布爾變量中設置一個pending變量,咱們能夠實現批處理操做。即先修改1個或多個布爾變量的pending變量,而後往commit_pending_bools1,這樣這些一個或多個的布爾變量將使用pending變量取代當前值。

接下來看看selinux_android_reload_policy函數:

 [-->external/libselinux/src/android.c:: selinux_android_reload_policy]

int selinux_android_reload_policy(void)

{

    int fd = -1, rc;  struct stat sb;   void *map = NULL;

    int i = 0;

   // sepolicy_file指明sepolicy文件的路徑。Android中有兩處,第一個是

  // /data/security/current/sepolicy。第二個是root目錄下的sepolicy文件。

  //下面這段邏輯可知,SEAndroid只使用其中的一個,若是/data/目錄下有sepolicy文件,則

  //優先使用它

    while (fd < 0 && sepolicy_file[i]) {

        fd = open(sepolicy_file[i], O_RDONLY | O_NOFOLLOW);

        i++;

    }

    ......

    map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);

    ......

   //假設使用根目錄下的sepolicy文件。下面這個函數由selinux.h定義,它將此文件加載到

   //內核中

    rc = security_load_policy(map, sb.st_size);

    ......

    munmap(map, sb.st_size);

    close(fd);

     return 0;

}

init經過mmap的方式,將sepolicy文件傳遞給了kernelinit使用了libselinux提供的API函數來完成相關操做。而libselinux則是經過操做/sys/fs/selinux下的文件來完成和KernelSELinux模塊的交互。libselinux庫的API不是咱們研究的重點,感興趣的兄弟請本身研究源碼。

總之,selinux_android_load_policy幹得最重要的一件事情就是將sepolicy文件傳遞給Kernel,這樣Kernel就有了安全策略配置文件,後續的MAC才能開展起來。

在此,請讀者注意sepolicy文件的位置:

  • 首先查看/data/security/current/sepolicy:筆者自定義的策略文件通常放在這裏,init優先使用它。
  • /sepolicyroot根目錄下的sepolicy,若是data目錄下沒有sepolicy,則使用它。系統默認的sepolicy在此。
(2)  selinux_init_all_handles

前面講過,init要給一些死貨和property打標籤,爲了完成這個工做,根據libselinuxAPIinit須要先建立兩個handler,代碼在selinux_init_all_handles中:

[-->init.c:: selinux_init_all_handles]

void selinux_init_all_handles(void)

{

    sehandle = selinux_android_file_context_handle();

    sehandle_prop = selinux_android_prop_context_handle();

}

建立兩個handler,主要爲後續作labeling控制。咱們來看看propcontext

[-->init.c::selinux_android_prop_context_handle]

struct selabel_handle* selinux_android_prop_context_handle(void)

{

    int i = 0;

    struct selabel_handle* sehandle = NULL;

   //setopts_prop也有兩個值:

   //第一個是/data/security/property_contexts。第二個是/property_contexts

    while ((sehandle == NULL) && seopts_prop[i].value) {

        sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, &seopts_prop[i], 1);

        i++;

    }

  //假設採用的是根目錄下的property_context文件

  ......

  return sehandle;

}

handler其實就是爲了打開xxx_context文件。因爲它們和restorecon有關,下面直接來看restorecon函數,看看這些handler是怎麼個用法。

2.2  restorecon分析

[-->init.c::restorecon]

int restorecon(const char *pathname)

{

    char *secontext = NULL;

    struct stat sb;

    int i;

 

    if (is_selinux_enabled() <= 0 || !sehandle)

        return 0;

 

    if (lstat(pathname, &sb) < 0)   return -errno;

    //查找file_context文件中是否包含有pathname路徑的控制選項

    if (selabel_lookup(sehandle, &secontext, pathname, sb.st_mode) < 0)

        return -errno;

   //設置patchname目錄的security_context,lsetfilecon的實現很是簡單,就是調用

   //

    if (lsetfilecon(pathname, secontext) < 0) {

        freecon(secontext);

        return -errno;

    }

    freecon(secontext);

    return 0;

}

想知道selinux是如何labeling一個文件或目錄的嗎?答案在lsetfilecon中:

[-->external/libselinux/src/lsetfilecon.c:: lsetfilecon]

int lsetfilecon(const char *path, const security_context_t context)

{

 //設置文件系統的屬性

 return lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1,0);

}

2.3  property權限檢查

通常而言,SELinux權限檢查都是由kernel來完成的,不過對於Android平臺中的Property而言,這卻徹底是一個用戶空間的內容。因此,咱們看看init是如何使用libselinux來完成用戶空間的權限檢查的。

每當其餘進程經過setprop函數設置屬性時,property_service中有一個叫check_

[system/core/init/property_service.c:: check_mac_perms]

static int check_mac_perms(const char *name, char *sctx)

{

    if (is_selinux_enabled() <= 0)  return 1;

 

    char *tctx = NULL;

    const char *class = "property_service";

    const char *perm = "set";

    int result = 0;

    ......

    //檢查property_context中是否認義了目標SContext,即tctx。

    if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0) goto err;

   //將源SContext和目標SContext進行比較,判斷是否有相關權限。name是屬性的名字

   //源SContext是調用setprop進程的SContext。目標SContext是property_context

   //文件中定義的SContext。

    if (selinux_check_access(sctx, tctx, class, perm, name) == 0)

        result = 1;

    freecon(tctx);

 err:

    return result;

}

怎麼樣?理解起來並不困難吧?用戶空間的權限檢查主要就是經過selinux_check_access完成,其輸入參數包括:

  • 源的SContext:它就是調用setprop的進程的SContext
  • 目標的SContext:不一樣的屬性有不一樣的SContext,這是在property_context中定義的。
  • 要檢查的Object class(系統所支持的類在external/sepolicy/security_classes文件中定義)。
  • 操做名稱(perm,由access vector定義。對Property這種Object class而言,其惟一須要作權限檢查的操做就是set。讀者可參考external/sepolicy/access_vectors這個文件)。

具體的哪個屬性(name參數指定,就是具體指明哪一文件)。

提示:關於這些API的說明,讀者請參考http://selinuxproject.org/page/User_Resources中的Manual pages文檔。

下面咱們來看Android中應用程序是如何使用SELinux的。

3.  應用程序中的SELinux

對應用程序而言,最重要的工做就是管理它們的DTTT

  • 全部AndroidApplication對應的進程都是從zygote進程中fork出來的。從前文介紹DT的知識可知,在作DT時,能夠根據所執行的不一樣Type的文件來轉換到不一樣的DT。但這個對Android而言不可行。由於zygotefork子進程後,並無執行execv
  • apk在安裝後,都會在/data/data/目錄下創建本身對於的文件夾,這個工做是由installd來完成的。一樣,installd應該給這些不一樣的文件夾打上對應的label

咱們先來看應用程序的DT

3.1  Java應用程序的DT

Android中應用進程(就是APK所在的進程)的DT轉換其實很簡單,它及其具備Android特點:

  • 普通的DT是根據所execv文件的Type來設置DT轉換條件。
  • Android中則根據該APK簽名信息來說最終的進程轉換到幾種預設值的Domain中。
(1)  mac_permissions.xml的用途

咱們先來看PackageManagerService

[-->PackageManagerService.java::PackageManageService]

......

/*下面這個函數將嘗試解析

 1)/data/security/mac_permissions.xml 或

 2)/system/etc/security/mac_permissions.xml 中的內容。

*/

mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();

注意,mac_permissions.xml位於external/sepolicy中,圖12所示爲該文件的原始:

12  mac_permissions.xml的內容

在系統過程當中,圖12中的@RELEASE@PLATFORM等內容會被RELEASEPLATFORM簽名信息替換。圖13所示爲Nexus 7中該文件的內容。

13  Nexus7mac_permissions.xml內容

mac_permissions.xml保存了不一樣簽名所對應的seinfo:如seinfoplatform時的簽名是什麼,seinfomedia的時候簽名又是什麼。那麼,這些信息有啥用呢?來看下文。

(2)  掃描APK

APK安裝時,也就是APKPKMGS掃描的時候,有以下的代碼:

[-->PackageManagerService.java::ScanPackageLI]

if (mFoundPolicyFile) {

     //下面這個函數將根據簽名信息賦值seinfo值給對應的apk

     SELinuxMMAC.assignSeinfoValue(pkg);

   }

[-->SELinuxMMAC.java::assignSeinfoValue]

public static void assignSeinfoValue(PackageParser.Package pkg) {

 

     //對於系統app(預裝的,位於system目錄下的)

     if (((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ||

          ((pkg.applicationInfo.flags &

                         ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {

   

        for (Signature s : pkg.mSignatures) {

                if (s == null)  continue;

              //sSigSeinfo存儲了mac_permissions.xml中seinfo標籤的內容

              if (sSigSeinfo.containsKey(s)) {

                    String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(s);

                    return;

                }

            }

            //sPackageSeinfo存儲了xml中package標籤下seinfo子標籤的內容

            if (sPackageSeinfo.containsKey(pkg.packageName)) {

                String seinfo = pkg.applicationInfo.seinfo =

                              sPackageSeinfo.get(pkg.packageName);

                 return;

            }

        }

        //default標籤中seinfo的值

        String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(null);

        ......

  }

assignSeinfoValue的功能如上代碼所示,它根據apk的簽名信息來賦值不一樣的seinfo,也就是諸如"platform",」media「之類的值。

提示:你們能想出爲何要設置seinfo嗎?恩,它就是AndroidApp定義的SContext中的Domain的值。

(3)  App的DT轉換

ActivityManagerService負責啓動目標應用進程,相關代碼以下所示:

[-->ActivityManagerService.java:: startProcessLocked]

Process.ProcessStartResult startResult =

                     Process.start("android.app.ActivityThread",

                    app.processName, uid, uid, gids, debugFlags, mountExternal,

                    app.info.targetSdkVersion, app.info.seinfo, null);

根據《深刻理解AndroidI》第4章對zygote的介紹,zygote進程將fork一個子進程,相關函數在:

[-->ZygoteConnection.java::runOnce]

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,

                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal,

                    parsedArgs.seInfo,parsedArgs.niceName);

該函數由JNI實現,代碼在dalvik/vm/native/ dalvik_system_Zygote.cpp中,其中最重要的是內部所調用的forkAndSpecializeCommon

[-->dalvik_system_Zygote.cpp:: forkAndSpecializeCommon]

pid = fork();

if (pid == 0) {

  ......

    err = setSELinuxContext(uid, isSystemServer, seInfo, niceName);

  .....}

 

[-->external/libselinux/android.c::selinux_android_setcontext]

int selinux_android_setcontext(uid_t uid,int isSystemServer,

                   const char *seinfo,const char *pkgname)

{

    char *orig_ctx_str = NULL, *ctx_str;  context_t ctx = NULL;

    int rc = -1;

    if (is_selinux_enabled() <= 0)  return 0;

   

    //重要函數:seapp_context_init,內部將調用selinux_android_seapp_context_reload

   //以加載seapp_contexts文件。

   // 1) /data/security/current/seapp_contexts 或者

   // 2) /seapp_contexts   本例而言,就是根目錄下的這個seapp_context文件

    __selinux_once(once, seapp_context_init);

   

    rc = getcon(&ctx_str);

    ctx = context_new(ctx_str);

    orig_ctx_str = ctx_str;

    //從zygote進程fork出來後,最初的SContext取值爲u:r:zygote:s0

   //下面這個函數將根據uid,pkgname等設置最終的SC。例如u:r:system_app:s0等

    rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname,

     ctx);

   ctx_str = context_str(ctx);

   rc = security_check_context(ctx_str);

   if (strcmp(ctx_str, orig_ctx_str)) {

        rc = setcon(ctx_str);

    }

 

    rc = 0;

    ......

    return rc;

}

14所示爲seapp_context的內容,很是簡單:

14  seapp_context內容

上面代碼中的seapp_context_lookup將根據圖14的內容,經過不一樣的apk所對應的seinfo,找到他們的目標domain,而後再設置爲它們新的SContext。例如圖15Nexus 7ps -Z的結果圖。

15  ps -Z查看apk進程的SContext

seapp_context_lookup是完成從seapp_context文件內容映射到具體對應爲哪一個Domain的關鍵函數,該函數第一次看起來嚇死人,其實蠻簡單。這裏就再也不多說。

anywaySEAndroid中,不一樣應用程序將根據它們的簽名信息獲得對應的SContext(主要是DomainMLS其實沒用上,但之後能夠用上,這是經過圖14中的levelFrom語句來控制的,具體可參考seapp_context_lookup的實現)。

DT完成後,咱們看系統如何爲它們的對應文件夾打標籤

3.2  App data目錄的TT

仍是在PackageManagerServicescanPackageLI函數中,

[-->PackageManagerService.java:: scanPackageLI]

int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid,

                                           pkg.applicationInfo.seinfo);

createDataDirsLI最終會調用installd實現的函數:

[-->installd/commands.c::install]

//內部調用selinux_android_setfilecon2,它和上文的selinux_android_setcontext

//幾乎同樣。最終它將設置pkgdir的SContext。注意,它主要根據seapp_context文件中的

//type字段來肯定最終的Type值。

if (selinux_android_setfilecon2(pkgdir, pkgname, seinfo, uid) < 0) {

     ......

 }

16展現了ls -Z /data/data目錄下的結果。

16  /data/data目錄下ls -Z的結果

是否是和圖14seapp_context文件的type字段描述同樣同樣的?

 

4  小試牛刀

下面,筆者將經過修改shell的權限,使其沒法設置屬性。

先來看shellte,以下所示:

[external/sepolicy/shell.te]

# Domain for shell processes spawned by ADB

type shell, domain;

type shell_exec, file_type;

#shell屬於unconfined_domain,unconfined便是不受限制的意思

unconfined_domain(shell)

 

# Run app_process.

# XXX Split into its own domain?

app_domain(shell)

unconfied_domain是一個宏,它將shell和以下兩個attribute相關聯:

[external/sepolicy/te_macros]

#####################################

# unconfined_domain(domain)

# Allow the specified domain to do anything.

#

define(`unconfined_domain', `

typeattribute $1 mlstrustedsubject; #這個和MLS有關

typeattribute $1 unconfineddomain;

')

unconfineddomain權限不少,它的allow語句定義在unconfined.te中:

[external/sepolicy/unconfined.te]

......

allow unconfineddomain property_type:property_service set;

從上面能夠看出,shell所關聯的unconfineddomain有權限設置屬性。因此,咱們把它改爲:

allow {unconfineddomain -shell} property_type:property_service set;

經過一個「-」號,將shell的權限排除。

而後:

  • 咱們mmm external/sepolicy,獲得sepolicy文件。
  • 將其push/data/security/current/sepolicy目錄下
  • 接着調用setprop selinux.reload_policy 1,使得init從新加載sepolicy,因爲/data目錄下有了sepolicy,因此它將使用這個新的。

17所示爲整個測試的例子:

17  測試結果

根據圖17

  • 從新加載sepolicy以前,筆者可經過"setprop wlan.driver.status test_ok"設置該屬性的值爲test_ok。注意,這個值筆者瞎設的。
  • 當經過setprop selinux.reload_policy 1的命令後,init從新加載了sepolicy
  • 今後,筆者再setprop wlan.driver.status 都不能修改該屬性的值。

18所示爲dmesg輸出,能夠看出,當selinux使用了data目錄下這個新的sepolicy後,shellsetprop權限就被否了!

18  dmesg輸出

提示:前面曾提到過audit,日誌一類的事情。恩,這個日誌由kernel輸出,可藉助諸如audit2allowhost上的工具查看哪些地方有違反權限的地方。系統會將源,目標SContext等信息都打印出來。

 

  全文總結

本文對SELinux的核心知識進行了介紹。從入門角度來講,有了這些內容,SELinux大概80%左右的知識都已經介紹,剩下來的工做就是不斷去修改和嘗試不一樣的安全配置文件。

而後咱們對SEAndroid進行了相關介紹,這部分基本上反映了Android是如何利用這些安全配置文件來構造本身的安全環境的。

從目前AOSP SEAndroid安全配置源文件來看,不少te文件中都使用了以下這樣的語句:

19  permissive定義

其中,permissive關鍵詞表示不用對上述這些type/domain進行MAC監管。permissive通常用於測試某個策略,看是否對整個系統有影響。一旦測驗經過,就能夠把permissve語句移掉,以真正提高安全。

基於SEAndroid,廣大搞機人能夠:

  • 針對行業,開發更加安全的安全策略。
  • 定製MLS,針對企業級或軍用級的多層權限管理。
  • 不知道google有沒有意向實現Modular Policy,這樣的話,SELinux靈活性更高。

另外,要提醒讀者的是,安全配置須要考慮的東西很是多,稍有不甚,就會影響系統其餘模塊的運行。好比筆者在研究SELinux時,不當心把Ubuntu的圖像界面系統啓動不了,後來只能移除SELinux後才解決。這也是爲何SELinux出來這麼多年,可是你們好像碰到它的機會不多的緣由,由於它的配置實在是太麻煩,很容易出錯!

最後,反覆提醒讀者,一旦修改了策略文件,務必進行全方位,多層面測試。

關於SEAndroid的更多官方說明,請參考

http://source.android.com/devices/tech/security/se-linux.html

相關文章
相關標籤/搜索