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