Android R, Package Visibility, and Some Holes
One of the changes that showed up in R DP2 is
the package visibility restriction.
Once your targetSdkVersion
reaches R
, you will not be able to “see” some
of the other apps on the device:
-
Explicit
Intents
cannot be used to start or bind to components -
Many (if not all)
PackageManager
methods filter them out
So, PackageManger
methods like getInstalledApplications()
, getInstalledPackages()
,
getPackagesHoldingPermissions()
, and 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 <queries>
manifest
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
that supports ACTION_MAIN
and 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
fits the <queries>
structure.
So, the simple way to bypass this restriction is to whitelist ACTION_MAIN
and CATEGORY_LAUNCHER
,
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 ACTION_MAIN
and CATEGORY_LAUNCHER
does not just allow
those activities to be visible via queryIntentActivities()
. Apps with a launcher activity
become visible in getInstalledApplications()
and 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 <queries>
configurations
to certain roles in RoleManager
, so only the launcher can whitelist
ACTION_MAIN
and CATEGORY_LAUNCHER
.
But, from the standpoint of fingerprinting, that might be insufficient. An app
could whitelist a bunch of common Intent
structures, such as ACTION_BOOT_COMPLETED
and ACTION_SEND
. Similarly, an app could elect to whitelist common user-installed packages, rather
than 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 PackageManager
results.
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