Android R, Package Visibility, and Some Holes
One of the changes that showed up in R DP2 is
the package visibility restriction.
R, you will not be able to “see” some
of the other apps on the device:
Intentscannot be used to start or bind to components
Many (if not all)
PackageManagermethods filter them out
PackageManger methods like
queryIntentActivities() all give you
a filtered view of what is really on the device.
The argument for this change is fingerprinting, at least in part. Many users do not install or remove apps frequently, so libraries can use that information to generate identifiers that work between apps. This is much like how ad networks use various bits of your browser settings to track you across sites, which you can visualize in the EFF’s Panopticlick tool.
The Android R documentation is a bit “hand-wavy” as to what your app can and cannot see. Based on some light experimentation, it appears that your app can still see pre-installed apps but not user-installed ones. From a fingerprinting standpoint, this seems reasonable – all users with the same model device should have the same mix of pre-installed apps.
If you need to see more apps than that, you can use a
element to whitelist certain packages or
Intent structures. There
is no user acceptance required; whatever you request in the whitelist, you can see.
This allows something like a launcher to whitelist apps with a component
CATEGORY_LAUNCHER, for example.
Hole #1: Whitelisting the World
And that’s the bigger of the holes: anyone can whitelist anything, so long as it
So, the simple way to bypass this restriction is to whitelist
as the vast majority of Android apps will have a launcher activity. And now you can
see (nearly) everything again.
Right now, at least, the whitelist affects the visibility of apps, across multiple
use cases. Whitelisting
CATEGORY_LAUNCHER does not just allow
those activities to be visible via
queryIntentActivities(). Apps with a launcher activity
become visible in
getInstalledPackages() as well.
My guess is that they become as visible as a built-in app.
A possible upcoming counter-move would be to tie certain
to certain roles in
RoleManager, so only the launcher can whitelist
But, from the standpoint of fingerprinting, that might be insufficient. An app
could whitelist a bunch of common
Intent structures, such as
ACTION_SEND. Similarly, an app could elect to whitelist common user-installed packages, rather
Intent structures. Given enough packages, you might be able to develop
a decent fingerprint just by seeing who has what mix of those packages installed.
Android old-timers like me will remember the Android 1.x/2.x days,
when malware would register a
BroadcastReceiver for a zillion common actions, in
hopes that their app would get control before the user had realized that the malware
was, indeed, malware. That same sort of attack seems likely here. That too
could be policed, perhaps at the Play Store approval level, but that can become
fraught with false positives (developers getting bans for legitimate activities)
and false negatives (fingerprinters slipping through because their list wasn’t quite
big enough to raise a warning).
Perhaps Android starts warning users about these whitelists, or starts requiring
dangerous permissions for using certain
PackageManager APIs used by fingerprinters.
Hole #2: Disabled Things Are Disabled
The objective of fingerprinting is to identify a user. This package visibility change is focused on one way of identifying the user: seeing what user-installed apps exist.
However, sometimes, users disable built-in apps. That still affects
queryIntentActivities() does not return activities from disabled apps, for example.
I do this a fair bit, disabling a bunch of pre-installed crap that I don’t want and cannot uninstall. So, a fingerprinter could try to identify people by the “negative space”: what should be on their device (given the model) but does not show up.
My guess is that not all that many people disable apps, so perhaps it is not worthy of a fingerprinter trying to exploit it. And I don’t know what Google could do about it anyway. So, this is just a small hole.
There may be other holes in this system — I have not tried all that much, and this “isn’t really my jam”. I’m just trying to figure out what to tell developers about how this works.
Plus, this is only Developer Preview 2, so some of this may be tweaked in future updates.
But my fear is the package visibility change winds up not satisfying anyone, by:
Adding stumbling blocks for legitimate scenarios, and
Not really solving the intended problem(s), such that attacks are still usable
Want an expert opinion on your Android app architecture decisions? Perhaps Mark Murphy can help!