1 Overview of Android security mechanism
Android is a system with separated permissions. This uses the existing permission management mechanism of Linux to assign different uids and gids to each Appl ic ation, so that the private data and access between different applications (both native and java layers can be isolated through this sandbox mechanism) can be isolated. At the same time, Android also expands on this basis and provides a permission mechanism, which is mainly used to subdivide permissions and control access to certain specific operations that applications can perform. It also provides a per-URI permission mechanism to provide ad-hoc access to certain specific data blocks.
1.1 uid, gid, gids
The basis of Android's privilege separation is built on the existing uid, gid, and gids of Linux.
UID. When Android installs an application, it will assign a uid to it (refer to the implementation of newUserLP in PackageManagerService). The uid of ordinary Android applications starts from 10000 (refer to Process.FIRST_APPLICATION_UID), and the uid below 10000 is the uid of the system process.
GID. For common applications, gid is equal to uid. Since the uid and gid of each application are different, both the native layer and the java layer can protect private data.
GIDS. gids are generated by the framework during the application installation process and are related to the specific permissions applied for by the application. If the corresponding permission applied for by the application is granted and there are corresponding gids, then the gids of the application will include this gid.
Detailed setting process of uid gid gids:
Please refer to startProcessLocked in ActivityManagerService. When starting a process through zygote, uid is directly passed to gid. Then zygote is used to fork a new process (forkAndSpecialize in zygote.java ) , and finally gid, uid and gids are set through Linux system calls in forkAndSpecializeCommon in the native layer (dalvik_system_zygote.c).
1.2 permission
A permission mainly contains three aspects of information: the name of the permission; the permission group it belongs to; and the protection level. A permission group refers to a collection of permissions divided into different groups according to their functions. Each permission group contains several specific permissions. For example, the COST_MONEY group contains android.permission.SEND_SMS, android.permission.CALL_PHONE and other cost-related permissions.
Each permission is identified by the protectionLevel: normal, dangerous, signature, signatureorsystem. Different protection levels represent the authentication method when the program wants to use this permission. Normal permissions can be used as long as they are applied for; dangerous permissions require user confirmation before they can be used during installation; signature and signatureorsystem permissions require the user's app and the system to use the same digital certificate.
The package's permission information is mainly specified in AndroidManifest.xml through some tags, such as
2 Android permission management mechanism
2.1 Framework permission mechanism
2.1.1 Installation entry
Permission initialization refers to the application of permission to the system, the system checks and authorizes, and establishes the corresponding data structure. In most cases, permissions are scanned from a package, which happens when the package is installed or upgraded. There are generally the following installation entrances:
n packageInstaller, which is triggered when a package is downloaded and installed. packageInstaller checks dangerous permissions through AppSecurityPermissions and prompts the user.
n pm command.
n adb install. Finally, pm install is called to install the apk package.
n Copy and install. PackageManagerService uses AppDirObserver to monitor /data/app/ and triggers installation if there is a copy.
These installation methods will eventually complete the installation of the program by calling the functions in PackageManagerService.
2.1.2 Permission creation
The first step is to extract permission information from AndroidManifest.xml. The following information is mainly extracted:
² shared uid
Specifies to share the same uid with other packages.
² permission
Extract the specified attributes of the permissions tag. It uses permissionInfo to describe the basic information of a permission. It needs to specify the protectedLevel information and the group information. It will be added to the permissions list structure of this package.
² permission-tree
Extract the permissions-tree tag attributes. Permissions-tree is also described by permissionInfo and added to the list structure of package permissions. Permission-tree is just a namespace to which some so-called Dynamic permissions are dynamically added. These permissions can be modified dynamically. These permission names must start with the name of permission-tree. It is not a permission itself, and has no protectedLevel and group. It only saves the package it belongs to and the permission name (with the package prefix).
² permission-group
Defines permission group information, represented by PermissionGroup. It does not represent a permission itself, but is added to the permissionGroups list of the package.
² uses-permission
Defines the permission name that the package needs to apply for. Add the permission name to the requestedPermissions list of the package.
² adopt-permissions
Store the name specified by this tag into the mAdoptPermissions list of the package. Name specifies that this package needs to adopt permissions from the package specified by name. Used when the system package is upgraded.
Step 2. Get the certificate in the Package, verify it, and save the signature information in the Package structure.
1. If the package comes from system img (system app), then you only need to obtain the signature information from the AndroidManifest.xml of the Package without verifying its integrity. However, if the package shares a uid with other packages, the signature stored in the sharedUser corresponding to the shared uid is inconsistent with it, and the signature verification fails.
2. If it is a normal package, you need to extract the certificate and signature information and verify the completeness of the file.
Step 3. If it is a normal package, clear the mAdoptPermissions field information of the package (only used for system package upgrades).
Step 4. If a shared user is specified in AndroidManifest.xml, first check the global list (mSharedUsers) to see if there is a SharedUserSetting data structure corresponding to the uid. If not, assign a new uid, create a SharedUserSetting and save it to the global list (mSharedUsers).
mUserIds stores the SharedUserSetting structure corresponding to the uids that have been allocated in the system. Each time when allocating, it always polls from the first one, finds the first free position i, and then adds FIRST_APPLICATION_UID.
Step 5. Create a PackageSettings data structure and bind PackageSettings to SharedUserSetting. PackageSettings saves the SharedUserSetting structure; SharedUserSetting uses the signature information in PackageSettings to fill its own internal signature information, and adds PackageSettings to a queue, indicating that PackageSettings is one of the sharers.
When creating, the packageName will first be used to query the global data structure mPackages to see if there is a corresponding PackageSettings data structure. If the PackageSettings data structure already exists (for example, the package has been uninstalled, but the data has not been deleted, and the package structure has been released), then compare the signature information in the package (scanned from AndroidManifest) with the signature information in PackageSettings to see if they match. If they do not match but it is a system package, then trust this package and update the signature information in the package to the existing PackageSettings. At the same time, if this package shares a uid with other packages, and the signature information saved in the shared uid does not match the current package, then the signature verification also fails.
Step 6. If the mAdoptPermissions field is not empty, process the adoption of the permission (change the owner of the permission to the current package from the PackageSettings corresponding to the specified package. This usually happens when the system app is upgraded. Before this, it is necessary to verify that the adopted package has been uninstalled, that is, check whether the package data structure exists).
Step 7. Add custom permissions. Add the permissionGroup defined in the package to the global list mPermissionGroups; add the permissions defined in the package to the global list (if it is a permission-tree type, add it to mSettings.mPermissionTrees, if it is a general permission, add it to mSettings.mPermissions).
Step 8. Clear inconsistent permission information.
1. Clear inconsistent permission-tree information. If the packageSettings field of the permission-tree is empty, it means that the package has not been parsed yet (if the code is executed to this point, packageSettings must have been created), remove it. If packageSettings is not empty, but the corresponding package data structure is empty (indicates that the package has been uninstalled, but the data is still retained), or the package data structure does not contain this permission-tree at all, then clear this permission-tree.
2. Clear inconsistent permission information. If the packageSettings or package structure is empty (the package is not parsed or uninstalled, but the data is retained), or the permission is not defined in the package at all, then clear the permission.
Step 9. Poll each package and grant permission.
1. Check the requested permissions and update the grantedPermissions list
2. If it has no shared user id set, then initialize its gids to mGlobalGids, which is read from permission.xml.
3. Traverse all the permissions applied for and perform the following checks
1) If the permission is normal or dangerous, pass the check.
2) If the permission requires signature verification. If the signature verification passes, the following checks are also required:
* If the program is upgraded and it is a system package, whether to grant the permission depends on whether the original package has been granted the permission. If it is granted, the check passes, otherwise it fails.
* If it is a new installation, then the check passes.
4. If the check in step 3 is passed, the permission is added to the grantedPermissions list of the package, indicating that the permission application is successful (granted). When the application is successful, the gids of the permission applied for is added to the gids of the package.
5. Set the permissionsFixed field to true, indicating that the permissions of this package have been modified. It will be prohibited to modify the permissions of non-system apps in the future.
2.1.3 Dynamic permission management
PackageManagerService provides addPermission/removePermission interfaces to dynamically add and remove some permissions. However, these permissions must be so-called dynamic permissions (BasePermission.TYPE_DYNAMIC).
If a package wants to add dynamic permissions, it must first declare the
Packages cannot use this interface to modify permissions statically applied for in the manifest, otherwise an exception will be thrown.
First, check whether this permission exists in the global permission list mSettings.mPermissions. If it exists and its type is BasePermission.TYPE_DYNAMIC, modify the permission information in the global table according to the passed permission information and trigger the persistence of permissions.xml.
If the permission is not found in the global permission list mSettings.mPermissions, first find the permissionTree where the permission is located, then add it to the global permission list mSettings.mPermissions, and trigger the persistence of permissions.xml.
2.1.4 Uri permission management
The following two interfaces are mainly used for Uri permission management (actually implemented in ActivityManagerService).
// Add read or write permissions to a content Uri for the specified uid and targetPkg.
public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri, int mode) throws RemoteException;
// Clear all permissions granted to a Uri via grantUriPermission.
public void revokeUriPermission(IApplicationThread caller, Uri uri, int mode) throws RemoteException;
Analysis of the main implementation process of grantUriPermission.
grantUriPermission analysis:
1. Verify that the ProcessRecord and targetPkg of the caller are not empty. Otherwise, the test fails.
2. Verify that the requested mode is Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION, otherwise it will fail.
3. Make sure the parameter Uri is a content Uri. Otherwise, the detection fails.
4. Get the target ContentProvider through Uri. If it does not exist, the detection fails.
5. Get the uid corresponding to targetPkg from PackageManagerService.
6. Check whether the package corresponding to the target uid really needs this permission?
First determine whether you want to apply for read or write permission, and then check whether the corresponding readPermission writePermission field in the corresponding ContentProvider has saved the permission name. If the field is not empty, use the target uid and the permission name to find out whether the uid has been granted the permission in PackageManagerService. If the permission has been obtained, there is no need to apply for the Uri permission for this Activity, and return. Otherwise, continue to perform the following operations.
7. Check the grantUriPermissions switch variable of this ContentProvider to see if it allows granting permissions to other packages. If not, throw an exception.
8. Check if the ContentProvider has set the Uri filter type uriPermissionPatterns. If the filter type is set, match the Uri that needs to apply for permission with it. If the match is different, an exception is thrown.
9. Check if the caller has permission to access this Uri. If not, throw an exception.
10. Get the HashMap "Uri, UriPermission" data structure corresponding to the target uid from mGrantedUriPermissions. Generate UriPermission using target uid and Uri and save it in mGrantedUriPermissions.
revokeUriPermission implementation analysis.
Find the ContentProvider corresponding to the Uri, and then delete all permissions corresponding to the Uri in mGrantedUriPermissions.
2.2 Dynamic check of permission
The dynamic check here refers to the check that is performed when the package performs certain operations or accesses data during program execution. The corresponding check is when the application is installed or upgraded, PackageManagerService scans the static permission information in the package.
The implementation of the system's permission check-related mechanisms is mainly concentrated in PackageManagerService and ActivityManagerService. ActivityManagerService is mainly responsible for the identity check at the bottom uid level; PackageManagerService maintains a table of uids to the permissions it has and is granted. After passing the identity check of ActivityManagerService, PackageManagerService checks this table based on the requester's uid to determine whether it has the corresponding permissions.
In addition, the implementation of the per-URI permission mechanism also requires a table, which is maintained in ActivityManagerService, which establishes a mapping from content URI to components that are authorized to access this URI . However, it also needs the PackageManagerService mechanism to assist in its implementation.
2.2.1 Interfaces provided by the framework
The Android framework provides some interfaces for checking permissions for external access (including itself). These interfaces are mainly provided by ContextWrapper and implemented in ContextImpl. If the package receives an operation request from an external visitor, these interfaces can be called to check permissions. Generally, the check interfaces of these interfaces can be divided into two types: one is to return an error, and the other is to throw an exception.
It mainly includes the following groups:
n permission and uid check API
The following set of interfaces are mainly used to check whether a certain caller (or other packages or itself) has the permission to access a certain permission. The pid and uid can be specified in the parameters. If not specified, the framework will obtain the caller's uid and pid information through Binder and fill it in. The return value is PackageManager.PERMISSION_GRANTED or PackageManager.PERMISSION_DENIED.
public int checkPermission(String permission, int pid, int uid) // Check whether a certain uid and pid has permission
public int checkCallingPermission(String permission) // Check whether the caller has permission. If the caller is yourself, return PackageManager.PERMISSION_DENIED
public int checkCallingOrSelfPermission(String permission) // Check whether you or other callers have permission
The following group is similar to the above. If the check fails, an exception will be thrown and a message will be printed.
public void enforcePermission(String permission, int pid, int uid, String message)
public void enforceCallingPermission(String permission, String message)
public void enforceCallingOrSelfPermission(String permission, String message)
n per-URI inspection API
Add read or write permissions to a package to access the content Uri.
public void grantUriPermission(String toPackage, Uri uri, int modeFlags)
public void revokeUriPermission(Uri uri, int modeFlags)
Checks whether the package with a certain pid and uid has read and write permissions for uri. The return value indicates whether it is granted.
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags)
public int checkCallingUriPermission(Uri uri, int modeFlags)
public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags)
public int checkUriPermission(Uri uri, String readPermission, String writePermission, int pid, int uid, int modeFlags)
Checks whether the package with a certain pid and uid has read and write permissions for uri. If it fails, throws an exception and prints a message.
public void enforceUriPermission(Uri uri, int pid, int uid, int modeFlags, String message)
public void enforceCallingUriPermission(Uri uri, int modeFlags, String message)
public void enforceCallingOrSelfUriPermission(Uri uri, int modeFlags, String message)
public void enforceUriPermission(Uri uri, String readPermission, String writePermission, int pid, int uid, int modeFlags, String message)
2.2.2 Implementation Analysis
The APIs provided in ContextImpl.java are actually encapsulated by the following interfaces in ActivityManagerService.
public int checkPermission(String permission, int pid, int uid) throws RemoteException; // Mainly used for general permission checks
public int checkUriPermission(Uri uri, int pid, int uid, int mode) throws RemoteException; // Mainly used for permission check of Content Uri
n Implementation analysis of checkPermission
1. If the passed permission name is null, then return PackageManager.PERMISSION_DENIED.
2. Determine whether the caller's uid meets the requirements.
1) If uid is 0, it means it is a process with root privileges and no control is performed on the privileges.
2) If the uid is the uid of the system server process, it means it is a system server and no control is applied to permissions.
3) If it is the ActivityManager process itself, no control is performed on permissions.
4) If the caller uid is inconsistent with the req uid passed in as a parameter, PackageManager.PERMISSION_DENIED is returned.
3. If the check in step 2 is passed, call PackageManagerService.checkUidPermission to determine whether the uid has the corresponding permission. The analysis is as follows.
1) First, it calls getUserI dLP to find the permission list of uid (that is, package) according to uid in the PackageManagerService.Setting.mUserIds array. Once found, it means that there is corresponding permission.
2) If not found, then look for it in PackageManagerService.mSystemPermissions. This information is read from /system/etc/permissions/platform.xml at startup. Here are some system-level application uid corresponding permissions.
3) Return the result.
Similarly, the implementation of checkUriPermission is mainly in ActivityManagerService, and the analysis is as follows:
1. If uid is 0, it means it is the root user, so the permissions are not controlled.
2. Otherwise, check whether the uid has this permission in the mGrantedUriPermissions table maintained by ActivityManagerService. If so, check whether it is requesting read or write permission.
3 Android Signature Mechanism
Regarding the signature mechanism, it is actually divided into two stages.
The package scanning phase requires integrity and certificate verification. The signature and certificate of a common package must be verified first. The specific method is to perform integrity checks on several files under the manifest. The integrity check includes all files in the jar package. If it is a system package, you only need to use the AndroidMenifest.xml file to extract the signature and verification information.
During the permission creation phase, if the package comes from the system img (system app), then trust it and use the new signature information to replace the old information. The premise is that if this package shares a uid with other packages, then the signature stored in the sharedUser corresponding to the shared uid is inconsistent with it, and the signature verification fails. Sometimes when an app is uninstalled but the data is not deleted, its PackageSettings information will be retained, which will store the signature information. This will cause inconsistencies when installing again.
3.1 Android Package Signature Principle
In Android, both the system and the app need to be signed. You can generate the public key and private key yourself through development/tools/make_key.
The android source code provides a tool. /out/host/linux-x86/framework/signapk.jar for manual signing. The main function of the signature is to limit the modification of the program to the same source. There are two main places in the system that will be checked. If it is a program upgrade installation, it is necessary to check whether the signature certificates of the new and old programs are consistent. If they are inconsistent, the installation will fail; for the protected level of the permission application is signature or signatureorsystem, it will check whether the certificates of the permission applicant and the permission declarant are consistent. Signature-related files can be found in the META-INF directory in the apk package.
The source code of signapk.jar is in build/tools/signapk. The signing process mainly consists of the following steps:
l Generate SHA1 signatures for all files except CERT.RSA, CERT.SF, and MANIFEST.MF
First, use SHA-1 to calculate the summary information of all non-directory files except CERT.RSA, CERT.SF, and MANIFEST.MF, then encode them using base64 and store them in MANIFEST.MF. If MANIFEST.MF does not exist, you need to create it. The storage format is entry name and the corresponding summary
l Generate a series of signatures based on the previously calculated SHA1 summary information and the private key and write them into CERT.SF
Calculate the SHA1 for the entire MANIFEST.MF and store the summary information in CERT.SF. Then use SHA1 to calculate the digital signature again for all the previously calculated summary information and write it to CERT.SF.
l Write the public key and signature information into CERT.RST
Use the private key to calculate the signature of the entire signature output file. At the same time, write the signature result and the previously claimed public key information into CERT.RSA for storage.
3.2 Package signature verification
The main logic of signature verification of a package during installation is implemented in the verifyCertificate function of the JarVerifier.java file. The main idea is to extract the certificate and signature information in cert.rsa, obtain the signature algorithm and other information, and then calculate it according to the previous method of signing the apk, and compare the obtained signature and summary information with the one saved in the apk.
Step 1. Extract the certificate information and verify the integrity of cert.sf.
1. First find out whether there are DSA and RSA files. If found, decode them and then read all the certificate lists in them (these certificates will be saved in the Package information for subsequent use).
2. Read the signature data information block list in this file, and only take the first signature data block. Read the publisher and certificate serial number.
3. According to the certificate serial number, match all the certificates obtained previously and find the matching certificate.
4. Read the signature algorithm and encoding method from the previously obtained signature data block
5. Read the cert.sf file and calculate the entire signature, compare it with the signature (in encoded format) in the data block, if they are the same, the integrity check is successful.
Step 2. Use the summary information in cert.sf to verify the integrity of MANIFEST.MF.
Extract the signature data blocks starting with SHA1-Digest-Manifest or SHA1-Digest from cert.sf (-Digest-Manifest is the summary information of the entire MANIFEST.MF, and the others are the summary information of other files in the jar package), and verify these data blocks one by one. The verification method is to regard cert.sf as many entries, each of which contains some basic information, such as the digest algorithm used in this entry (SHA1, etc.), which file in the jar package the digest is calculated for, and what the digest result is. When processing, first find the file information in each digest data, then read it from the jar package, and then use the digest algorithm before -Digest to calculate. If the calculation result matches the information saved in the digest data block, then the verification is completed.
Previous article:A new generation of smart sidewalks with WiFi and Bluetooth
Next article:NVIDIA GPU Big Reveal: 28nm's Contribution to Kepler's Energy Efficiency
Recommended ReadingLatest update time:2024-11-16 19:52
- Popular Resources
- Popular amplifiers
- MathWorks and NXP Collaborate to Launch Model-Based Design Toolbox for Battery Management Systems
- STMicroelectronics' advanced galvanically isolated gate driver STGAP3S provides flexible protection for IGBTs and SiC MOSFETs
- New diaphragm-free solid-state lithium battery technology is launched: the distance between the positive and negative electrodes is less than 0.000001 meters
- [“Source” Observe the Autumn Series] Application and testing of the next generation of semiconductor gallium oxide device photodetectors
- 采用自主设计封装,绝缘电阻显著提高!ROHM开发出更高电压xEV系统的SiC肖特基势垒二极管
- Will GaN replace SiC? PI's disruptive 1700V InnoMux2 is here to demonstrate
- From Isolation to the Third and a Half Generation: Understanding Naxinwei's Gate Driver IC in One Article
- The appeal of 48 V technology: importance, benefits and key factors in system-level applications
- Important breakthrough in recycling of used lithium-ion batteries
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- 【AT32WB415 Review】Serial Communication and MP3 Module Playback Control
- Simulation design of phase-shifted resonant power supply and its synchronous rectification circuit
- A very detailed disassembly of the Joyoung soymilk maker!
- How to make a self-propelled car
- Research on WiMAX Network Application Scheme Based on IEEE 802.16e Technology
- ADI's "Basic Tutorial on Analog Electronic Devices" is available for free download!
- Asking for advice on tps65982
- What is the use of ceramic capacitors in parallel with DC motors?
- Last 3 days: Apply for free evaluation of Fudan Micro FM33LC046N Demo board
- Recommend several books on computer vision and image processing with OpenCV