<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    hello world

    隨筆 - 2, 文章 - 63, 評論 - 0, 引用 - 0
    數(shù)據(jù)加載中……

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

    第一章 Android的權(quán)限機制

        Android是基于Linux的系統(tǒng),其權(quán)限訪問控制自然離不開Linux的權(quán)限訪問控制,而在第一章當(dāng)中,將分成兩個部分來剖析Android的權(quán)限控制系統(tǒng)。

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

    1.1 Llinux文件權(quán)限
         我們在Linux當(dāng)中輸入命令    

    $ls -l

    我們可以看到這樣類似如下的結(jié)果

    drwxr-xr-x 2 root root 4096 11月 2808:32 bin
    drwxr-xr-x 3 root root 4096 12月 1809:18 boot
    drwxr-xr-x 2 root root 4096 3月 182012 cdrom
    drwxr-xr-x 15 root root 4380 1月 419:28 dev
    drwxr-xr-x 176 root root 12288 1月 419:01 etc
    drwxr-xr-x 3 root root 4096 4月 162012 home

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

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

    p 管道文件

    d 目錄文件

    l 符號連接文件

    - 普通文件

    s socket文件

    c 字符設(shè)備文件

    b 塊設(shè)備文件

    分別為讀寫執(zhí)行權(quán)限,

    -表示沒有該位上的權(quán)限

    讀取權(quán)限: r

    寫入權(quán)限: w

    執(zhí)行權(quán)限: x

                  s,S 表示設(shè)置了SUID位.

                  s表示該原標(biāo)志為x,

                  S表示該原標(biāo)志為-

    分別為讀寫執(zhí)行權(quán)限,

    -表示沒有該位上的權(quán)限

    讀取權(quán)限: r

    寫入權(quán)限: w

    執(zhí)行權(quán)限: x

                  s,S 表示設(shè)置了GUID位.

                  s表示該位原標(biāo)志為x,

                  S表示該位原標(biāo)志為-

    分別為讀寫執(zhí)行權(quán)限,

    -表示沒有該位上的權(quán)限

    讀取權(quán)限: r

    寫入權(quán)限: w

    執(zhí)行權(quán)限: x

                  s,S 表示設(shè)置了Sticky位.

                  s表示該位原標(biāo)志為x,

                  S表示該位原標(biāo)志為-

    表1 Linux文件權(quán)限標(biāo)識符

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

        SGID和SUID的存在意義在于,當(dāng)一個非特權(quán)進程可以通過執(zhí)行設(shè)置了SGID和SUID標(biāo)志的程序,來獲得特定權(quán)限。例如su,當(dāng)它沒有設(shè)置SGID和SUID標(biāo)志位的時候,實際上它是不能創(chuàng)建一個具有root權(quán)限的shell進程的。

        以上的文件權(quán)限標(biāo)識符在Linux當(dāng)中實際上是使用二進制來表示的,例如rwxrw-rw-,轉(zhuǎn)成二進制形式就是111110110,但實際情況下,我們?yōu)榱烁奖汩喿x,我們使用的是八進制進行標(biāo)識,也就是766。但是文件標(biāo)識符當(dāng)中除了基本讀寫執(zhí)行之外,再算上特殊權(quán)限,實際上Linux權(quán)限訪問控制使用的是12位二進制數(shù)字(3位特殊權(quán)限 + 9位基礎(chǔ)權(quán)限)來表示訪問權(quán)限。比如rwsrw-rw-,轉(zhuǎn)化成八進制表示方式,就是4766。

    1.2 linux進程權(quán)限
        假設(shè),我們在系統(tǒng)當(dāng)中運行了一個程序,然后我們通過ps命令進行查詢,得知該進程的pid為1025,之后我們在linux當(dāng)中輸入命令

    $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,F(xiàn)SUID
        RUID(實際用戶id:Real User ID):進程的創(chuàng)建用戶。
        EUID(有效用戶id:Effective User ID):進程的有效用戶,用于權(quán)限訪問控制。
        SUID(保存設(shè)置用戶id:Saved Set-User-ID):在程序執(zhí)行(exec)之后作為EUID的副本,用于進程切換自己的EUID時使用,對用戶來說實際意義不大。參考[1]
        FSUID(文件系統(tǒng)用戶id:File System User ID):Linux新引進的一類用戶、組,用于文件訪問控制。(推測,文件訪問上FSUID優(yōu)先于EUID)
        Gid行有四列,它們分別為RGID,EGID,SGID,F(xiàn)SGID
        RGID(實際用戶id:Real User ID):進程的創(chuàng)建用戶組
        EGID(有效用戶id:Effective User ID):進程的有效用戶組,用于權(quán)限訪問控制。
        SGID(保存設(shè)置用戶id:Saved Set-User-ID):在程序執(zhí)行(exec)之后作為EGID的副本,用于進程切換自己的EGID時使用,對用戶來說實際意義不大。參考[1]
        FSGID(文件系統(tǒng)用戶id:File System User ID):Linux新引進的一類用戶、組,用于文件訪問控制。(推測,文件訪問上FSGID優(yōu)先于EGID)
        Groups行是組id,里面是一組使用空格分開的數(shù)字,這些數(shù)字就是是用戶組的id,它同樣用于權(quán)限訪問控制。

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

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

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

        1.若進程擁有超級權(quán)限,則setuid函數(shù)將RUID\EUID\SUID設(shè)置為uid。

        2.若進程沒有超級權(quán)限,而uid的值等于RUID或者SUID,則setuid將會把EUID設(shè)置為uid。而不會改變RUID或者SUID的值。

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

    1.3 Linux的權(quán)限訪問控制

        這部分很簡單,所有的系統(tǒng)調(diào)用最終都到內(nèi)核當(dāng)中,內(nèi)核作為管理中樞,對所有的文件訪問調(diào)用進行了核查。而APUE描述了內(nèi)核對讀寫執(zhí)行權(quán)限的測試算法:
        1.若進程的EUID是0,則允許訪問。
        2.若進程的EUID等于所有者ID,那么:若所有者對應(yīng)的訪問權(quán)限位被設(shè)置,則允許訪問,否則拒絕訪問。
        3.若進程的EGID或者附加組ID之一等于文件的組ID,那么:若組對應(yīng)的訪問權(quán)限位被設(shè)置,則允許訪問,否則拒絕訪問。
        4.若其它用戶對應(yīng)的訪問權(quán)限位被設(shè)置,則允許訪問,否則拒絕訪問。

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

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

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

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

        2.Android接口調(diào)用控制,首先是root用戶和system用戶擁有所有的接口調(diào)用權(quán)限,然后對于其它用戶使用Context以下這幾個函數(shù)來實現(xiàn)  

    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開頭的,不單檢查,沒有權(quán)限的還會拋出異常。

        這幾個函數(shù)最后會調(diào)用到PKMS的checkUidPermission,該函數(shù)通過對比應(yīng)用權(quán)限信息來判斷該應(yīng)用是否獲得權(quán)限。

        3.Android權(quán)限等級劃分為normal,dangerous,signature,signatureOrSystem,system,development,其中

        signature需要簽名才能賦予權(quán)限,

        signatureOrSystem需要簽名或者系統(tǒng)級應(yīng)用(放置在/system/app目錄下)才能賦予權(quán)限,

        system系統(tǒng)級應(yīng)用(放置在/system/app目錄下)才能賦予權(quán)限,系統(tǒng)權(quán)限的描述在frameworks/base/core/res/AndroidManifest.xml當(dāng)中。

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

     

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

    pm list permissions -f

       來查看系統(tǒng)所有權(quán)限的描述

     

        如果我們需要在系統(tǒng)中增加一個權(quán)限,怎么辦?那我們照下列的步驟來做

        1.確定你的權(quán)限屬于文件訪問控制,還是接口調(diào)用控制。

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

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

        4.如果是接口調(diào)用控制,那就在你的接口調(diào)用里面,加入上述Context檢查權(quán)限的函數(shù)。

        

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

     

     

    參考資料

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

    [2] Sticky標(biāo)志位, http://en.wikipedia.org/wiki/Sticky_bit

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

    [4]《Android 內(nèi)核剖析》,柯元旦.

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

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

    posted on 2017-06-02 21:20 聽風(fēng) 閱讀(204) 評論(0)  編輯  收藏 所屬分類: 嵌入式

    主站蜘蛛池模板: 亚洲成a人在线看天堂无码| 2021国内精品久久久久精免费| 国产免费久久精品99re丫y| 国产成人亚洲精品青草天美| 一级做a爱过程免费视| 免费人成在线观看网站视频| 老司机免费午夜精品视频| 国产成人在线免费观看| 国产偷国产偷亚洲高清人| yy6080久久亚洲精品| 一区二区三区在线观看免费| 久久精品夜色噜噜亚洲A∨| 中文字幕视频在线免费观看| 亚洲精品成人无限看| 久草免费手机视频| 亚洲欧洲国产综合| 最近最新中文字幕完整版免费高清| 亚洲伊人久久大香线蕉啊| 免费看美女让人桶尿口| 精品成人一区二区三区免费视频 | 国产精品免费小视频| 亚洲日韩一区精品射精| 亚洲AV无码成人精品区大在线| 男女男精品网站免费观看| 亚洲热线99精品视频| 57pao国产成永久免费视频| 久久精品国产亚洲AV久| 免费国产真实迷j在线观看| 国产成人自产拍免费视频| 亚洲一区二区成人| 在线观看免费人成视频| 羞羞漫画在线成人漫画阅读免费| 国产成人综合亚洲AV第一页| 亚州免费一级毛片| 韩国亚洲伊人久久综合影院| 亚洲国产精彩中文乱码AV| 无码日韩人妻av一区免费| ssswww日本免费网站片| 亚洲视频一区在线| 免费一级特黄特色大片在线| 午夜精品免费在线观看|