詳解Android 安全機制
Android 是一個權(quán)限分離的系統(tǒng) 。 這是利用 Linux 已有的權(quán)限管理機制,通過為每一個 Application 分配不同的 uid 和 gid , 從而使得不同的 Application 之間的私有數(shù)據(jù)和訪問( native 以及 java 層通過這種 sandbox 機制,都可以)達到隔離的目的 。 與此 同時, Android 還 在此基礎(chǔ)上進行擴展,提供了 permission 機制,它主要是用來對 Application 可以執(zhí)行的某些具體操作進行權(quán)限細分和訪問控制,同時提供了 per-URI permission 機制,用來提供對某些特定的數(shù)據(jù)塊進行 ad-hoc 方式的訪問。
1.1 uid 、 gid 、 gids
Android 的權(quán)限分離的基礎(chǔ)是建立在 Linux 已有的 uid 、 gid 、 gids 基礎(chǔ)上的 。
UID 。 Android 在 安裝一個應(yīng)用程序,就會為 它 分配一個 uid (參考 PackageManagerService 中的 newUserLP 實現(xiàn))。其中普通 A ndroid 應(yīng)用程序的 uid 是從 10000 開始分配 (參見 Process.FIRST_APPLICATION_UID ), 10000 以下是系統(tǒng)進程的 uid 。
GID 。對 于普通應(yīng)用程序來說, gid 等于 uid 。由于每個應(yīng)用程序的 uid 和 gid 都不相同, 因此不管是 native 層還是 java 層都能夠達到保護私有數(shù)據(jù)的作用 。
GIDS 。 gids 是由框架在 Application 安裝過程中生成,與 Application 申請的具體權(quán)限相關(guān)。 如果 Application 申請的相應(yīng)的 permission 被 granted ,而且 中有對應(yīng)的 gid s , 那么 這個 Application 的 gids 中將 包含這個 gid s 。
uid gid gids 的 詳細 設(shè)置過程:
請參考 Act i vityManagerService 中的 startProcessLocked 。在通過 zygote 來啟動一個 process 時,直接將 uid 傳給 給了 gid 。再通過zygote 來 fork 出新的進程( zygote.java 中的 forkAndSpecialize ),最終在 native 層( dalvik_system_zygote.c )中的forkAndSpecializeCommon 中通過 linux 系統(tǒng)調(diào)用來進行 gid 和 uid 和 gids 的設(shè)置。
1.2 permission
一個權(quán)限主要包含三個方面的信息:權(quán)限的名稱;屬于的權(quán)限組;保護級別。一個權(quán)限組是指把權(quán)限按照功能分成的不同的集合。每一個權(quán)限組包含若干具體權(quán)限,例如在 COST_MONEY 組中包含 android.permission.SEND_SMS , android.permission.CALL_PHONE 等和費用相關(guān)的權(quán)限。
每個權(quán)限通過 protectionLevel 來標識保護級別: normal , dangerous , signature , signatureorsystem 。不同的保護級別代表了程序要使用此權(quán)限時的認證方式。 normal 的權(quán)限只要申請了就可以使用; dangerous 的權(quán)限在安裝時需要用戶確認才可以使用; signature 和 signatureorsystem 的權(quán)限需要使用者的 app 和系統(tǒng)使用同一個數(shù)字證書。
Package 的權(quán)限信息主要 通過在 AndroidManifest.xml 中通過一些標簽來指定。如 permission> 標簽, permission-group> 標簽 permission-tree>等標簽。如果 package 需要申請使用某個權(quán)限,那么需要使用 use-permission>標簽來指定。
2 Android permission 管理機制
2.1 Framework permission 機制
2.1.1 安裝入口
permission 的初始化,是指 permission 的向系統(tǒng)申請,系統(tǒng)進行檢測并授權(quán),并建立相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。絕大多數(shù)的情況下 permission 都是從一個 package 中掃描所得,而這發(fā)生在 package 安裝和升級的時候。一般有如下幾種 安裝入口:
n packageInstaller , package 被下載安裝時會觸發(fā)使用。 packageInstaller 會通過 AppSecurityPermissions 來檢查 dangerous 的權(quán)限,并對用戶給出提示。
n pm 命令 。
n adb install 。最終還是 調(diào)用 pm install 來安裝 apk 包。
n 拷貝即安裝。 PackageManagerService 中使用 AppDirObserver 對 /data/app/ 進行監(jiān)視 ,如果有拷貝即觸發(fā)安裝。
這些安裝方式 最終都會通過調(diào)用 PackageManagerService 中的函數(shù)來完成程序的安裝。
2.1.2 permission 創(chuàng)建
第一步,從 AndroidManifest.xml 中提取 permission 信息。主要提取如下信息:
2 shared uid
指定與其它 package 共享同一個 uid 。
2 permission
提取 permissions 標簽指定屬性。它使用 permissionInfo 來描述一個權(quán)限的基本信息。需要指定 protectedLevel 信息,并指定所屬 group信息。它將被添加到這個 package 的 permissions 這個 list 結(jié)構(gòu)中。
2 permission-tree
提取 permissions-tree 標簽屬性。 permissions-tree 也通過 permissionInfo 來描述,并被添加到 package 的 permissions 這個 list 結(jié)構(gòu)中。 permission-tree 只是一個名字空間,用來向其中動態(tài)添加一些所謂 Dynamic 的 permission ,這些 permission 可以動態(tài)修改。這些permission 名稱要以 permission-tree 的名稱開頭。它本身不是一種權(quán)限,沒有 protectedLevel 和所屬 group 。只是保存了所屬的 packge和權(quán)限名(帶有 package 前綴的)。
2 permission-group
定義 permission 組信息,用 PermissionGroup 表示。本身不代表一個權(quán)限,會添加進入 package 的 permissionGroups 這個 list 中。
2 uses-permission
定義了 package 需要申請的權(quán)限名。將權(quán)限名添加到 package 的 requestedPermissions 這個 list 中。
2 adopt-permissions
將該標簽指定的 name 存入 package 的 mAdoptPermissions 這個 list 中。 Name 指定了這個 package 需要從 name 指定的 package 進行權(quán)限領(lǐng)養(yǎng)。在 system package 進行升級時使用。
第二步。獲取 Package 中的證書,驗證,并將簽名信息保存在 Package 結(jié)構(gòu)中。
1. 如果該 package 來自 system img (系統(tǒng) app ),那么只需要從該 Package 的 AndroidManifest.xml 中獲取簽名信息,而無需驗證其完整性。但是如果這個 package 與其它 package 共享一個 uid ,那么這個共享 uid 對應(yīng)的 sharedUser 中保存的簽名與之不一致,那么簽名驗證失敗。
2. 如果是普通的 package ,那么需要提取證書和簽名信息,并對文件的完成性進行驗證。
第三步。如果是普通的 package ,那么清除 package 的 mAdoptPermissions 字段信息(系統(tǒng) package 升級才使用)。
第四步。如果在 AndroidManifest.xml 中指定了 shared user ,那么先查看全局 list 中( mSharedUsers )是否該 uid 對應(yīng)的 SharedUserSetting 數(shù)據(jù)結(jié)構(gòu),若沒有則新分配一個 uid ,創(chuàng)建 SharedUserSetting 并保存到全局全局 list ( mSharedUsers )中。
mUserIds 保存了系統(tǒng)中已經(jīng)分配的 uid 對應(yīng)的 SharedUserSetting 結(jié)構(gòu)。每次分配時總是從第一個開始輪詢,找到第一個空閑的位置 i ,然后加上 FIRST_APPLICATION_UID 即可。
第五步。創(chuàng)建 PackageSettings 數(shù)據(jù)結(jié)構(gòu)。并將 PackageSettings 與 SharedUserSetting 進行綁定。其中 PackageSettings 保存了 SharedUserSetting 結(jié)構(gòu);而 SharedUserSetting 中會使用 PackageSettings 中的簽名信息填充自己內(nèi)部的簽名信息,并將 PackageSettings 添加到一個隊列中,表示 PackageSettings 為其中的共享者之一。
在創(chuàng)建時,首先會以 packageName 去全局數(shù)據(jù)結(jié)構(gòu) mPackages 中查詢是否已經(jīng)有對應(yīng)的 PackageSettings 數(shù)據(jù)結(jié)構(gòu)存在。如果已經(jīng)存在PackageSettings 數(shù)據(jù)結(jié)構(gòu)(比如這個 package 已經(jīng)被 uninstall ,但是還沒有刪除數(shù)據(jù),此時 package 結(jié)構(gòu)已經(jīng)被釋放)。那么比較該package 中的簽名信息(從 AndroidManifest 中掃描得到)與 PackageSettings 中的簽名信息是否匹配。如果不匹配但是為 system package ,那么信任此 package ,并將 package 中的簽名信息更新到已有的 PackageSettings 中去,同時如果這個 package 與其它package 共享了 uid ,而且 shared uid 中保存的簽名信息與當前 package 不符,那么簽名也驗證失敗。
第六步。如果 mAdoptPermissions 字段不為空,那么處理 permission 的領(lǐng)養(yǎng)(從指定的 package 對應(yīng)的 PackageSettings 中,將權(quán)限的擁有者修改為當前 package ,一般在 system app 升級的時候才發(fā)生,在此之前需要驗證當被領(lǐng)養(yǎng)的 package 已經(jīng)被卸載,即檢查 package 數(shù)據(jù)結(jié)構(gòu)是否存在)。
第七步。添加自定義權(quán)限。將 package 中定義的 permissionGroup 添加到全局的列表 mPermissionGroups 中去;將 package 中定義的 permissions 添加到全局的列表中去(如果是 permission-tree 類型,那么添加到 mSettings.mPermissionTrees ,如果是一般的 permission 添加到 mSettings.mPermissions 中)。
第八步。清除不一致的 permission 信息。
1. 清除不一致的 permission-tree 信息。如果該 permission-tree 的 packageSettings 字段為空,說明還未對該 package 進行過解析(若代碼執(zhí)行到此處時 packageSettings 肯定已經(jīng)被創(chuàng)建過),將其 remove 掉。如果 packageSettings 不為空,但是對應(yīng)的 package 數(shù)據(jù)結(jié)構(gòu)為空(說明該 package 已經(jīng)
pid控制相關(guān)文章:pid控制原理
評論