全方位理解Android權限之底層實現概覽


0000

這個階段搞了很多和Android文件權限相關的問題,雖然一知半解,但也算是對Android權限機制有一些自己的理解。遂將這些內容整理出來。因為權限這部分涉及到的內容很多,故將知識分為幾塊內容分別去整理。目前能想到的概要如下:

  1. Android 權限底層實現原理概述
  2. Android uid,gid的生成與權限機制的聯系
  3. Android packageManagerService與權限的千絲萬縷(源碼解析)
  4. Android 從recovery模式下的OTA升級理解權限
  5. Android ROOT 原理
  6. Android 簽名
  7. Android 權限大殺器 — Selinux的策略

這是第一篇。2,3,4已經有一些草稿了,但離發出來還有一些時間。5,6,7還在規划中。可以關注新弄的公眾號softard,后面比較完善的文章都會在這個號上及時更新。

這里再推薦一本書 ,這也是查資料找到的一本寶貝,非常牛逼。

0001 Overview

Linux File Permission

眾所周知,Android的內核是linux的內核。對於linux來說,系統的一切都是文件。同時,linux為文件系統設計了一套完善的權限機制。下面簡單提一下linux文件權限的核心:

比如在Android手機adb shell下查看一個目錄

# ls -ld data/data/
drwxrwx--x 113 system system 4096 1970-01-01 15:08 data/data/

其中,drwxrwx--x這10位代表文件權限,第一位文件類型可以忽略(這里類型是文件夾),后面每三位代表文件擁有的權限,包括rwx(可讀,可寫,可執行)。system system表示文件屬於system用戶和屬於system組。

翻譯過來是,system用戶對該文件擁有讀寫執行權限,system組對該文件擁有讀寫執行權限,其他用戶對該文件擁有執行權限。簡單來說就是771權限。

Android Permission

Permission權限是Android系統定義的一套權限機制,用於控制APP訪問某個硬件設備或某個Android系統的組件。
舉兩個常見的例子:

  1. 如果你的App想要訪問存儲卡,你需要在你的AndroidManifest文件中使用對應的permission用於向系統請求權限 。
  2. 你可以給你的Activity組件加個自定義的訪問權限,這樣任何想啟動該Activity的程序必須在它的AndroidManifest中進行權限的請求。見Android自定義權限

那么為什么你在AndroidManifest文件請求storage權限你就可以訪問設備文件?linux文件屬性的權限和Permission到底是怎么聯系起來的呢?下面我們來具體來講。

0010 packages.list & packages.xml

Android開機階段會掃描所有App,從Manifest文件中把App信息和權限存到packages.xmlpackages.list文件中,具體的處理過程會在后面第三篇去分析。

因為文件包含所有已安裝應用的信息,所以我們嘗試安裝一個App(com.softard.test),並且查看其信息:

packages.list

com.softard.test 10052 1 /data/user/0/com.softard.test default none

這里10052是uid,至於其怎么生成的后面第二篇再詳談。

packages.xml

<package name="com.softard.test" codePath="/data/app/com.softard.test-1" nativeLibraryPath="/data/app/com.softard.test-1/lib" publicFlags="944291654" privateFlags="0" ft="8bbd70" it="89023c" ut="8bc04d" version="1" userId="10052">
        <sigs count="1">
            <cert index="10" key="308..../>
        </sigs>
        <proper-signing-keyset identifier="11" />
    </package>

然后對App做個修改,將其改成系統App並簽名放到system/app/Test下,再看這兩個文件:

com.softard.test 1000 0 /data/user/0/com.softard.test platform 3009,3002,1023,1015,3003,3001,1021,1000,2002,2950,1010,1007

看到uid變成了1000,selinux從default變成platform,權限組從none變成3009,3002,1023,1015,3003,3001,1021,1000,2002,2950,1010,1007。而且應用一下子增加了一堆權限:

 <package name="com.softard.test" codePath="/system/app/Test" nativeLibraryPath="/system/app/Test/lib" primaryCpuAbi="armeabi-v7a" publicFlags="944291397" privateFlags="0" ft="1683b80c790" it="1683b80c790" ut="1683b80c790" version="1" sharedUserId="1000" isOrphaned="true">
        <sigs count="1">
            <cert index="0" />
        </sigs>
        <perms>
            <item name="android.permission.BIND_INCALL_SERVICE" granted="true" flags="0" />
            <item name="android.permission.WRITE_SETTINGS" granted="true" flags="0" />
            <item name="android.permission.CONFIGURE_WIFI_DISPLAY" granted="true" flags="0" />
            <item name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE" granted="true" flags="0" />
            <item name="android.permission.ACCESS_WIMAX_STATE" granted="true" flags="0" />
            <item name="android.permission.RECOVERY" granted="true" flags="0" />
            <item name="com.qualcomm.permission.READPROC" granted="true" flags="0" />
            <item name="android.permission.USE_CREDENTIALS" granted="true" flags="0" />
            <item name="android.permission.MODIFY_AUDIO_SETTINGS" granted="true" flags="0" />
            <item name="android.permission.ACCESS_CHECKIN_PROPERTIES" granted="true" flags="0" />
            <item name="com.zqautomotive.oris.wechat.provider.WRITE" granted="true" flags="0" />
            <item name="android.permission.INSTALL_LOCATION_PROVIDER" granted="true" flags="0" />
            <item name="android.permission.MANAGE_ACCOUNTS" granted="true" flags="0" />
            <item name="android.permission.SYSTEM_ALERT_WINDOW" granted="true" flags="0" />
            <item name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION" granted="true" flags="0" />
            <item name="android.permission.CONTROL_LOCATION_UPDATES" granted="true" flags="0" />
            <item name="android.permission.CLEAR_APP_USER_DATA" granted="true" flags="0" />
            <item name="com.zqautomotive.oris.wechat.provider.READ" granted="true" flags="0" />
            <item name="android.permission.BROADCAST_CALLLOG_INFO" granted="true" flags="0" />
            <item name="android.permission.NFC" granted="true" flags="0" />
            <item name="android.permission.CALL_PRIVILEGED" granted="true" flags="0" />
            <item name="android.permission.CHANGE_NETWORK_STATE" granted="true" flags="0" />
            <item name="android.permission.MASTER_CLEAR" granted="true" flags="0" />
            <item name="android.permission.WRITE_SYNC_SETTINGS" granted="true" flags="0" />
            <item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />
            <item name="android.permission.PEERS_MAC_ADDRESS" granted="true" flags="0" />
            <item name="android.permission.DEVICE_POWER" granted="true" flags="0" />
            <item name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" granted="true" flags="0" />
            <item name="android.permission.READ_PROFILE" granted="true" flags="0" />
            <item name="android.permission.BLUETOOTH" granted="true" flags="0" />
            <item name="android.permission.WRITE_MEDIA_STORAGE" granted="true" flags="0" />
            <item name="android.permission.WRITE_BLOCKED_NUMBERS" granted="true" flags="0" />
            <item name="com.qualcomm.permission.USE_QCRIL_MSG_TUNNEL" granted="true" flags="0" />
            <item name="android.permission.ACCESS_SURFACE_FLINGER" granted="true" flags="0" />
            <item name="com.zqautomotive.voice_controller.GET_SPEECH_RESULT" granted="true" flags="0" />
            <item name="android.permission.AUTHENTICATE_ACCOUNTS" granted="true" flags="0" />
            <item name="android.permission.INTERNET" granted="true" flags="0" />
            <item name="android.permission.REORDER_TASKS" granted="true" flags="0" />
            <item name="zq.permissio.CONNECTION_MQTT_SERVICE" granted="true" flags="0" />
            <item name="android.permission.BLUETOOTH_ADMIN" granted="true" flags="0" />
            <item name="android.permission.CONTROL_VPN" granted="true" flags="0" />
            <item name="android.permission.UPDATE_DEVICE_STATS" granted="true" flags="0" />
            <item name="android.permission.MANAGE_FINGERPRINT" granted="true" flags="0" />
            <item name="com.qualcomm.permission.IZAT" granted="true" flags="0" />
            <item name="android.permission.BIND_CONNECTION_SERVICE" granted="true" flags="0" />
            <item name="android.permission.MANAGE_USB" granted="true" flags="0" />
            <item name="android.permission.INTERACT_ACROSS_USERS_FULL" granted="true" flags="0" />
            <item name="android.permission.STOP_APP_SWITCHES" granted="true" flags="0" />
            <item name="android.permission.BATTERY_STATS" granted="true" flags="0" />
            <item name="android.permission.PACKAGE_USAGE_STATS" granted="true" flags="0" />
            <item name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" granted="true" flags="0" />
            <item name="android.permission.TETHER_PRIVILEGED" granted="true" flags="0" />
            <item name="android.permission.WRITE_SECURE_SETTINGS" granted="true" flags="0" />
            <item name="android.permission.MOVE_PACKAGE" granted="true" flags="0" />
            <item name="android.permission.READ_BLOCKED_NUMBERS" granted="true" flags="0" />
            <item name="com.qualcomm.permission.wfd.QC_WFD" granted="true" flags="0" />
            <item name="android.permission.READ_SEARCH_INDEXABLES" granted="true" flags="0" />
            <item name="android.permission.ACCESS_IMS_CALL_SERVICE" granted="true" flags="0" />
            <item name="android.permission.BLUETOOTH_PRIVILEGED" granted="true" flags="0" />
            <item name="android.permission.HARDWARE_TEST" granted="true" flags="0" />
            <item name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE" granted="true" flags="0" />
            <item name="android.permission.BIND_JOB_SERVICE" granted="true" flags="0" />
            <item name="android.permission.CONFIRM_FULL_BACKUP" granted="true" flags="0" />
            <item name="android.permission.SET_TIME" granted="true" flags="0" />
            <item name="android.permission.WRITE_APN_SETTINGS" granted="true" flags="0" />
            <item name="android.permission.CHANGE_WIFI_STATE" granted="true" flags="0" />
            <item name="android.permission.MANAGE_USERS" granted="true" flags="0" />
            <item name="android.permission.SET_PREFERRED_APPLICATIONS" granted="true" flags="0" />
            <item name="android.permission.DELETE_CACHE_FILES" granted="true" flags="0" />
            <item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />
            <item name="zq.permissio.CONNECTION_ACTIVATION_SERVICE" granted="true" flags="0" />
            <item name="android.permission.DISABLE_KEYGUARD" granted="true" flags="0" />
            <item name="android.permission.BACKUP" granted="true" flags="0" />
            <item name="android.permission.CHANGE_CONFIGURATION" granted="true" flags="0" />
            <item name="android.permission.USER_ACTIVITY" granted="true" flags="0" />
            <item name="android.permission.READ_LOGS" granted="true" flags="0" />
            <item name="android.permission.COPY_PROTECTED_DATA" granted="true" flags="0" />
            <item name="android.permission.INTERACT_ACROSS_USERS" granted="true" flags="0" />
            <item name="android.permission.SET_KEYBOARD_LAYOUT" granted="true" flags="0" />
            <item name="android.permission.USE_FINGERPRINT" granted="true" flags="0" />
            <item name="android.permission.WRITE_USER_DICTIONARY" granted="true" flags="0" />
            <item name="android.permission.READ_SYNC_STATS" granted="true" flags="0" />
            <item name="android.permission.REBOOT" granted="true" flags="0" />
            <item name="android.permission.OEM_UNLOCK_STATE" granted="true" flags="0" />
            <item name="android.permission.MANAGE_DEVICE_ADMINS" granted="true" flags="0" />
            <item name="android.permission.CHANGE_APP_IDLE_STATE" granted="true" flags="0" />
            <item name="android.permission.SET_POINTER_SPEED" granted="true" flags="0" />
            <item name="android.permission.MANAGE_NOTIFICATIONS" granted="true" flags="0" />
            <item name="android.permission.READ_SYNC_SETTINGS" granted="true" flags="0" />
            <item name="android.permission.OVERRIDE_WIFI_CONFIG" granted="true" flags="0" />
            <item name="android.permission.FORCE_STOP_PACKAGES" granted="true" flags="0" />
            <item name="android.permission.ACCESS_NOTIFICATIONS" granted="true" flags="0" />
            <item name="android.permission.VIBRATE" granted="true" flags="0" />
            <item name="com.android.certinstaller.INSTALL_AS_USER" granted="true" flags="0" />
            <item name="android.permission.READ_USER_DICTIONARY" granted="true" flags="0" />
            <item name="android.permission.ACCESS_WIFI_STATE" granted="true" flags="0" />
            <item name="android.permission.CHANGE_WIMAX_STATE" granted="true" flags="0" />
            <item name="android.permission.MODIFY_PHONE_STATE" granted="true" flags="0" />
            <item name="android.permission.STATUS_BAR" granted="true" flags="0" />
            <item name="android.permission.READ_FRAME_BUFFER" granted="true" flags="0" />
            <item name="android.permission.LOCATION_HARDWARE" granted="true" flags="0" />
            <item name="android.permission.WAKE_LOCK" granted="true" flags="0" />
            <item name="android.permission.INJECT_EVENTS" granted="true" flags="0" />
            <item name="android.permission.DELETE_PACKAGES" granted="true" flags="0" />
        </perms>
        <proper-signing-keyset identifier="1" />
    </package>

所以問題來了,改成系統應用后uid為什么變成1000?后面代表權限組的一串數字又都是什么?

0011 Android File Permission

android_filesystem_config.h

在Android中,所有權限的定義都在:system/core/include/private/android_filesystem_config.h

在這個頭文件中定義了Android系統的一些用戶,包含root用戶,system用戶,shell用戶所對應的值等等。

/* This is the master Users and Groups config for the platform.
 * DO NOT EVER RENUMBER
 */

#define AID_ROOT             0  /* traditional unix root user */

#define AID_SYSTEM        1000  /* system server */

#define AID_RADIO         1001  /* telephony subsystem, RIL */
#define AID_BLUETOOTH     1002  /* bluetooth subsystem */
#define AID_GRAPHICS      1003  /* graphics devices */
#define AID_INPUT         1004  /* input devices */
#define AID_AUDIO         1005  /* audio devices */
#define AID_CAMERA        1006  /* camera devices */
#define AID_LOG           1007  /* log devices */
#define AID_COMPASS       1008  /* compass device */
#define AID_MOUNT         1009  /* mountd socket */
#define AID_WIFI          1010  /* wifi subsystem */
#define AID_ADB           1011  /* android debug bridge (adbd) */
#define AID_INSTALL       1012  /* group for installing packages */
#define AID_MEDIA         1013  /* mediaserver process */
#define AID_DHCP          1014  /* dhcp client */
#define AID_SDCARD_RW     1015  /* external storage write access */
#define AID_VPN           1016  /* vpn system */
#define AID_KEYSTORE      1017  /* keystore subsystem */
#define AID_USB           1018  /* USB devices */
#define AID_DRM           1019  /* DRM server */
#define AID_MDNSR         1020  /* MulticastDNSResponder (service discovery) */
#define AID_GPS           1021  /* GPS daemon */
#define AID_UNUSED1       1022  /* deprecated, DO NOT USE */
#define AID_MEDIA_RW      1023  /* internal media storage write access */
#define AID_MTP           1024  /* MTP USB driver access */
#define AID_UNUSED2       1025  /* deprecated, DO NOT USE */
#define AID_DRMRPC        1026  /* group for drm rpc */
#define AID_NFC           1027  /* nfc subsystem */
#define AID_SDCARD_R      1028  /* external storage read access */
#define AID_CLAT          1029  /* clat part of nat464 */
#define AID_LOOP_RADIO    1030  /* loop radio devices */
#define AID_MEDIA_DRM     1031  /* MediaDrm plugins */
#define AID_PACKAGE_INFO  1032  /* access to installed package details */
#define AID_SDCARD_PICS   1033  /* external storage photos access */
#define AID_SDCARD_AV     1034  /* external storage audio/video access */
#define AID_SDCARD_ALL    1035  /* access all users external storage */
#define AID_LOGD          1036  /* log daemon */
#define AID_SHARED_RELRO  1037  /* creator of shared GNU RELRO files */
#define AID_DBUS          1038  /* dbus-daemon IPC broker process */
#define AID_TLSDATE       1039  /* tlsdate unprivileged user */
#define AID_MEDIA_EX      1040  /* mediaextractor process */
#define AID_AUDIOSERVER   1041  /* audioserver process */
#define AID_METRICS_COLL  1042  /* metrics_collector process */
#define AID_METRICSD      1043  /* metricsd process */
#define AID_WEBSERV       1044  /* webservd process */
#define AID_DEBUGGERD     1045  /* debuggerd unprivileged user */
#define AID_MEDIA_CODEC   1046  /* mediacodec process */
#define AID_CAMERASERVER  1047  /* cameraserver process */
#define AID_FIREWALL      1048  /* firewalld process */
#define AID_TRUNKS        1049  /* trunksd process (TPM daemon) */
#define AID_NVRAM         1050  /* Access-controlled NVRAM */
#define AID_DNS           1051  /* DNS resolution daemon (system: netd) */
#define AID_DNS_TETHER    1052  /* DNS resolution daemon (tether: dnsmasq) */
/* Changes to this file must be made in AOSP, *not* in internal branches. */

#define AID_SHELL         2000  /* adb and debug shell user */
#define AID_CACHE         2001  /* cache access */
#define AID_DIAG          2002  /* access to diagnostic resources */

/* The range 2900-2999 is reserved for OEM, and must never be
 * used here */
#define AID_OEM_RESERVED_START 2900
#define AID_OEM_RESERVED_END   2999

/* The 3000 series are intended for use as supplemental group id's only.
 * They indicate special Android capabilities that the kernel is aware of. */
#define AID_NET_BT_ADMIN  3001  /* bluetooth: create any socket */
#define AID_NET_BT        3002  /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET          3003  /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW       3004  /* can create raw INET sockets */
#define AID_NET_ADMIN     3005  /* can configure interfaces and routing tables. */
#define AID_NET_BW_STATS  3006  /* read bandwidth statistics */
#define AID_NET_BW_ACCT   3007  /* change bandwidth statistics accounting */
#define AID_NET_BT_STACK  3008  /* bluetooth: access config files */
#define AID_READPROC      3009  /* Allow /proc read access */
#define AID_WAKELOCK      3010  /* Allow system wakelock read/write access */

/* The range 5000-5999 is also reserved for OEM, and must never be used here. */
#define AID_OEM_RESERVED_2_START 5000
#define AID_OEM_RESERVED_2_END   5999

#define AID_EVERYBODY     9997  /* shared between all apps in the same profile */
#define AID_MISC          9998  /* access to misc storage */
#define AID_NOBODY        9999

#define AID_APP          10000  /* first app user */

#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
#define AID_ISOLATED_END   99999 /* end of uids for fully isolated sandboxed processes */

#define AID_USER        100000  /* offset for uid ranges for each user */

#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
#define AID_SHARED_GID_END   59999 /* start of gids for apps in each user to share */

從頭文件定義,就知道每個權限組都是由一串數字代表的。除了數字,該文件還定義了一個結構體數組,映射數字對應的字符串:

static const struct android_id_info android_ids[] = {
    { "root",          AID_ROOT, },

    { "system",        AID_SYSTEM, },

    { "radio",         AID_RADIO, },
    { "bluetooth",     AID_BLUETOOTH, },
    { "graphics",      AID_GRAPHICS, },
    { "input",         AID_INPUT, },
    { "audio",         AID_AUDIO, },
    { "camera",        AID_CAMERA, },
    { "log",           AID_LOG, },
    { "compass",       AID_COMPASS, },
    { "mount",         AID_MOUNT, },
    { "wifi",          AID_WIFI, },
    { "adb",           AID_ADB, },
    { "install",       AID_INSTALL, },
    { "media",         AID_MEDIA, },
    { "dhcp",          AID_DHCP, },
    { "sdcard_rw",     AID_SDCARD_RW, },
    { "vpn",           AID_VPN, },
    { "keystore",      AID_KEYSTORE, },
    { "usb",           AID_USB, },
    { "drm",           AID_DRM, },
    { "mdnsr",         AID_MDNSR, },
    { "gps",           AID_GPS, },
    // AID_UNUSED1
    { "media_rw",      AID_MEDIA_RW, },
    { "mtp",           AID_MTP, },
    // AID_UNUSED2
    { "drmrpc",        AID_DRMRPC, },
    { "nfc",           AID_NFC, },
    { "sdcard_r",      AID_SDCARD_R, },
    { "clat",          AID_CLAT, },
    { "loop_radio",    AID_LOOP_RADIO, },
    { "mediadrm",      AID_MEDIA_DRM, },
    { "package_info",  AID_PACKAGE_INFO, },
    { "sdcard_pics",   AID_SDCARD_PICS, },
    { "sdcard_av",     AID_SDCARD_AV, },
    { "sdcard_all",    AID_SDCARD_ALL, },
    { "logd",          AID_LOGD, },
    { "shared_relro",  AID_SHARED_RELRO, },
    { "dbus",          AID_DBUS, },
    { "tlsdate",       AID_TLSDATE, },
    { "mediaex",       AID_MEDIA_EX, },
    { "audioserver",   AID_AUDIOSERVER, },
    { "metrics_coll",  AID_METRICS_COLL },
    { "metricsd",      AID_METRICSD },
    { "webserv",       AID_WEBSERV },
    { "debuggerd",     AID_DEBUGGERD, },
    { "mediacodec",    AID_MEDIA_CODEC, },
    { "cameraserver",  AID_CAMERASERVER, },
    { "firewall",      AID_FIREWALL, },
    { "trunks",        AID_TRUNKS, },
    { "nvram",         AID_NVRAM, },
    { "dns",           AID_DNS, },
    { "dns_tether",    AID_DNS_TETHER, },

    { "shell",         AID_SHELL, },
    { "cache",         AID_CACHE, },
    { "diag",          AID_DIAG, },

    { "net_bt_admin",  AID_NET_BT_ADMIN, },
    { "net_bt",        AID_NET_BT, },
    { "inet",          AID_INET, },
    { "net_raw",       AID_NET_RAW, },
    { "net_admin",     AID_NET_ADMIN, },
    { "net_bw_stats",  AID_NET_BW_STATS, },
    { "net_bw_acct",   AID_NET_BW_ACCT, },
    { "net_bt_stack",  AID_NET_BT_STACK, },
    { "readproc",      AID_READPROC, },
    { "wakelock",      AID_WAKELOCK, },

    { "everybody",     AID_EVERYBODY, },
    { "misc",          AID_MISC, },
    { "nobody",        AID_NOBODY, },
};

好了,了解這個文件我們再來看我們應用的信息:

com.softard.test 1000 0 /data/user/0/com.softard.test platform 3009,3002,1023,1015,3003,3001,1021,1000,2002,1010,1007

我們把數字對應的信息截取下來:

#define AID_SYSTEM        1000  "system"	/* system server */		
#define AID_LOG           1007  "log"		/* log devices */		
#define AID_WIFI          1010  "wifi"		/* wifi subsystem */	
#define AID_SDCARD_RW     1015  "sdcard_rw"	/* external storage write access */
#define AID_GPS           1021  "gps"		/* GPS daemon */
#define AID_MEDIA_RW      1023  "media_rw"	/* internal media storage write access */
#define AID_DIAG          2002  "diag"		/* access to diagnostic resources */
#define AID_NET_BT_ADMIN  3001  "net_bt_admin"/* bluetooth: create any socket */
#define AID_NET_BT        3002  "net_bt"	/* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET          3003  "inet"		/* can create AF_INET and AF_INET6 sockets */
#define AID_READPROC      3009  "readproc"	/* Allow /proc read access */

所以,當我指定應用為系統應用時,就將uid指定為了1000。並且擁有了各種屬於系統的權限組。

那么,指定系統應用后是怎么獲得這一系列的gid呢?這一塊源碼流程很多,放到后面集中分析。

好了,現在我們了解system/core/include/private/android_filesystem_config.h文件定義以后,其實就前進了一大步。注意一下代碼所在源碼位置,位於system/core下,其實它已經是Android內核部分了,所以后面涉及到權限內容,都會導入這個頭文件。

現在來看一段源碼再來熟悉一下這部分內容:

FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);

這是位於frameworks/base/services/core/java/com/android/server/pm/Settings.java的一段代碼,功能就是創建packages.list文件。從函數名稱和參數可以知道,它是給文件添加權限的,通過這段代碼可以推測出:它給packages.list文件賦予了0640的權限,權限隸屬於system,權限組為package_info。

然后我們進入系統看一看是不是這樣:

/data/system # ls -l packages.list
-rw-r----- 1 system package_info 13627 1970-01-01 11:27 packages.list

有沒有發現原來Android底層權限其實也不是很難理解嘛?

這時,又有一個問題了,創建文件你可以這樣設定權限,但系統文件/文件夾的默認權限又是從哪來的?這就要引入另外一個文件了。

fs_config.c

寫過Android App的你肯定知道,App的一些數據都放在/data/data目錄下。正常情況下這個目錄是不可以訪問的:

/data/data $ ls
ls: .: Permission denied

我們看一下這個目錄的權限:

/data/data $ ls -ld
drwxrwx--x 310 system system 12288 2019-01-11 09:51 .

我們作為shell用戶,只有一個x權限, 當然訪問不了。那如果我要給shell賦予訪問權限改怎么改呢?

這就需要了解一下system/core/libcutils/fs_config.c文件了。系統目錄和文件的用戶組以及權限都是在這個文件里定義的:

/* Rules for directories.
** These rules are applied based on "first match", so they
** should start with the most specific path and work their
** way up to the root.
*/
static const struct fs_path_config android_dirs[] = {
    { 00770, AID_SYSTEM, AID_CACHE,  0, "cache" },
    { 00500, AID_ROOT,   AID_ROOT,   0, "config" },
    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" },
    { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local" },
    { 01771, AID_SYSTEM, AID_MISC,   0, "data/misc" },
    { 00770, AID_DHCP,   AID_DHCP,   0, "data/misc/dhcp" },
    { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
    { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest" },
    { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest64" },
    { 00775, AID_ROOT,   AID_ROOT,   0, "data/preloads" },
    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
    { 00755, AID_ROOT,   AID_SYSTEM, 0, "mnt" },
    { 00755, AID_ROOT,   AID_ROOT,   0, "root" },
    { 00750, AID_ROOT,   AID_SHELL,  0, "sbin" },
    { 00751, AID_ROOT,   AID_SDCARD_R, 0, "storage" },
    { 00755, AID_ROOT,   AID_SHELL,  0, "system/bin" },
    { 00755, AID_ROOT,   AID_SHELL,  0, "system/vendor" },
    { 00755, AID_ROOT,   AID_SHELL,  0, "system/xbin" },
    { 00755, AID_ROOT,   AID_ROOT,   0, "system/etc/ppp" },
    { 00755, AID_ROOT,   AID_SHELL,  0, "vendor" },
    { 00777, AID_ROOT,   AID_ROOT,   0, "sdcard" },
    { 00755, AID_ROOT,   AID_ROOT,   0, 0 },
};

/* Rules for files.
** These rules are applied based on "first match", so they
** should start with the most specific path and work their
** way up to the root. Prefixes ending in * denotes wildcard
** and will allow partial matches.
*/
static const char conf_dir[] = "/system/etc/fs_config_dirs";
static const char conf_file[] = "/system/etc/fs_config_files";

static const struct fs_path_config android_files[] = {
    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
    { 00440, AID_ROOT,      AID_ROOT,      0, "system/etc/recovery.img" },
    { 00444, AID_ROOT,      AID_ROOT,      0, conf_dir + 1 },
    { 00444, AID_ROOT,      AID_ROOT,      0, conf_file + 1 },
    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
    { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-ephemeral/*" },
    { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
    { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest/tests.txt" },
    { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/tests.txt" },
    { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest/*" },
    { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/*" },

    /* the following two files are INTENTIONALLY set-uid, but they
     * are NOT included on user builds. */
    { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },

    /* the following files have enhanced capabilities and ARE included in user builds. */
    { 00750, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
    { 00700, AID_SYSTEM,    AID_SHELL,     CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },

    /* Support FIFO scheduling mode in SurfaceFlinger. */
    { 00755, AID_SYSTEM,    AID_GRAPHICS,     CAP_MASK_LONG(CAP_SYS_NICE), "system/bin/surfaceflinger" },

    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/xbin/*" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/xbin/*" },
    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
    { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
    { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
    { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
    { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
};

感覺也不用多說,android_dirs[]負責文件夾的權限配置,android_files[]負責文件的權限配置。

從里面定義找找剛提到的/data/data目錄

{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },

你看,就是這么回事兒而已。如果要改成shell權限的話,只需要這樣改就可以了:

{ 00771, AID_SYSTEM, AID_SHELL, 0, "data/data" },

當然,如果系統里還要添加其他目錄、文件需要指定權限,只需要在這個文件里添加一行即可。

0100 Android App Permission

講到這里,還遺留一個開頭提出的問題:

為什么你在AndroidManifest文件請求storage權限你就可以訪問設備文件?

0010里提到過,PackageManagerService在啟動后會掃描所有已經安裝的App,然后加載和解析他們的Androidmanifest文件,生成packages.listpackages.xml等文件。解析過程就包括了permission的解析與攔截。

frameworks/base/core/res/AndroidManifest.xml 這個文件中定義了Permission攔截規則,下面列舉幾個:

<!-- Allows an application to read from external storage.
     <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
     granted this permission.</p>
     <p>This permission is enforced starting in API level 19.  Before API level 19, this
     permission is not enforced and all apps still have access to read from external storage.
     You can test your app with the permission enforced by enabling <em>Protect USB
     storage</em> under Developer options in the Settings app on a device running Android 4.1 or
     higher.</p>
     <p>Also starting in API level 19, this permission is <em>not</em> required to
     read/write files in your application-specific directories returned by
     {@link android.content.Context#getExternalFilesDir} and
     {@link android.content.Context#getExternalCacheDir}.
     <p class="note"><strong>Note:</strong> If <em>both</em> your <a
     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
     minSdkVersion}</a> and <a
     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
     targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
     grants your app this permission. If you don't need this permission, be sure your <a
     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
     targetSdkVersion}</a> is 4 or higher.
     <p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_EXTERNAL_STORAGE"
            android:permissionGroup="android.permission-group.STORAGE"
            android:label="@string/permlab_sdcardRead"
            android:description="@string/permdesc_sdcardRead"
            android:protectionLevel="dangerous" />

<!-- Allows applications to access information about Wi-Fi networks.
         <p>Protection level: normal
-->
<permission android:name="android.permission.ACCESS_WIFI_STATE"
            android:description="@string/permdesc_accessWifiState"
            android:label="@string/permlab_accessWifiState"
            android:protectionLevel="normal" />

<!-- @SystemApi Allows applications to set the system time.
    <p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_TIME"
            android:protectionLevel="signature|privileged" />

這里看一下protectionLevel,normal是一般權限,即不需要動態申請,直接在Manifest里注冊即可獲得的權限。dangerous是敏感權限,需要動態申請告知用戶才能獲取的權限。signature|privileged一般是系統priv-app才擁有的權限,也就是擁有系統簽名的系統應用。

他的攔截規則大概是,如果App申請了signature|privileged權限,但他是普通開發者的三方App,PMS就會將其從申請權限的列表里將該權限刪除。這樣你的App實際上就沒有獲得對應的權限了。

那么,文件屬性的權限是怎么和Permission聯系起來的?不出意外,系統也有一個關聯文件的定義frameworks/base/data/etc/platform.xml

<!-- This file is used to define the mappings between lower-level system
     user and group IDs and the higher-level permission names managed
     by the platform.

     Be VERY careful when editing this file!  Mistakes made here can open
     big security holes.
-->
<permissions>

    <!-- ================================================================== -->
    <!-- ================================================================== -->
    <!-- ================================================================== -->

    <!-- The following tags are associating low-level group IDs with
         permission names.  By specifying such a mapping, you are saying
         that any application process granted the given permission will
         also be running with the given group ID attached to its process,
         so it can perform any filesystem (read, write, execute) operations
         allowed for that group. -->

    <permission name="android.permission.BLUETOOTH_ADMIN" >
        <group gid="net_bt_admin" />
    </permission>

    <permission name="android.permission.BLUETOOTH" >
        <group gid="net_bt" />
    </permission>

    <permission name="android.permission.BLUETOOTH_STACK" >
        <group gid="net_bt_stack" />
        <group gid="wakelock" />
    </permission>

    <permission name="android.permission.NET_TUNNELING" >
        <group gid="vpn" />
    </permission>

    <permission name="android.permission.INTERNET" >
        <group gid="inet" />
    </permission>

    <permission name="android.permission.READ_LOGS" >
        <group gid="log" />
    </permission>

    <permission name="android.permission.WRITE_MEDIA_STORAGE" >
        <group gid="media_rw" />
        <group gid="sdcard_rw" />
    </permission>

    <permission name="android.permission.ACCESS_MTP" >
        <group gid="mtp" />
    </permission>

    <permission name="android.permission.NET_ADMIN" >
        <group gid="net_admin" />
    </permission>

    <!-- The group that /cache belongs to, linked to the permission
         set on the applications that can access /cache -->
    <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
        <group gid="cache" />
    </permission>

    <!-- RW permissions to any system resources owned by group 'diag'.
         This is for carrier and manufacture diagnostics tools that must be
         installable from the framework. Be careful. -->
    <permission name="android.permission.DIAGNOSTIC" >
        <group gid="input" />
        <group gid="diag" />
    </permission>

    <!-- Group that can read detailed network usage statistics -->
    <permission name="android.permission.READ_NETWORK_USAGE_HISTORY">
        <group gid="net_bw_stats" />
    </permission>

    <!-- Group that can modify how network statistics are accounted -->
    <permission name="android.permission.MODIFY_NETWORK_ACCOUNTING">
        <group gid="net_bw_acct" />
    </permission>

    <permission name="android.permission.LOOP_RADIO" >
        <group gid="loop_radio" />
    </permission>

    <!-- Hotword training apps sometimes need a GID to talk with low-level
         hardware; give them audio for now until full HAL support is added. -->
    <permission name="android.permission.MANAGE_VOICE_KEYPHRASES">
        <group gid="audio" />
    </permission>

    <permission name="android.permission.ACCESS_FM_RADIO" >
        <!-- /dev/fm is gid media, not audio -->
        <group gid="media" />
    </permission>

    <!-- These are permissions that were mapped to gids but we need
         to keep them here until an upgrade from L to the current
         version is to be supported. These permissions are built-in
         and in L were not stored in packages.xml as a result if they
         are not defined here while parsing packages.xml we would
         ignore these permissions being granted to apps and not
         propagate the granted state. From N we are storing the
         built-in permissions in packages.xml as the saved storage
         is negligible (one tag with the permission) compared to
         the fragility as one can remove a built-in permission which
         no longer needs to be mapped to gids and break grant propagation. -->
    <permission name="android.permission.READ_EXTERNAL_STORAGE" />
    <permission name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <!-- ================================================================== -->
    <!-- ================================================================== -->
    <!-- ================================================================== -->

    <!-- The following tags are assigning high-level permissions to specific
         user IDs.  These are used to allow specific core system users to
         perform the given operations with the higher-level framework.  For
         example, we give a wide variety of permissions to the shell user
         since that is the user the adb shell runs under and developers and
         others should have a fairly open environment in which to
         interact with the system. -->

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="media" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
    <assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" />

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="audioserver" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="audioserver" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="audioserver" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="cameraserver" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />

    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />

    <!-- This is a list of all the libraries available for application
         code to link against. -->

    <library name="android.test.runner"
            file="/system/framework/android.test.runner.jar" />
    <library name="javax.obex"
            file="/system/framework/javax.obex.jar" />
    <library name="org.apache.http.legacy"
            file="/system/framework/org.apache.http.legacy.jar" />

    <!-- These are the standard packages that are white-listed to always have internet
         access while in power save mode, even if they aren't in the foreground. -->
    <allow-in-power-save package="com.android.providers.downloads" />

    <!-- These are the standard packages that are white-listed to always have internet
         access while in data mode, even if they aren't in the foreground. -->
    <allow-in-data-usage-save package="com.android.providers.downloads" />

    <!-- These are the packages that are white-listed to be able to run as system user -->
    <system-user-whitelisted-app package="com.android.settings" />

    <!-- These are the packages that shouldn't run as system user -->
    <system-user-blacklisted-app package="com.android.wallpaper.livepicker" />
</permissions>

這個文件定義了所有權限所屬的gid。從里面找一下READ_EXTERNAL_STORAGE權限,emmmm,什么都沒做。這是因為6.0之后存儲權限變成動態,需要用戶確認才可以獲取權限,所以這里不作處理。動態權限這部分代碼先不分析了,來看一下老版本的文件:

<permission name="android.permission.READ_EXTERNAL_STORAGE" >
    <group gid="sdcard_r" />
</permission>

那明確了,READ_EXTERNAL_STORAGE權限獲取的gid是sdcard_r,然后查看上面的文件定義,對應AID_SDCARD_R,數值是1028。實際上在7.0上得到的是sdcard_rw,即1015。

PMS在解析每個Permission時會根據這個文件將Permission關聯的gid 加入到一個gid的數組中去,從而硬件設備所對應的設備文件就能被該應用程序訪問。這塊具體代碼流程放到下一篇去分析。想自己跟代碼的話可以從該函數看起:

private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
                                              String[] grantedPermissions) {
    for (int userId : userIds) {
        grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
    }

    // We could have touched GID membership, so flush out packages.list
    synchronized (mPackages) {
        mSettings.writePackageListLPr();
    }
}

回到存儲權限,既然系統會根據permission給App添加合適的gid,那么我們在看下內置存儲的權限為

/sdcard # ls -ld
drwxrwx--x 27 root sdcard_rw 4096 1970-01-01 18:30 .

所以獲得sdcard_rw權限組的應用才可以訪問內置存儲。

到此Android權限的底層實現原理簡單介紹完了,不過目前這里還留有一個坑,那就是我在測試App里添加STORAGE權限后,安裝到設備里,通過查看進程屬性,發現:

# ps | grep softard
u0_a53    3530  638   969076 30720 binder_thr b07244fc S com.softard.test
# cat /proc/3530/status
Name:	com.softard.test
State:	S (sleeping)
Tgid:	3530
Pid:	3530
PPid:	638
TracerPid:	0
Uid:	10053	10053	10053	10053
Gid:	10053	10053	10053	10053
Ngid:	0
FDSize:	256
Groups:	9997 50053

Groups沒有對應的gid,但是程序的確可以訪問/sdcard

然后我又給App系統簽名,作為系統應用放進去再看,

# ps | grep soft
system    3560  629   985352 49184 SyS_epoll_ abea53b8 S com.softard.test
# cat /proc/3560/status
Name:	com.softard.test
State:	S (sleeping)
Tgid:	3560
Pid:	3560
PPid:	629
TracerPid:	0
Uid:	1000	1000	1000	1000
Gid:	1000	1000	1000	1000
Ngid:	0
FDSize:	256
Groups:	1000 1007 1010 1015 1021 1023 2002 2950 3001 3002 3003 3009 9997 41000

這時候Groups有sdcard_rw權限了。然后從設置里手動關掉存儲權限,App無法讀取文件,再次檢查gid發現這個1015依舊存在。

WTF,7.0的表現跟5.0完全不一樣?又是一個坑…后面抽空再填吧...

行吧,這篇概覽就這樣了,后面就開始從眼花繚亂的源碼角度去看這一切的實現。

0101 Reference

Android文件屬性的權限和Permission的聯系


免責聲明!

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



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