Android Internals: Package Verifiers

Inspired by Nikolay Elenkov’s detailed technical posts on Android Explorations, I decided to dig into the Android source code myself and document the package verification mechanism in Android.

Package verification was introduced in Android 4.2 to allow for apps to be verified or checked before they are installed. If you have tried to install a malicious app on a production Android device, you might have seen the following screen, displayed by the verifier:

screenshot of malicious app install warning

Android was built in such a way that it tries to be generic for third-parties to implement stuff. Package verification is a feature that is currently only used and implemented by Google, but it is abstracted in such a way that any manufacturer can implement their own. Documentation and examples on how to do this is almost non-existent, although anyone determined enough can read the Android source code and figure it out for themselves.

The package installation process has been previously documented at DZone here and in Japanese here, so I will not be going through the details here.

The verification mechanism consists of what is called the required verifier which decides whether or not your app can be installed on the device. Later on, a mechanism for “non-required package verifiers” or sufficient verifiers was also added. Sufficient verifiers have to be explicitly requested by the app (that is about to be installed) through its manifest file. These verifiers will be consulted before an application package is allowed to be installed. Android will consult the sufficient verifier(s) only when there is a required verifier. If there is no required verifier in the system, no verification of any kind is performed.

Package Manager Internals

Package verification is handled by the PackageManagerService. Internally it uses PackageVerificationState to track the verification state of a particular package install, and PackageVerificationResponse objects for passing messages to the PackageHandler (a subclassed Handler). None of these classes are exposed externally. Instead, PackageManager exposes the verification API that should be used by package verifiers, in particular verifyPendingInstall and extendVerificationTimeout.

The package installation process is driven by Messages sent to the PackageHandler. After the verification request intents are broadcasted, a delayed Messaage is sent to the Handler‘s message queue using sendDelayedMessage. All timeouts are implemented the same way, which is why the extendVerificationTimeout method requires the response to be specified up front — the message containing the response code is created at the time of invocation and sent using sendDelayedMessage. Calling the verification APIs will also send messages to the PackageHandler.

The PackageManagerService broadcasts the PACKAGE_NEEDS_VERIFICATION intent to package verifiers when a package is about to be installed. Package verifiers respond to this intent by calling verifyPendingInstall. The Intent contains extras that specify install flags, the installer package, and the temporary path to the APK file, which allows you to read (or “scan”) the APK.

A PACKAGE_VERIFIED intent is also broadcasted to verifiers after verification for a particular package has completed, provided that they have the PACKAGE_VERIFICATION_AGENT permission and the appropriate intent filter. No action is required by the verifiers. The purpose of this intent is to allow for monitoring of the installation attempts of packages and the verification result, whether allowed or rejected.

There are 2 global settings that influence package verification behaviour: PACKAGE_VERIFIER_TIMEOUT and PACKAGE_VERIFIER_DEFAULT_RESPONSE (these constants are hidden in Settings.Global). The timeout controls how much time elapses before PackageManager checks whether the verifier(s) have responded (defaults to 10 seconds). The default response determines what happens when the verifier(s) have not replied after the timeout has elapsed. If the default response is VERIFICATION_ALLOW, packages will be installed even if the verifier(s) do not respond. Package verifiers can call extendVerificationTimeout if it realises that a response cannot be provided in time (e.g. when it needs to consult a server and there is currently no network connectivity). This method must be called before the verification timeout has elapsed. These settings can be altered using the settings tool, through an adb shell, like so:

settings put global verifier_default_response -1

where -1 indicates PackageManager.VERIFICATION_REJECT and 1 means PackageManager.VERIFICATION_ALLOW.

Upon startup, the system finds the required verifier by calling the getRequiredVerifierLPr method. This only happens once, when the PackageManagerService is being initialized. If there is more than one package that fulfils the requirements of being a required verifier, an exception is thrown and Android will fail to boot up:

    E/System  ( 2515): ******************************************
    E/System  ( 2515): ************ Failure starting core service
    E/System  ( 2515): java.lang.RuntimeException: There can be only one required verifier
    E/System  ( 2515):      at com.android.server.pm.PackageManagerService.getRequiredVerifierLPr(PackageManagerService.java:1510)
    E/System  ( 2515):      at com.android.server.pm.PackageManagerService.<init>(PackageManagerService.java:1468)
    ...

The required verifier and sufficient verifiers are distinguished from one another by their uids (user IDs). The uids of the verifiers are checked in the PackageVerificationState class (note the mRequiredVerifierUid and mSufficientVerifierUids fields within the class). Verifiers should thus have different uids.

Required Verifier

The concept of the required verifier is easy to understand. It is the primary mechanism for package verification. If the system has a required verifier, and the system settings have been enabled (which it is by default), the verifier will be consulted for all packages before they are allowed to be installed. Note that the verification mechanism is only concerned with preventing installations — the verifier can choose to display any additional dialog(s) to prompt the user for input or to convey information about the package (e.g. why the installation was disallowed).

Verifiers are notified of pending installs via the PACKAGE_NEEDS_VERIFICATION intent. When the verifier receives the intent broadcast, it responds by invoking verifyPendingInstall. The required verifier must have the PACKAGE_VERIFICATION_AGENT permission in order to receive the broadcast. As this permission is only granted to signatureOrSystem apps, this means that only device manufacturers or ROM vendors will be able to provide such a verification app.

The required verifier is provided by Google on most production Android devices (but not on the emulator), so it must be one of the Google-bundled apps. Using adb shell dumpsys package, we can check which package implements this functionality:

    Verifiers:
      Required: com.android.vending (uid=10014)


    Activity Resolver Table:
      Full MIME Types:
        ...

      MIME Typed Actions:
        ...
          android.intent.action.PACKAGE_NEEDS_VERIFICATION:
            42a1dd98 com.android.vending/com.google.android.vending.verifier.PackageVerificationReceiver filter 4290d8a0

          android.intent.action.PACKAGE_VERIFIED:
            42a1dd98 com.android.vending/com.google.android.vending.verifier.PackageVerificationReceiver filter 4290d8a0

The PackageManager includes the verifier information at the start of the dump. Further down, you can see that the com.android.vending package has also registered for the appropriate verification intents. This package will thus be responsible for the verification of packages on the device. If you reverse-engineer the APK, you will find that it consults the Google Safe Browsing API (probably a subset not published publicly) with the package information.

There can only be one required verifier in the system that fulfills the criteria, otherwise the OS will not boot up.

Sufficient Verifiers

This provides a means for a package to explicitly request for verification, by specifying a <package-verifier> element in the manifest, which looks something like this:

    <package-verifier 
        android:name="org.mycompany.verifier" 
        android:publicKey="Zm9vYmFy..." />

The publicKey attribute ensures that the package being installed will only be verified by a legitimate verifier that has been pre-determined (i.e. signed by the specified public key). The public key of the verifier package is base64-encoded, like the ones found in /data/system/package.xml. This mechanism assures developers that only verifiers they trust will receive verification requests.

There can be multiple sufficient verifiers requested in the manifest. If sufficient verifiers have been requested, at least one of them must be matched, otherwise the installation fails with “Additional verifiers required, but none installed.” For the installation to proceed, there must be at least a single sufficient verifier that responds ALLOW to the verification request. An exception to this case is if the default verification response is VERIFICATION_ALLOW and none of the verifiers respond before the timeout. This internally sets the response to VERIFICATION_ALLOW_WITHOUT_SUFFICIENT, causing the logic in isInstallAllowed to return true.

Uses for such verifiers are limited as it requires the developer to explicitly request for verification. However, since Android allows for new permissions to be defined by third-party applications, this mechanism might potentially be used for the verification of the consumers of these non-standard permissions.

Sufficient Verifiers Bug

As far as I can tell, the current implementation of sufficient verifiers does not work as intended. They have in place the mechanisms for finding the verifiers, sending the broadcasts to them, and receiving the replies, but the permissions enforcement code in PackageManager prevents sufficient verifiers from responding to the broadcasts.

Sufficient verifiers are registered almost the same way as the required verifier — by declaring an appropriate receiver — except that they do not require the PACKAGE_VERIFICATION_AGENT permission. Commit 7e671 was introduced one year later in Aug 2012, adding checks that require package verifiers to have the PACKAGE_VERIFICATION_AGENT permission to use the verification APIs exposed through PackageManager. However, recall that if more than one package has this permission, Android will refuse to boot up due to the check at getRequiredVerifierLPr.

Until Google fixes this Catch 22, (the current concept of) sufficient verifiers will not work in released versions of Android.

Future Work

As Google regularly develops features and releases them into the AOSP tree without documentation, it will be interesting to see what Google is planning to do with the concept of “sufficient verifiers”.

Examples of such on-going work also include App Ops, which is still being actively developed and was accidentally exposed to users in Android 4.3.

Commit References

  • Aug 2011: commit 5ab21 introduced the concept of a package verifier
  • Sep 2011: commit 05ca4 added support for sufficient verifiers
  • Aug 2012: commit 7e671 exposes verification APIs in PackageManager and require PACKAGE_VERIFICATION_AGENT permission
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s