淺析Android權限機制(一) —— Android的權限機制


第一章 Android的權限機制

    Android是基於Linux的系統,其權限訪問控制自然離不開Linux的權限訪問控制,而在第一章當中,將分成兩個部分來剖析Android的權限控制系統。

一. Linux權限機制
     Linux的權限訪問是由進程(訪問者)和文件(被訪問者)兩部分組成的。其中相當一部分內容參考至APUE[1]。

1.1 Llinux文件權限
     我們在Linux當中輸入命令    

$ls -l

我們可以看到這樣類似如下的結果

drwxr-xr-x 2 root root 4096 11月 28 08:32 bin
drwxr-xr-x 3 root root 4096 12月 18 09:18 boot
drwxr-xr-x 2 root root 4096 3月 18 2012 cdrom
drwxr-xr-x 15 root root 4380 1月 4 19:28 dev
drwxr-xr-x 176 root root 12288 1月 4 19:01 etc
drwxr-xr-x 3 root root 4096 4月 16 2012 home

    第一列使用的如drwxr-xr-x的10位字段,表示的是該文件的文件類型和其權限。下表描述了各個標志位的含義

9 6 - 8 3 - 5 0 - 2
文件類型 擁有者訪問權限 所在用戶組訪問權限 其它用戶訪問權限

p 管道文件

d 目錄文件

l 符號連接文件

- 普通文件

s socket文件

c 字符設備文件

b 塊設備文件

分別為讀寫執行權限,

-表示沒有該位上的權限

讀取權限: r

寫入權限: w

執行權限: x

              s,S 表示設置了SUID位.

              s表示該原標志為x,

              S表示該原標志為-

分別為讀寫執行權限,

-表示沒有該位上的權限

讀取權限: r

寫入權限: w

執行權限: x

              s,S 表示設置了GUID位.

              s表示該位原標志為x,

              S表示該位原標志為-

分別為讀寫執行權限,

-表示沒有該位上的權限

讀取權限: r

寫入權限: w

執行權限: x

              s,S 表示設置了Sticky位.

              s表示該位原標志為x,

              S表示該位原標志為-

表1 Linux文件權限標識符

    特殊權限SGID標志位:普通文件設置了該標志位,則表示該進程的egid變成被運行的程序的所有者的gid。沒有設置該位,則進程的egid為運行該程序的用戶的gid。
    特殊權限SUID標志位:普通文件設置了該標志位,則表示該進程的euid變成被運行的程序的所有者的uid。沒有設置該位,則進程的euid為運行該程序的用戶的uid。 
    特殊權限Sticky標志位:舊的UNIX系統定義該位為指示操作系統在程序退出后,保留程序的代碼段到swap空間。而在linux系統當中,該位表示防刪除位,意味着該位被設置之后,只有文件的擁有者和root用戶才能刪除該文件。[1][2]

    SGID和SUID的存在意義在於,當一個非特權進程可以通過執行設置了SGID和SUID標志的程序,來獲得特定權限。例如su,當它沒有設置SGID和SUID標志位的時候,實際上它是不能創建一個具有root權限的shell進程的。

    以上的文件權限標識符在Linux當中實際上是使用二進制來表示的,例如rwxrw-rw-,轉成二進制形式就是111110110,但實際情況下,我們為了更方便閱讀,我們使用的是八進制進行標識,也就是766。但是文件標識符當中除了基本讀寫執行之外,再算上特殊權限,實際上Linux權限訪問控制使用的是12位二進制數字(3位特殊權限 + 9位基礎權限)來表示訪問權限。比如rwsrw-rw-,轉化成八進制表示方式,就是4766。

1.2 linux進程權限
    假設,我們在系統當中運行了一個程序,然后我們通過ps命令進行查詢,得知該進程的pid為1025,之后我們在linux當中輸入命令

$cat proc/1025/status

    我們可以看到其中有一段

    Name:    live.androidpad
    Uid:    10040    10040    10040    10040
    Gid:    10040    10040    10040    10040
    Groups:    1007 1015 3003

    其中,Uid行有四列,它們分別為RUID,EUID,SUID,FSUID
    RUID(實際用戶id:Real User ID):進程的創建用戶。
    EUID(有效用戶id:Effective User ID):進程的有效用戶,用於權限訪問控制。
    SUID(保存設置用戶id:Saved Set-User-ID):在程序執行(exec)之后作為EUID的副本,用於進程切換自己的EUID時使用,對用戶來說實際意義不大。參考[1]
    FSUID(文件系統用戶id:File System User ID):Linux新引進的一類用戶、組,用於文件訪問控制。(推測,文件訪問上FSUID優先於EUID)
    Gid行有四列,它們分別為RGID,EGID,SGID,FSGID
    RGID(實際用戶id:Real User ID):進程的創建用戶組
    EGID(有效用戶id:Effective User ID):進程的有效用戶組,用於權限訪問控制。
    SGID(保存設置用戶id:Saved Set-User-ID):在程序執行(exec)之后作為EGID的副本,用於進程切換自己的EGID時使用,對用戶來說實際意義不大。參考[1]
    FSGID(文件系統用戶id:File System User ID):Linux新引進的一類用戶、組,用於文件訪問控制。(推測,文件訪問上FSGID優先於EGID)
    Groups行是組id,里面是一組使用空格分開的數字,這些數字就是是用戶組的id,它同樣用於權限訪問控制。

    對於FSGID和FSUID,這個東西是Linux中引進的,很多時候它的值是直接復制EGID和EUID的。而Unix系統當中,RUID\EUID\SUID、RGID\EGID\SGID和Groups作為標配,我們這里只討論進程的這7個參數。正如我們使用命令輸出的結果一樣,除了Groups參數使用整形數組來表示之外,其余6個參數在Linux系統當中使用的都是整形來表示。而,這幾個參數都會決定進程的權限等特性,而它們是基於什么規則來賦值的呢?

    雖然實際上跟文件訪問權限有關的僅僅是EUID、EGID和Groups,但是因為文章的受眾很可能是只了解Android系統的開發者,所以我這里也多講一些。Linux當中所有的進程創建都是通過fork函數創建的,當進程被fork之后,子進程會繼承父進程的RUID\EUID和RGID\EGID,而SUID和SGID會在exec之后作為EUID和EGID的副本被賦值(關於fork和exec的更多講解,請參考APUE[1]和[3])。而在進程創建之后,子進程可以通過setuid和setgid修改自身的RUID\EUID\SUID、RGID\EGID\SGID,但是這是有固定規則的。

    以下是setuid的使用規則,setgid也與之類似:

    1.若進程擁有超級權限,則setuid函數將RUID\EUID\SUID設置為uid。

    2.若進程沒有超級權限,而uid的值等於RUID或者SUID,則setuid將會把EUID設置為uid。而不會改變RUID或者SUID的值。

    3.如果上述兩個條件都不滿足,則返回失敗。

1.3 Linux的權限訪問控制

    這部分很簡單,所有的系統調用最終都到內核當中,內核作為管理中樞,對所有的文件訪問調用進行了核查。而APUE描述了內核對讀寫執行權限的測試算法:
    1.若進程的EUID是0,則允許訪問。
    2.若進程的EUID等於所有者ID,那么:若所有者對應的訪問權限位被設置,則允許訪問,否則拒絕訪問。
    3.若進程的EGID或者附加組ID之一等於文件的組ID,那么:若組對應的訪問權限位被設置,則允許訪問,否則拒絕訪問。
    4.若其它用戶對應的訪問權限位被設置,則允許訪問,否則拒絕訪問。

二. Android權限機制
    原本想對這部分內容進行詳細解析的,但后來發現涉及的內容包含了PKMS,AMS,應用程序安裝,應用程序啟動等內容。假若我來描寫這些內容,第一,篇幅太多,第二,自己的描述能力有限容易誤導別人。所以我就不深入說了,有興趣的朋友可以參考[4][5][6]。

    在這里我們只需要知道,Android的策略是這樣的:

    1.文件和設備訪問,使用Linux的權限訪問控制。部分權限聲明之后,應用程序啟動的時候,AMS會從PKMS那里獲得該應用進程的uid,gid和組id信息,然后通過Zygote來創建一個指定id的進程。獲得指定組id的進程,也會獲得部分文件的訪問權限,例如聲明android.permission.WRITE_EXTERNAL_STORAGE來訪問sdcard會被賦予sdcard_rw的組id。權限所對應的組id在frameworks/base/data/etc/platform.xml當中。

    特別注意:第一章也描述了,內核檢查id的順序是EUID然后再到EGID和組ID,所以,當你聲明android.permission.WRITE_EXTERNAL_STORAGE的同時,聲明shareUserId為system,是沒有讀寫sdcard權限的。

    2.Android接口調用控制,首先是root用戶和system用戶擁有所有的接口調用權限,然后對於其它用戶使用Context以下這幾個函數來實現  

    Context.checkCallingOrSelfPermission(String);
    Context.checkCallingOrSelfUriPermission(Uri,int);
    Context.checkCallingPermission(Permission);
    Context.checkCallingUriPermission(Uri,int);
    Context.checkPermission(String,int,int);
    Context.checkUriPermission(Uri,int,int,int);
    Context.checkUriPermission(Uri,String,String,int,int,int);

    Context.enforceCallingOrSelfPermission(String,String);
    Context.enforceCallingOrSelfUriPermission(Uri,int,String);
    Context.enforceCallingPermission(String,String);
    Context.enforceCallingUriPermission(String,String);
    Context.enforcePermission(String,int,int,String);
    Context.enforceUriPermission(Uri,int,int,int,String);
    Context.enforceUriPermission(Uri,String,String,int,int,int,String);

    其中check開頭的,只做檢查。enforce開頭的,不單檢查,沒有權限的還會拋出異常。

    這幾個函數最后會調用到PKMS的checkUidPermission,該函數通過對比應用權限信息來判斷該應用是否獲得權限。

    3.Android權限等級划分為normal,dangerous,signature,signatureOrSystem,system,development,其中

    signature需要簽名才能賦予權限,

    signatureOrSystem需要簽名或者系統級應用(放置在/system/app目錄下)才能賦予權限,

    system系統級應用(放置在/system/app目錄下)才能賦予權限,系統權限的描述在frameworks/base/core/res/AndroidManifest.xml當中。

    這就解答了,為什么有時候聲明一些權限沒有起作用,例如android.permission.WRITE_MEDIA_STORAGE。

 

    如果我們想知道某個權限怎么使用,有什么制約怎么辦?

 pm list permissions -f

   來查看系統所有權限的描述

 

    如果我們需要在系統中增加一個權限,怎么辦?那我們照下列的步驟來做

    1.確定你的權限屬於文件訪問控制,還是接口調用控制。

    2.在frameworks/base/core/res/AndroidManifest.xml,中增加你的權限描述。

    3.如果是文件訪問控制,那就在frameworks/base/data/etc/platform.xml為你的權限依附指定的組id。

    4.如果是接口調用控制,那就在你的接口調用里面,加入上述Context檢查權限的函數。

    

    (這段內容確實不大好寫,醞釀了好久,再醞釀就胎死腹中了,再度吐槽一下自己的描述能力。:-)第二章內容會講述一下Android root的原理。)

 

 

參考資料

[1]《Advanced Programming in the UNIX Environment》, W.Richard Stevens.

[2] Sticky標志位, http://en.wikipedia.org/wiki/Sticky_bit

[3] Linux下Fork與Exec使用, http://www.cnblogs.com/hicjiajia/archive/2011/01/20/1940154.html

[4]《Android 內核剖析》,柯元旦.

[5]《深入理解Android》 ,鄧平凡.

[6] Android權限官方文檔 ,http://developer.android.com/intl/zh-CN/guide/topics/security/permissions.html.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM