Intent Firewall 防火墙

鱼安然
2023-12-01

Introduction

The Intent Firewall is a component of the Android framework which allows for the enforcement of
intents based on rules defined in XML files. As of last modifying this document, Intent Firewall is not
an officially supported feature of the Android framework and therefore has no official documentation
and could change significantly in future versions. Please refer to Documentation Status to confirm that
this document is up to date.

Capabilities of Intent Firewall

Every intent started in the Android framework, including intents created by the operating system, go
through the Intent Firewall. This means that the Intent Firewall has the power to allow or deny any
intent. The Intent Firewall is also able to dynamically update its rule set as XML files are written to and
deleted from the Intent Firewall directory which makes it a very flexible system to configure on the fly.

Limitations of Intent Firewall

The biggest limitation to the Intent Firewall is that it is only accessible via system applications and root
users since configuring the firewall requires being able to write directly to the device's filesystem. This
is done for obvious security reasons. Even for root users and system applications, writing directly to
the filesystem can be challenging because most physical Android devices keep their filesystem
mounted in read-only mode during normal operation. This means that in order to configure the Intent
Firewall, the filesystem must be remounted into read-write mode. However, most Android devices will
also fail to boot if they are left in read-write mode, meaning that the root user or system application
must then return the filesystem back to read-only mode once they are done configuring the Intent
Firewall. This also raises concerns because it is possible to brick a user's phone should the phone crash
while the filesystem is in read-write mode. This makes the Intent Firewall unusable for standard
applications intended for release via the Google Play Store and difficult to use for root users and
system applications. Phone manufacturers can avoid most of these headaches by directly modifying
the operating system image with additional services designed to streamline the writing process to the
device's filesystem. The Security Enhancements (SE) for Android project has modified images
containing said services, unfortunately SE Android is not fully merged into the standard Android
framework.
Another major limitation with the Intent Firewall is that it does not consider the sender when deciding
how to handle an incoming intent. It can only consider the details of the intent and its intended
receiver.
Lastly, there is no way to conjunctionally combine component filters and intent filters which limits the
types of rules that can be defined.

Getting Started

Configuring Android Intent Firewall

How To Load New Rules

Rules need to be placed in the Intent Firewall's rules directory. This can be challenging given the
reasons I mentioned in Limitations of Intent Firewall section. Any time a file is written or deleted from
this directory, Intent Firewall will automatically look for any files with the .xml extension and try to
parse them for rules. This directory is often /data/system/ifw/, but not always. For developers
interested in writing applications to interact with the Intent Firewall, you can find the correct directory
using the getSystemSecureDirectory() method which belongs to the
android.os.Enviornment class. The ifw/ directory will be a subdirectory of the directory
returned by getSystemSecureDirectory(). See Intent Firewall Rules for more information on rule
syntax.

How To Delete Rules

To delete a rule, you can either remove it from the XML file or delete the XML file all together. The
Intent Firewall will automatically detect that a file has been modified or deleted and reload its rule set.

How To Log Intent Firewall

The easiest way to monitor the Intent Firewall is to use the command adb logcat -s
IntentFirewall:V. This command will filter all the default logs on the Android device and show the
verbose and higher level logs for the Intent Firewall.
Upon writing a valid XML file, a new line should show up in the logs that looks like this:
I/IntentFirewall( 549): Read new rules (A:0 B:0 S:0)
A, B and S correlate the total count of Activity rules, Broadcast rules and Service rules respectively.
One important thing to note is that Intent Firewall will only increment these counts for rules which
contain an intent filter. Rules containing only a component filter will work, but they will not increment
these counters.
Upon writing an invalid XML file, the Intent Firewall's parsers will often throw exceptions. However, do
not rely on the Intent Firewall to throw exceptions when bad rules are written since the Intent Firewall
does little checking beyond checks for proper XML syntax. It is possible, and quite easy, to write rules
that will either never match or always match without the Intent Firewall raising any kind of errors or
exceptions.
If you have added rules which have the log attribute set to true, you can see when these rules match
by using the command adb logcat -b events -s ifw_intent_matched. When these rules
match, a new line in the log will appear which looks like this:
I/ifw_intent_matched( 536):
[0,com.android.browser/.BrowserActivity,10008,1,NUL
L,android.intent.action.MAIN,NULL,NULL,270532608]
The information dumped in between the square brackets is [intentType, componentName,
callerUid, callerPkgCount, callerPkgs, action, mimeType, uri, flags].

Intent Firewall Rules

Format

This is the general format of an XML file containing rules for the Intent Firewall:
<rules>
<activity block="[true/false]" log="[true/false]" >
<intent-filter >
<path literal="[literal]" prefix="[prefix]" sglob="[sglob]" />
<auth host="[host]" port="[port]" />
<ssp literal="[literal]" prefix="[prefix]" sglob="[sglob]" />
<scheme name="[name]" />
<type name="[name]" />
<cat name="[category]" />
<action name="[action]" />
</intent-filter>
<component-filter name="[component]" />
</activity>
</rules>
The rule shown here is for activities, but rules can also target services and broadcasts using the same
syntax. Also note that most of these nodes and attributes are not required and most of the time they
will not all be used to define a rule. In fact, component-filter and intent-filter have varying degrees of
usefulness depending on if your rule is for activities, services, or broadcasts. There are specific
examples of rules later in this section.

Important Considerations

Component-filter requires an explicit component name to work. If you are unfamiliar with
components, some examples are included in the next section. If an invalid name is set for the
component filter, the Intent Firewall will throw an exception. For developers interested in componentfilter,
you can resolve component names programmatically with the help of the package manager.
Never pass "*" as a name. This will cause the Android device to act unpredictably. If this occurs,
remove the bad rule and the phone should recover after some time. To match all, use ".*" or "*/*",
but be aware that most attributes will not accept wild cards.
Intent-filter has multiple criteria which must be met in order for a filter to match. See Intent Filter
Analysis for more information.

Examples

<!-- block all intents to the android phone dialer -->
<rules>
<activity block="true" log="false">
<component-filter name="com.android.dialer/.DialtactsActivity" />
</activity>
</rules>
<!-- block all intents to the android phone dialer AND android web browser -->
<rules>
<activity block="true">
<component-filter name="com.android.browser/.BrowserActivity" />
<component-filter name="com.android.dialer/.DialtactsActivity" />
</activity>
</rules>
<!-- block access to settings menu -->
<rules>
<activity block="true" log="false">
<component-filter name="com.android.settings/.Settings" />
</activity>
</rules>
<!-- block and log a specific broadcast -->
<rules>
<broadcast block="true" log="true">
<intent-filter>
<action name="com.example.demoapp.CUSTOM_INTENT" />
</intent-filter>
</broadcast>
</rules>
<!-- two rules in one file -->
<rules>
<activity block="true" log="false">
<component-filter name="com.example.demoapp/.MainActivity" />
</activity>
<broadcast block="true" log="true">
<intent-filter>
<action name="com.example.demoapp.CUSTOM_INTENT" />
</intent-filter>
</broadcast>
</rules>

Writing and Deploying Your First Rule

In this section, I will provide a step by step guide on how to write and deploy an Intent Firewall rule in
the easiest way possible. This guide is intended to provide a starting point for people interested in
exploring the Intent Firewall. This guide assumes that you already know how to create emulators using
the AVD Manager and have some familiarity with the Android Debugging Bridge (ADB) along with how
intents work in the Android framework.
For this guide, I will be using an Android emulator made using AVD Manager. In general, it is easier to
work with the Intent Firewall in an emulator because root access is already permitted and the
filesystem is already mounted to allow writing.
Our objective will be to write a rule for the Intent Firewall to log whenever the Android device
broadcasts that the "Airplane Mode" setting has been changed.
The first step is to write our rule. In this case, we're interested in the Airplane Mode broadcast sent out
by the Android device. This particular system broadcast uses the action
android.intent.action.AIRPLANE_MODE so this is what we'll write our intent filter to match:
<rules>
<broadcast log="true">
<intent-filter>
<action name="android.intent.action.AIRPLANE_MODE" />
</intent-filter>
</broadcast>
</rules>
Save this rule as an XML file like ifw.xml. The name is not important as long as it ends with the XML
extension.
The next step is to set up our logging so we can visually confirm when the Intent Firewall reads our
rule and when our rule matches the Airplane Mode broadcast. To do this, we'll use two terminals. In
one terminal, run the command adb logcat -s IntentFirewall:V. This is where we'll get
confirmation that the Intent Firewall has successfully read in our new rule. There will likely already be
an entry in this log from when the device first booted up. In the other terminal, run the command adb
logcat -b events -s ifw_intent_matched. This is where we'll see when an intent matches
our rule.
It is now time to copy our rule onto the emulated device. The easiest way to do this is with the
command adb push ifw.xml /data/system/ifw. If everything went well, we should now see an
entry in our first terminal saying:
I/IntentFirewall( 549): Read new rules (A:0 B:1 S:0)
Your message might vary slightly. If no message appears, confirm that you copied your file to the
correct directory. If XML parser exceptions appear, double check that your XML file contains no typos.
With the rule now loaded into the Intent Firewall, it is time to test it. Turn on Airplane Mode from the
device settings and you should see a new message appear in the second terminal.
You have successfully written and deployed your first Intent Firewall rule.

Useful Applications

The following are some high level ideas for what can be done with Intent Firewall:
Use component-filter to block an entire application from running.
Use intent-filter to block a broadcast so no applications receive it.
Use component-filter to prevent the user from accessing their device settings.

Code Analysis

In the following section, I will outline the various classes used in the Intent Firewall and some of their
interesting characteristics. This analysis is by no means an exhaustive look at the code and I encourage
you to look at the source code yourself if you wish to learn more.

Intent Firewall Analysis

Noteworthy Behaviors

If multiple rules match a particular intent, their log and block settings are combined using or logic. For
example, if one matching rule only has block set to true and another matching rule only has log set to
true, then the intent will be blocked and logged.

XML Parsing

This class only deals with this portion of the rule:
<rules>
<activity />
<service />
<broadcast />
</rules>

Methods

checkStartActivity() - calls Activity Resolver (extension of Intent Resolver) to decide if an activity should
be allowed to start. Passes the Activity Resolver an intent, callerUid, callerPid, resolved type and App

Uid.


checkService() - checks if a service should be allowed to start using the Service Resolver. Works

similarly to checkStartActivty() method.


checkBroadcast() - checks if a broadcast should be allowed to start using the Broadcast Resolver.

Works similarly to checkStartActivity() method.


checkIntent() - takes in a resolver, component name, intent type, intent, callerUid, caller Pid, resolved
type and receiving uid and checks if the intent should be blocked or logged. Does this by querying the
resolver for a list of rules and then iterating through them. Logging of intents that should be logged is
done in this method. See Rules.query in Intent Firewall Rule Analysis and IntentFirewallResolver.query

in Intent Firewall Resolver Analysis.


logIntent() - method called by checkIntent() when an intent should be logged. Tries to get information
from the package manager and then pass this information to EventLogTags.writeIfwIntentMatched().

If it catches any exceptions it logs the message "Remote exception while retrieving packages."


getRulesDir() - returns the directory where rules are stored.


readRulesDir() - reads in all files with the extension ".xml" and loads in their rules. New Firewall Intent
Resolvers are created so old rules are destroyed. This method iterates through all the files and calls

the readRules() method on each file.


readRules() - tries to open the given file and parse the XML file into a temporary list. This method only
parses down to the activity/broadcast/service level and confirms that the XML file has no syntax errors.
Once the method knows a rule's type (activity, broadcast or service), it calls the Rule.readFromXML()
method to parse the rule and if there are no errors it then appends the new rule to the appropriate
resolver's temporary rules list. Once all the rules have been parsed, the temporary lists are appended
onto the real filter lists for the resolvers. See Rule.readFromXML() in Intent Firewall Rule Analysis.

Intent Firewall Rule Analysis
XML Parsing

This class' parser is intended to be called on individual rules after the Intent Firewall has already parsed
the rules layer. The following template only shows the portion of the XML file that is passed to the
rule class. See Intent Firewall Analysis for information on the parent layer.
<!-- Activity -->
<activity block="true|false" log="true|false">
<intent-filter />
<component-filter name="[component]" />
</activity>
<!-- Broadcast -->
<broadcast name="" block="true|false" log="true|false">
<intent-filter />
<component-filter name="[component]" />
</broadcast>
<!-- Service -->
<service name="" block="true|false" log="true|false">
<intent-filter />
<component-filter name="[component]" />
</service>

Methods

readFromXML() - looks for a block and/or log attribute in the XML and if found, sets the rule's block
and log variables to those values and then returns itself.
readChild() - looks at the current root of the XML and if it's an intent filter, creates a new Firewall
Intent Filter and calls its FirewallIntentFilter.readFromXml() method. If the root is a component filter,
then it gets the name attribute and adds it to the Component Filter. See
FirewallIntentFilter.readFromXml() in Firewall Intent Filter Analysis.
Firewall Intent Filter Analysis
This class in an extension of the Intent Filter class. More information on Intent Filter is available here:

Intent Filter Analysis.
Methods

FirewallIntentFilter(Rule rule) - Constructor method. Sets the object's rule to the passed in rule.
Intent Filter Analysis
Filter Rules
For an intent-filter to match, three conditions must hold:
1. The action must match
2. The category must match
3. The data type and optionally data scheme must match

Important Considerations

An intent-filter with no category will only match an intent with no category.
Category will accept wild cards.
It is possible for an intent-filter to match without explicitly including a scheme or type node,
despite the third condition. This is particularly true when intent-filter is used for broadcast rules.

XML Format

<path literal="[literal]" prefix="[prefix]" sglob="[sglob]" />
<auth host="[host]" port="[port]" />
<ssp literal="[literal]" prefix="[prefix]" sglob="[sglob]" />
<scheme name="[name]" />
<type name="[name]" />
<cat name="[category]" />
<action name="[action]" />

Intent Firewall Resolver Analysis

The Firewall Intent Resolver is an extension of the Intent Resolver class. More information on Intent
Resolver is available here: Intent Resolver Analysis.

Methods

allowFilterResults() - checks if the rule list contains the intent filter and returns true or false.

Intent Resolver Analysis
Methods

addFilter() - adds a filter to the resolver.


removeFilter() - removes a filter from the resolver.


dump() prints information on a filter.


queryIntent() - Takes an intent and finds all the filters related to that intent. First, the resolver will look
for the MIME type of the intent and if it finds one it'll look up filters for that MIME type. In this check,
the resolver looks for a wildcard ("*/") match before checking for filters with matching MIME types.
Note, "*/*" will always match. Finally, the resolver will try to match the data URI if one is present. The

method does this using four "cuts" and the buildResolveList() method.


buildResolveList() - Starts by taking in an intent and fetching its action, data and package name. Once it
has this information, it first looks at the package name and if the filter's package name doesn't match
the intent's package name, it drops the filter. If it didn't drop the filter it then checks the destination.
Interestingly enough, it only does this to prevent multiple filters from being added for the same target
object. Finally, it calls the filter's match() method and sees if the filter matches the intent. If it does,
this filter is added to a new rule along with a count of how many conditions it matched and is added to
the results list. Finally, the list is sorted based on priority level and stored along with a few lists which

contain sub-portions of the overall final list.


 类似资料: