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