Hey you. You know all those news articles about how Facebook is listening to your every conversation to sell you ads about things you talk about? And then you go “oh yeah Facebook is pretty shitty and also Zuckerberg called people dumb fucks for trusting him, I’m going to make a hat out of foil”? We’ve all been there.

Luckily, Android is made by Google. Who also mine your every thought to sell ads, but part of that is blocking Facebook from stealing them first. So Android has a permission system and a security model enforcing it, so that random apps you install can’t intercept all your SSL traffic and steal your bank password. Unless you let them, I guess.

When you install an app, it gives you that big popup saying “This app requires permission to access location data”, etc. That is stored in the app manifest, an XML file describing the app and what permissions it wants. This is parsed as part of Android app loading to grant permissions to the process via PackageManagerService and queried via PermissionManagerService to see if it should be able to request GPS - if an app tries to get your location anyways, it will just error out.

“But I’m super smart”, I hear you say, “and I know about cool Java stuff from years ago to do things I’m not supposed to!”. Or know that you can ship native written-in-C-and-bubblegum shared objects with apps and call them via JNI. Surely you can just bypass the security manager, or do whatever the class you’re trying to invoke is doing manually, and then ride off into the sunset? On Linux you’d just ioctl some gps device and get data, and Android is Linux! Thankfully, that doesn’t work.

It’s maybe important to go over how apps actually run. Android is, fundamentally, a Java operating system on top of the Linux kernel. When it boots, it runs a process called zygote which sets up and caches a new JVM instance and then just…waits. When apps want to run, zygote forks, creating a new process, and then the new process loads your own java bytecode and starts snapchatting or whatever. Java sandboxing was hilariously insecure, as the flood of Java applet exploits showed years ago. This is why you’re allowed to run native code, because being stuck inside the Java sandbox isn’t part of their security model. Breaking out of it doesn’t get you anything - you’re still in your own process, and Android gives each app a separate UID and GID with their own permissions for isolation. Android even has strict SELINUX rules limiting processes access to files and syscalls that they shouldn’t use, so that even if other high privilege native processes included by your OEM are owned in some way, they probably don’t have access to the actual GPS modem device either.

An integral part of Android is that your app doesn’t do all that much. That link above for querying permissions is to PermissionManagerService, a core service. Services are long-running singletons started automatically when Android boots, and aren’t in your process. Most of them are running in system_server, which is the highest trusted process in Android, and which you talk to via Binder[1]. When an app does (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE), they aren’t creating a new instance of the Location service - they’re getting a LocationManager that just asks the existing Location service to do things on its behalf, and then subscribe to results. The Location service is the one that asks PermissionManagerService if you’re allowed to do it or not, via code you can’t touch. And, since system_server is the one actually handling getting GPS data and pushing it to subscribers, it can also list all the apps that are currently subscribed easily, allowing auditing of apps behaviors, so you can see if TikTok is requesting your location when it really shouldn’t be. Newer Android versions even have one-time permissions, allowing you to only give apps access to GPS or your camera once instead of indefinitely, where it could keep using it in the background.

Together, it lets you be reasonably sure that Facebook isn’t listening to you 24/7 to sell ads. There are security vulnerabilities that allow for subverting the Android security model, same as anything else, but Google takes them pretty seriously, and it’d be a giant scandal if Facebook was using some permissions 0day to activate microphones since it’s pretty easy to check. Using ADB, you can call the dump() method in all of those core services via Binder (try it with adb shell dumpsys activity!), which gives you a lot of introspection into what’s happening on your phone.

And, of course, it must be said that this is for unauthorized access to microphones. Quite a lot of apps ask for all the permissions they can get away with, and then setup a background service to gather data, and the Android permission model doesn’t save you if you give permission. This used to be pretty bad, but Google has since realized that people just want to install apps and not read boring “Facebook wants access to:” popups, so Android does stuff like popping up for permission the first time the app tries to use a capability it requested, and has fine-grained revocation for permissions so you can deny Facebook access to your microphone whenever you want without being forced to uninstall it.


Footnote:

  1. 1: Binder IPC is the almost-entirely-Android-specific IPC mechanism. Think of it like Windows COM, or Linux DBus. Android wrote their own IPC so that it has lower overhead and allowed for process-to-process transactions without a broker for better performance since Android uses Binder so much, or because Google has massive NIH syndrome and hates the open source ecosystem (depending on who you ask). This is also why cybersecurity people go crazy over Binder vulnerabilities. It’s the one trusted interface to talking to the processes that handle a lot of stuff on your phone, so if there’s a deserialization bug or something, it’s bad. And even better, Binder is a Linux kernel module always accessible to nearly every process, meaning if it’s a bug in Binder itself, woops now you’re kernelmode