hello world

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

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

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

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

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

          1.1 Llinux文件權(quán)限
               我們?cè)贚inux當(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)限。下表描述了各個(gè)標(biāo)志位的含義

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

          p 管道文件

          d 目錄文件

          l 符號(hào)連接文件

          - 普通文件

          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)識(shí)符

              特殊權(quán)限SGID標(biāo)志位:普通文件設(shè)置了該標(biāo)志位,則表示該進(jìn)程的egid變成被運(yùn)行的程序的所有者的gid。沒有設(shè)置該位,則進(jìn)程的egid為運(yùn)行該程序的用戶的gid。
              特殊權(quán)限SUID標(biāo)志位:普通文件設(shè)置了該標(biāo)志位,則表示該進(jìn)程的euid變成被運(yùn)行的程序的所有者的uid。沒有設(shè)置該位,則進(jìn)程的euid為運(yùn)行該程序的用戶的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)一個(gè)非特權(quán)進(jìn)程可以通過執(zhí)行設(shè)置了SGID和SUID標(biāo)志的程序,來獲得特定權(quán)限。例如su,當(dāng)它沒有設(shè)置SGID和SUID標(biāo)志位的時(shí)候,實(shí)際上它是不能創(chuàng)建一個(gè)具有root權(quán)限的shell進(jìn)程的。

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

          1.2 linux進(jìn)程權(quán)限
              假設(shè),我們?cè)谙到y(tǒng)當(dāng)中運(yùn)行了一個(gè)程序,然后我們通過ps命令進(jìn)行查詢,得知該進(jìn)程的pid為1025,之后我們?cè)趌inux當(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(實(shí)際用戶id:Real User ID):進(jìn)程的創(chuàng)建用戶。
              EUID(有效用戶id:Effective User ID):進(jìn)程的有效用戶,用于權(quán)限訪問控制。
              SUID(保存設(shè)置用戶id:Saved Set-User-ID):在程序執(zhí)行(exec)之后作為EUID的副本,用于進(jìn)程切換自己的EUID時(shí)使用,對(duì)用戶來說實(shí)際意義不大。參考[1]
              FSUID(文件系統(tǒng)用戶id:File System User ID):Linux新引進(jìn)的一類用戶、組,用于文件訪問控制。(推測(cè),文件訪問上FSUID優(yōu)先于EUID)
              Gid行有四列,它們分別為RGID,EGID,SGID,F(xiàn)SGID
              RGID(實(shí)際用戶id:Real User ID):進(jìn)程的創(chuàng)建用戶組
              EGID(有效用戶id:Effective User ID):進(jìn)程的有效用戶組,用于權(quán)限訪問控制。
              SGID(保存設(shè)置用戶id:Saved Set-User-ID):在程序執(zhí)行(exec)之后作為EGID的副本,用于進(jìn)程切換自己的EGID時(shí)使用,對(duì)用戶來說實(shí)際意義不大。參考[1]
              FSGID(文件系統(tǒng)用戶id:File System User ID):Linux新引進(jìn)的一類用戶、組,用于文件訪問控制。(推測(cè),文件訪問上FSGID優(yōu)先于EGID)
              Groups行是組id,里面是一組使用空格分開的數(shù)字,這些數(shù)字就是是用戶組的id,它同樣用于權(quán)限訪問控制。

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

              雖然實(shí)際上跟文件訪問權(quán)限有關(guān)的僅僅是EUID、EGID和Groups,但是因?yàn)槲恼碌氖鼙姾芸赡苁侵涣私釧ndroid系統(tǒng)的開發(fā)者,所以我這里也多講一些。Linux當(dāng)中所有的進(jìn)程創(chuàng)建都是通過fork函數(shù)創(chuàng)建的,當(dāng)進(jìn)程被fork之后,子進(jìn)程會(huì)繼承父進(jìn)程的RUID\EUID和RGID\EGID,而SUID和SGID會(huì)在exec之后作為EUID和EGID的副本被賦值(關(guān)于fork和exec的更多講解,請(qǐng)參考APUE[1]和[3])。而在進(jìn)程創(chuàng)建之后,子進(jìn)程可以通過setuid和setgid修改自身的RUID\EUID\SUID、RGID\EGID\SGID,但是這是有固定規(guī)則的。

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

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

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

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

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

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

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

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

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

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

              2.Android接口調(diào)用控制,首先是root用戶和system用戶擁有所有的接口調(diào)用權(quán)限,然后對(duì)于其它用戶使用Context以下這幾個(gè)函數(shù)來實(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)限的還會(huì)拋出異常。

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

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

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

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

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

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

           

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

          pm list permissions -f

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

           

              如果我們需要在系統(tǒng)中增加一個(gè)權(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)容確實(shí)不大好寫,醞釀了好久,再醞釀就胎死腹中了,再度吐槽一下自己的描述能力。:-)第二章內(nèi)容會(huì)講述一下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) 閱讀(203) 評(píng)論(0)  編輯  收藏 所屬分類: 嵌入式

          主站蜘蛛池模板: 精河县| 荆州市| 岳阳县| 永丰县| 淮阳县| 永年县| 泽库县| 稻城县| 玛沁县| 门源| 西城区| SHOW| 泽库县| 石林| 沛县| 依安县| 乌拉特后旗| 葵青区| 南宫市| 长顺县| 武冈市| 松原市| 鞍山市| 甘肃省| 方城县| 盐城市| 禄丰县| 孝昌县| 怀安县| 洛阳市| 历史| 安庆市| 通道| 嘉善县| 汝南县| 洛扎县| 乌鲁木齐市| 邛崃市| 绵阳市| 临夏市| 凤冈县|