Custom Permission Vulnerability and the 'L' Developer Preview

Earlier this year, I blogged about a vulnerability in the way custom permissions work in Android. In a nutshell, the <permission> element is “first one in wins”, opening up scenarios in which an attacker can silently gain access to secured components of another app.

A Google+ post from early July tipped me off that there might be changes in the “L” Developer Preview, and I finally got the time to run some tests.

Near as I can tell, the “L” Developer Preview requires that all apps with a <permission> element for the same android:name value be signed by the same signing key. The actual protectionLevel or other values inside the <permission> do not matter. Even if they are identical, an app trying to define the <permission> will fail to install if an existing installed app already defines the <permission>. Specifically, the installation of the second app will fail with a INSTALL_FAILED_DUPLICATE_PERMISSION error.

As with many changes of this type, there is good news, and there is bad news.

The good news is that this should go a long way towards closing this security hole. No longer can an app gain access to another app’s secured compoennts simply by being installed first. The exception is if they are signed by the same signing key, in which case Android assumes that they are written by the same developer (or firm).

However, there are various aspects of bad news:

  1. Two apps signed by different signing keys cannot access each other’s secured components, if they are secured via custom permissions. You wind up with a “deadly embrace”-style scenario. One app has to be installed first. If that app does not have the <permission> element, it will not be able to hold that custom permission. But if it does have the <permission> element, the second app cannot be installed if it also has the same custom <permission> defined. If both apps each have their own custom <permission>, we cannot simultaneously satisfy the rules for both of those custom <permission> elements, and something breaks.

  2. In a host-and-plugin architecture, the plugins cannot define the <permission>, as if they get installed first, the host cannot then get installed. Hence, if a plugin detects that it was installed before the host, it will need to prompt the user to uninstall the plugin, install the host, then re-install the plugin… which may be enough to cause the user to just uninstall the plugin and go with some other solution.

  3. We may see “denial of service”-style attacks – whether intentional or otherwise – when an app defines the <permission> that should be defined by some other app. For example, any app can prevent the user from later installing Adobe Reader, just by defining a <permission> that Adobe Reader defines. And, because this behavior is different from the pre-“L” behavior, this could easily happen by accident.

One thing that could help here would be to extend <uses-permission> to include an android:permissionMissingMessage attribute (or perhaps something shorter). This attribute would point to a string resource that would be shown in a dialog if the user attempts to install the app and the permission requested in <uses-permission> does not exist. Right now, the installation just goes ahead, despite the fact that there is no obvious scenario in which that permission will ever work. IMHO, the installation should fail, where the permissionMissingMessage would give the user guidance for how to resolve the conflict. For example, a plugin would use a message to tell the user to install the host app first. We could go even further and have an android:permissionProvider attribute, pointing to the package name of the app that should be installed first to provide the missing <permission>. The dialog showing the custom message could then have a button to allow the user to go install the missing app via the device’s default marketplace (e.g., Play Store). I have no idea if “L” offers anything like this, as the “L” developer documentation is merely JavaDocs. I filed an enhancement request about it.

Of course, there is every chance that the shipping Android release stemming from “L” will roll back this change in <permission> behavior, or introduce other modifications that address my concerns.

All that being said, what I am seeing is a distinct improvement over what we had, from a security standpoint, and with minor tweaks, we can fix the UX issues as well.