How Android's permissions mapping with UIDs/GIDs works?


Question

Reading the book: Android Security Internals I'm reading at Chapter 2 - Permission Management paragraph that permissions are assigned to application at install time by the package manager with a mapping like Apk's UID <-> Permissions.



Later in the book (Permission Assignment - Permissions and Process Attributes paragraph) I read that




If additional permissions have been assigned to the application, they are mapped to GIDs and assigned as supplementary GIDs to the process.




And, since android.permission.INTERNET permission is associated with inet GID:




any process for an app that has been granted the
INTERNET permission is associated with the supplementary GID correspond-
ing to the inet group




But I was asking me if this is always necessary.



Imagining a case where you install APK X declaring android.permission.INTERNET permission in AndroidManifest.xml, since mapping of permissions with UIDs is done at install time, PackageManager should be able to map the permission directly with the APK's UID instead of adding inet GID to your APK package. So I'm wondering why it has to be that:




any process for an app that has been granted the INTERNET permission is associated with the supplementary GID correspond- ing to the inet group




Anyone can clarify me this?


Answer

Android's permission management can be divided majorly in two parts: Linux kernel and Android framework.



DISCRETIONARY ACCESS CONTROL:



Discretionary Access Control (DAC) based on users, groups and access mode predates back to early days of UNIX. Every file (including directories) and process has a user owner (UID) and a group owner (GID). So a process is allowed to Read Write and eXecute a resource depending on its access mode bits (RWX) for User, Group and Others (UGO). These permissions attributes are saved along with files on filesystem.

UID/GID 0 is special for Linux kernel; it's the super user (administrator) that is never denied from doing anything. All other users in range 1-65534 are non-privileged IDs which an OS can use in whatever way it wants to control access.



Android reserves UIDs in range 1000-9999 for system use unlike Linux distros where 1000 is usually the first UID assigned to human users. Android is designed for single human user but every Java app, whether preinstalled (as system or user app) or installed by user, is treated as a user. UID range 10000-19999 is reserved for these apps. At first boot (for preinstalled apps) or when installing a new app, a unique UID/GID is assigned to the app which is static unless the app is uninstalled. This app vs. UID mapping can be seen in file /data/system/packages.list or using command id (1) if the app provides a shell or can execute native binaries.



All of these UID's have hard-coded names on Android which are predefined, unlike Linux distros, where there are almost standardized naming conventions for users and groups which can be added / removed in /etc/passwd and /etc/group. Android shares only root user name with Linux. However these names are only for the ease of human users, for kernel only numbers (UID/GID) mean.



Access Control Lists (ACLs) can be used to extend DAC for more granular privileges but those are rarely used on Linux and (AFAIK) not used on Android.



LINUX CAPABILITIES:



Root user's authorities are further divided into subgroups called capabilities. Instead of using UID 0 whenever an elevated task is to be performed, a non-privileged UID can be granted only the required capability. File capabilities which are attached to files using Extended Attributes (XATTR), can also be used to elevate process capabilities whenever required. Android makes use of File Capabilities as well as Ambient Capabilities. See this thread for more details.



MANDATORY ACCESS CONTROL:



Mandatory Access Control (MAC) was introduced later to supplement DAC for better security. Android uses SELinux as part of its security implementations. SELinux also makes use of Extended Attributes to label files with a context while every process is also run with a SELinux context. Then a policy is defined which includes thousands of rules allowing one context access the other, denied otherwise by default. See this answer for more details on SELinux and an example how Android makes use of DAC, capabilities and MAC.



By making use of Linux kernel's DAC, MAC and capabilities, Android launches every app in a sandboxed virtual machine forked from zygote process, with its unique ID and with all capabilities dropped, so that forced to access only it's own files in /data/data/<app_pkg_name> or in external storage. See this answer for more details.



MANIFEST PERMISSIONS:



To have a further fine-grained control of system resources, in addition to Linux's access control mechanisms at kernel level, Android enforces it's own Manifest Permissions to installed apps within its core framework. These permissions are of three types: Normal, Dangerous and Signature.

All normal permission are granted to a requesting app without human interaction. For instance a user can't restrict an app from accessing internet if the app is requesting android.permission.INTERNET. Some of such permissions are controlled by using third party tools.

Dangerous permissions - such as READ_CONTACTS - aren't granted to an app without user's approval. Some of Signature permissions treated as Special permissions - such as REQUEST_INSTALL_PACKAGES - can also be controlled from Settings app > Apps & notifications > Advanced > Special app access menu on newer Android versions.

Additionally some of the permissions for which user doesn't have independent control such as GET_ACCOUNTS, or the operations which don't have corresponding permissions at all such as RUN_IN_BACKGROUND, can be controlled from a hidden permissions manager of Android: AppOps. But this is meant only for OS use and not for end users.



PERMISSION CHECKING AND ENFORCING:



Permission preferences are stored by Android Package Manager in different files such as /data/system/packages.list, /data/system/packages.xml, /data/system/users/0/runtime-permissions.xml at app install time or at runtime. These permission checks are then enforced on multiple events such as when accessing intents, starting an activity, sending/receiving broadcast, accessing a content provider, starting/binding to a service etc.



Though the whole permission checking and enforcing process happens under zygote in which ActivityManager and PackageManager - which are part of system_server - play major role, the core framework doesn't handle every permission check on its own. It again takes help from kernel to make permission checks more robust and efficient.

For instance READ/WRITE_EXTERNAL_STORAGE permissions are enforced through UIDs/GIDs by bind-mounting different views of Storage in a mount namespace for every app. See this answer for further details.



PERMISSION <--> GID MAPPING:



Another special case where Android relies on Linux kernel for permission check is android.permission.INTERNET. As stated earlier, only UID/GID 0 is special for standard Linux kernel. However Android applied a special patch PARANOID_NETWORKING to Linux kernel which maps certain capabilities to certain group IDs in range 3000-3999 making them special. One of those is INET (3003) group which allows its members to access internet (create PACKET sockets) which isn't possible without capability NET_RAW otherwise. All permission <-> GID mappings can be found in file /system/etc/permissions/platform.xml.



Coming to your question:




since mapping of permissions with UIDs is done at install time, PackageManager should be able to map the permission directly with the APK's UID instead of adding inet GID to your APK package




So the answer is, PackageManager doesn't handle android.permission.INTERNET on its own. It just adds the app to INET group and saves the configuration. Let's take example of Termux:



~# grep termux /data/system/packages.list
com.termux 10142 0 /data/user/0/com.termux default:targetSdkVersion=28 3003


Next time the app is launched with 3003 in its supplementary groups so that kernel doesn't restrict the app from accessing internet when enforcing DAC:



~# ps -p $(pgrep com.termux) -o cmd,uid,gid,supgrp
CMD UID GID SUPGRP
com.termux 10142 10142 3003,9997,20142,50142


SOURCES:




Topics


2D Engines   3D Engines   9-Patch   Action Bars   Activities   ADB   Advertisements   Analytics   Animations   ANR   AOP   API   APK   APT   Architecture   Audio   Autocomplete   Background Processing   Backward Compatibility   Badges   Bar Codes   Benchmarking   Bitmaps   Bluetooth   Blur Effects   Bread Crumbs   BRMS   Browser Extensions   Build Systems   Bundles   Buttons   Caching   Camera   Canvas   Cards   Carousels   Changelog   Checkboxes   Cloud Storages   Color Analysis   Color Pickers   Colors   Comet/Push   Compass Sensors   Conferences   Content Providers   Continuous Integration   Crash Reports   Credit Cards   Credits   CSV   Curl/Flip   Data Binding   Data Generators   Data Structures   Database   Database Browsers   Date &   Debugging   Decompilers   Deep Links   Dependency Injections   Design   Design Patterns   Dex   Dialogs   Distributed Computing   Distribution Platforms   Download Managers   Drawables   Emoji   Emulators   EPUB   Equalizers &   Event Buses   Exception Handling   Face Recognition   Feedback &   File System   File/Directory   Fingerprint   Floating Action   Fonts   Forms   Fragments   FRP   FSM   Functional Programming   Gamepads   Games   Geocaching   Gestures   GIF   Glow Pad   Gradle Plugins   Graphics   Grid Views   Highlighting   HTML   HTTP Mocking   Icons   IDE   IDE Plugins   Image Croppers   Image Loaders   Image Pickers   Image Processing   Image Views   Instrumentation   Intents   Job Schedulers   JSON   Keyboard   Kotlin   Layouts   Library Demos   List View   List Views   Localization   Location   Lock Patterns   Logcat   Logging   Mails   Maps   Markdown   Mathematics   Maven Plugins   MBaaS   Media   Menus   Messaging   MIME   Mobile Web   Native Image   Navigation   NDK   Networking   NFC   NoSQL   Number Pickers   OAuth   Object Mocking   OCR Engines   OpenGL   ORM   Other Pickers   Parallax List   Parcelables   Particle Systems   Password Inputs   PDF   Permissions   Physics Engines   Platforms   Plugin Frameworks   Preferences   Progress Indicators   ProGuard   Properties   Protocol Buffer   Pull To   Purchases   Push/Pull   QR Codes   Quick Return   Radio Buttons   Range Bars   Ratings   Recycler Views   Resources   REST   Ripple Effects   RSS   Screenshots   Scripting   Scroll Views   SDK   Search Inputs   Security   Sensors   Services   Showcase Views   Signatures   Sliding Panels   Snackbars   SOAP   Social Networks   Spannable   Spinners   Splash Screens   SSH   Static Analysis   Status Bars   Styling   SVG   System   Tags   Task Managers   TDD &   Template Engines   Testing   Testing Tools   Text Formatting   Text Views   Text Watchers   Text-to   Toasts   Toolkits For   Tools   Tooltips   Trainings   TV   Twitter   Updaters   USB   User Stories   Utils   Validation   Video   View Adapters   View Pagers   Views   Watch Face   Wearable Data   Wearables   Weather   Web Tools   Web Views   WebRTC   WebSockets   Wheel Widgets   Wi-Fi   Widgets   Windows   Wizards   XML   XMPP   YAML   ZIP Codes