<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
    數據加載中……

    淺析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月 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位字段,表示的是該文件的文件類型和其權限。下表描述了各個標志位的含義

    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.

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

    主站蜘蛛池模板: 久久久久久噜噜精品免费直播| 日韩a级毛片免费视频| 一区二区三区精品高清视频免费在线播放 | AV无码免费永久在线观看| 黄色视频在线免费观看| 精品国产日韩亚洲一区91| 亚洲区视频在线观看| 久久精品国产亚洲| 亚洲一区二区三区偷拍女厕| 日本免费电影一区| 99久久免费精品国产72精品九九| 免费国产污网站在线观看15 | 国产亚洲美女精品久久久2020| 国内精品免费视频自在线| xxxx日本免费| 99热在线观看免费| 香蕉免费一区二区三区| 中国一级毛片免费看视频| 一级特黄aaa大片免费看| 在线观看国产一区亚洲bd| 亚洲精品无码av片| 亚洲欧好州第一的日产suv| 亚洲ts人妖网站| 亚洲成人福利在线观看| 亚洲精品视频在线观看免费 | 免费国产黄网站在线观看视频 | 亚洲中文字幕无码一区二区三区| 亚洲А∨精品天堂在线| 国产午夜无码视频免费网站 | 亚洲欧美国产国产综合一区| 亚洲一区二区三区四区视频| 亚洲午夜电影在线观看高清| 亚洲免费视频观看| 亚洲午夜在线播放| 亚洲AV无码专区在线电影成人| 亚洲欧洲无码AV不卡在线| 亚洲丶国产丶欧美一区二区三区| 亚洲精品9999久久久久无码 | 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 亚洲人成电影网站国产精品| 青青草原亚洲视频|