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:
-
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. -
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. -
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.