Protecting System Intents in Android

0
16422

Robot-securing-desktop

The last article on ‘Intents in Android’ covered the basics of one of Android’s important inter-application communication mechanisms intents. This article goes deeper into Android’s System Intents, and their security aspects, i.e., how Android prevents applications from misusing system-level intents.

System-level intents are those that the Android System sends a more appropriate term would be broadcasts to the rest of the system and the applications, to notify them about a certain event. These are mostly sent by various services that are part of the core Android framework. These intent broadcasts can be sticky, ordered, etc, depending on the nature of the event and the receivers. On receiving these intents, the registered listeners take necessary action.

Why do system intents need to be protected?

A normal intent is something like ACTION_PHONE_CALL, which an application can send (provided it has the required permission granted during installation) to initiate a phone call; whereas, an easy example for a malicious system intent would be ACTION_SHUTDOWN. No application should be able to shut down your device. Another example would be ACTION_BATTERY_CHANGED, which is broadcast when the phone’s battery properties are changed. The system application that shows the battery capacity receives this intent, extracts the battery properties (one of which is the capacity) and shows it in the notification area. If a malicious application were able to send this intent, it might send erroneous values for the capacity, and as a result, the end user might see strange results in how the battery capacity is reported.

Protecting system-level intents

When an application sends an intent, the Activity Manager, which plays a major role in managing the life-cycle of an application and in Inter-Process Communication (IPC), verifies the permissions of the sender for the particular intent. If an application sends a system-level intent, this permission check will fail and an exception will be thrown.

 

Figure-1
The sample application code shown below has a button captioned Send System Intent; on clicking it, the application tries to send the ACTION_BATTERY_CHANGED intent. However, what happens is that as soon as it is clicked, you will see the Unfortunately the app has stopped dialogue (Figure 1). This is because a security exception happens when your application sends a system intent:

public class IntentTestActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

/** When we click this Button, it tries to send System Intent */
Button intentBtn = (Button)findViewById(R.id.intent);
intentBtn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
Intent myIntent=new Intent();
myIntent.setAction(Intent.ACTION_BATTERY_CHANGED);
getBaseContext().sendBroadcast(myIntent);
}
});
}

A part of the stack trace of the exception message is as follows:

E/AndroidRuntime(18585): FATAL EXCEPTION: main
E/AndroidRuntime(18585): java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.BATTERY_CHANGED from pid=18585, uid=10064

As a result of this, the Activity Manager kills the application. Thus, the Android system makes sure that no application can send a system intent. You can try this with the help of the source code provided at https://www.opensourceforu.com/article_source_code/jan13/intents_android.zip and by using an Android emulator:

W/ActivityManager( 263): Force finishing activity com.example.intenttest/.IntentTestActivity
I/WindowManager( 263): WIN DEATH: Window{2100b9b8 com.example.intenttest/com.example.intenttest.IntentTestActivity paused=false}
I/ActivityManager( 263): Process com.example.intenttest (pid 18585) has died.

Creating system intents
However, if you are at an OEM/ODM, creating your own system-level intent is an easy two-step process. First, add the intent name in frameworks/base/core/java/android/content/intent.java, as shown below:

/**
* Broadcast Action: Have the device reboot. This is only for use by
* system code.
*
*

This is a protected intent that can only be sent
* by the system.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_REBOOT = "android.intent.action.REBOOT";

Next, add the intent string inside the list of protected intents in frameworks/base/core/res/framework/AndroidManifest.xml. A part of this file looks like what follows:

But if you are really adding a system intent that does not exist in Android, you might want to up-stream your change to Google, and walk into the hall of fame!

Android CTS
Google provides an automated test suite that performs thorough regression/performance testing on various Android devices. This framework is called the Compatibility Test Suite (CTS). This exhaustive testing also includes verifying the security of system intents. The code that does this test resides in cts/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java. So, to make Android CTS test your system intent, add it to the list of intents (actually, it’s an array of Strings named BROADCASTS) mentioned in this file.

LEAVE A REPLY

Please enter your comment!
Please enter your name here