By Jake Edge
February 28, 2013
In a two-hour session at the 2013 Android Builders Summit,
Marko Gargenta described the "underpinnings" of Android security. It was a
wide-ranging talk that filled in many details of the Android
security model and its implementation.
There are multiple layers in the Android stack, Gargenta said, showing a slide [JavaScript] of
the Android architecture. He broke the stack up into four layers:
kernel, native code, API, and apps. Each of those has its own security
concerns, he said.
Apps
In the Android security architecture, apps cannot directly interact with each
other, nor
with any of the other processes on the system. Those other processes come
about as
the Android system is initialized. After the kernel boots, init
launches a
few daemons
needed by the rest of the system (vold, netd, installd), then starts the
servicemanager. In turn, the servicemanager launches zygote, which is the
"initial app" and the root of the app tree. All of those processes run as
the root user, but anything started after that (including the
system_server
and any apps) run under its own user ID (UID).
Each app runs in its own process, and by default is not allowed do anything to
adversely affect any other app, the system, or the user. That separation
is enforced by the kernel's normal user permissions. On top of that,
Android adds a fine-grained permission system that allows users to grant
specific privileges to apps, but the apps must declare the privileges they
want ahead of time.
Apps can explicitly share resources and data with other apps via the binder
inter-process
communication (IPC) mechanism, ContentProviders,
Intents,
the filesystem,
local sockets, and so on. That sharing is outside of the scope of the
Android security model. All apps are treated equally by the system, with
the same level of application sandboxing.
The sole enforcement mechanism for the application sandbox is the Linux
kernel. The Dalvik virtual machine (VM) does not provide a security
boundary (unlike the Java VM). Each app has its own Dalvik VM as well as
all the Android resources (activities, services, receivers, providers,
etc.) in its process space.
Apps are stored in a .apk files, which must be signed. The
signature is meant to uniquely identify the owner of the app, but that
doesn't necessarily translate to a real life entity. It is, instead,
used to create a trust relationship between apps. The signature is also
used to verify that the contents of .apk file have been correctly
signed with the owner's key and have not been corrupted.
App signing uses public-key cryptography as defined by the Java JAR
specification. Most developers will already
have a key that was created by Eclipse and lives in
.android/debug.keystore. The keytool utility should
be used to create a more permanent keystore. No third party
certificate authority (CA) is needed for signing the keys as they can be
self-signed. Google Play store policy for apps requires a key that is valid
until at least October 2033, but
keys should be valid for 25 years or more, Gargenta said.
Once an app is signed, it is "zipped" into a archive file, which is essentially
what an .apk is. Each file in the zip archive is individually
signed, and those signatures are stored in a file in the META-INF
directory. The .apk contains the classes, resources, and the
manifest, along with META-INF. One can use jarsigner to
sign the files, and keytool to verify keys and signatures.
The platform itself has four different keys, which are often overlooked by
people creating their own ROM. There is a "platform" key used to sign the
core frameworks, a "shared" key for ContentProviders, a "media" key for the
media frameworks and applications (e.g. Gallery, DrmProvider), and a
"testkey" for everything else. Those can be created using
keytool. Shipping a ROM with the default keys is a big mistake,
Gargenta said, because anyone can create an update.zip firmware
update file to
replace any part of the system they want.
Users
Android doesn't use Linux users (and UIDs) in the usual way. There are
"virtual users" that correspond to each app. When installed, an app gets a
UID (and
identical group ID)
assigned to it. Up until Ice Cream Sandwich (ICS, Android 4.0), the UIDs
were assigned starting at 10,001 and given names like app_N,
where N is the offset from 10,000. After ICS, the mapping took
multiple human users into account, so the names became uM_aN, where
M corresponds to the human user, and uses a different formula
(100,000 * user + appnum, so u10_a3 becomes 101,003 1,010,003).
There is no passwd file on an Android system, but the mapping
from app to UID can be found in the /system/packages.list file.
That file lists the app name, UID, and the location of the app's private data
storage in the filesystem. When an app is first downloaded, it is put into
a quarantine space and examined by installd; if the signature
check passes, a UID/GID is assigned and the app is installed. It is possible
to have multiple apps (all signed with the same key) running under the same
UID, but they are really
considered by the system to be part of the same app.
Files
Android has a few separate filesystems. The /system filesystem is
"essentially the ROM", Gargenta said. It is mounted read-only and contains
the Android OS, system libraries and apps, system executables, and so on.
The application developer and user have no access to that filesystem
(unless the device is rooted), and it contains no user data, so it doesn't
need to be backed up or encrypted.
The /data partition is mounted read-write and contains all of the
downloaded apps and the storage for all apps (including the system apps).
The /data/data directory is the location where apps store their
data. A
a subdirectory named after the app is created that is owned by its UID/GID
and has
permissions that does not allow access from other UIDs. This is how the storage sandbox is
handled. There is a lib directory in the app's storage, which holds
the native libraries that the app needs. That directory is
added to the LD_LIBRARY_PATH of apps before they are started.
The init process mounts the filesystems and sets the permissions
for the files in those filesystems, which can be seen in the
init.rc file. It ensures that
/system is mounted read-only as it may have previously been
mounted read-write for an over-the-air (OTA) update.
In Android 4.2 ("Jelly Bean"), support for multiple human users was added
for uses like tablets that are shared by multiple family members. The
number of supported users is set in a configuration file; for phones the
value is 1, but tablets it is often set to 8. When there are multiple users,
apps can be installed for one or more of them. In that case, the data is
not shared—instead, each user gets their own copy of the app's data
directory, but the code and libraries are shared (the latter using a
symbolic link from the lib directory).
Permissions
Permissions are at the heart of the app security model for Android. One
can see the list of all permissions in the system using the
"pm list permissions" command in the adb shell.
Also, the "run-as" command can be used to test permissions as
granted to
specific apps. That is useful for debugging and testing, Gargenta said.
Some permissions are better than others, at least in terms of being
featured in the Google Play store, he said. He listed the Top Ten Bad
Permissions. These are permissions that, if requested by an app, make
it less likely to be featured in the store. For the most part, these are
somewhat dangerous permissions that are a
red flag that the application is asking for more than it needs—or
more than it should need.
For example, the SEND_SMS and RECEIVE_SMS permissions
(for sending and receiving text messages) were at the top of the list.
Unless the app is an SMS program, it shouldn't be using those. Instead, it
should start an SMS composer activity, which will activate an existing SMS
app to handle the message. Similarly, using an intent for
ACTION_IMAGE_CAPTURE will bring up the camera to allow the user to
take a picture and return the result. That avoids requiring the
CAMERA permission. He had suggestions for several other
permissions as well.
Permissions in Android map to groups (i.e. GIDs). If a particular app is
granted a permission, it is added to the group. For example, Android's
"paranoid networking" works by checking if the user is in the
"inet" group; if so, it allows network access, otherwise not.
The permissions for files and devices are set by the init process
Gargenta also briefly looked at some other Android security topics,
including encryption, malware, and device administration for companies that
are issuing phones to their employees (or allowing those employees to use
their own). Those topics were something of an aside to the deep dive into
Android security. Overall, there was a lot to digest in a fairly short
period of time, as Gargenta's slides would
suggest. A longer time slot might have been harder to allocate for a
two-day conference like ABS, but there was certainly material enough to
fill it.
[ Thanks to the Linux Foundation for assisting with travel costs to San Francisco for ABS. ]
(
Log in to post comments)