1 <?xml version="1.0" encoding="utf-8"?>
2 <manifest xmlns:android="http://schemas.android.com/
3 apk/res/android" package="com.example.app">
4 ...
5 <application ...>
6 <provider
7 android:name=".ExampleProvider"
8 android:authorities="com.example.app.provider"
9 android:permission="com.example.app.permission">
10 </provider>
11 </application>
12 <permission
13 android:protectionLevel="normal"
14 android:name="com.example.app.permission">
15 </permission>
16
17 </manifest>
Figure 2. An example AndroidManifest.xml
file that defines a content provider
Accordingly, to locate those candidate apps, our sys-
tem first parses their manifest files to determine whether
there is any content provider component defined. If yes,
we extract the corresponding attributes. The first one is
the exported property as it specifies whether or not the
content provider is accessible by other apps. (If it is not
defined, the default true value is assumed, which means
any app can access it.) The second one is to detect the
presence of any custom permission(s) to regulate the read
or write accesses to the content provider. More specifi-
cally, there are three closely-related ones: readPermission,
writePermission, and permission. The readPermission
and writePermission explicitly specify the respective per-
mission used to query and make changes to the data
managed by content provider. If they are missing, the
permission attribute will be used.
In other words, our system chooses those apps as candi-
dates if they explicitly export a content provider by setting
true in its exported attribute or implicitly export this in-
terface without specifying this attribute. In addition, our
system also selects those apps, which may have custom
permissions, but the corresponding protection level(s) are
not defined or defined at the normal level. After that, for
bookkeeping purposes, we further extract other attributes of
the content provider component from these candidate apps,
including the name property, which specifies the specific
class implementing the content provider interface, as well as
authorities, which is used by the Android runtime to lo-
cate the content provider itself. All these relevant attributes
will be collected along with the app information and saved
into a local database for subsequent analysis.
3.2 Vulnerable App Determination
After selecting candidate apps, our next step is to ana-
lyze them to locate vulnerable ones. In order to effectively
manage a structured set of data in a local SQLite database,
the Android framework provides well-defined APIs to ease
the creation and maintenance of content providers. Specif-
ically, these APIs are provided in a number of system-
wide classes, including SQLiteDatabase (which contains
the methods to create, delete and execute SQL commands)
and SQLiteQueryBuilder (which helps build SQL queries).
In other words, content providers can leverage these meth-
ods to implement their own standardized APIs that can
be invoked to query and make changes to records in lo-
cal databases. To simplify our discussion, we call these
Android APIs that actually manipulate local databases
terminal functions.
From another perspective, the content provider compo-
nent essentially encapsulates local content and exports them
through standardized APIs. For instance, one standard-
ized API is query() that accepts one parameter URI to pin-
point which table to query and other parameters to spec-
ify query conditions (e.g., the conditions used in the where
clause). Another API is insert() which handles requests
to insert new content into local databases. Consequently,
these Android APIs become the actual entry points of con-
tent providers to other apps. We call them start functions.
Figure 3 shows the implementation of a content provider
named ExampleProvider. It implements the query() (line
17), insert() (line 29) and openFile() (line 37) inter-
faces which can be invoked by other apps to operate on
the internal SQLite database and internal files. Hence these
three functions are start functions. In order to manipu-
late the data maintained by the internal SQLite database, it
leverages the methods provided by SQLiteDatabase class
to perform SQL query (line 25) or insert data (line 33) into
database. Hence these two methods are terminal functions.
Similarly, the function used to open internal files (line 41)
is classed as a terminal function.
A passive content leak vulnerability exhibits if certain
inputs can trigger an execution path from a start function
to a terminal function. Accordingly, we generate a func-
tion call graph of a given app to help determine reachabil-
ity from the public content provider interfaces (i.e., start
functions) to the low-level database-operating routines (i.e.,
terminal functions). More specifically, we first generate
the whole program function call graph for the app and find
all the functions containing terminal functions. Then for
each start function, we identify all potential paths from
it to corresponding terminal functions. Although the con-
struction of whole program function call graph is a well-
studied topic, there are certain aspects unique to Android.
One example is the resolution of object references, which is
the Android counterpart to traditional points-to analysis in
binary analysis, as the exact type of a class object needs to
be determined before we can actually obtain the list of func-
tions it may invoke. The second one is the call graph dis-
continuity introduced by the event-driven nature of Android
apps (e.g., with extensive use of callbacks or event registra-
tions). As an app may register various callback functions
4