From 854060af30f928c0a65591e9c8314ae17056e6b8 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 9 Jul 2009 18:14:31 -0700 Subject: [PATCH] Fix bug #1873249i: Apps can DoS/brick device This is the problem where various things are listening for broadcasts (such as battery status, PIN/PUK/Network) that an application can send to cause harm to the system. Solving this is tricky because many of these broadcasts are sticky, and I have never figured out how to do permissions with sticky broadcasts in a sane way. So instead, I am going to punt on the general problem and just brute force it: There is new a way for system components to declare specific broadcast actions to be protected, which means that only the system and the phone can send them. This is good enough for now. None of it is exposed in the public API so we can make something a little less stupid in the future if we ever need to. --- core/java/android/content/Intent.java | 83 ++++++++++++++++++- .../android/content/pm/IPackageManager.aidl | 2 + .../android/content/pm/PackageParser.java | 64 +++++++++----- core/java/android/os/Process.java | 6 ++ core/java/android/provider/Telephony.java | 3 + core/res/AndroidManifest.xml | 33 ++++++++ core/res/res/values/attrs_manifest.xml | 9 +- .../android/server/PackageManagerService.java | 18 +++- .../server/am/ActivityManagerService.java | 23 +++++ .../internal/telephony/TelephonyIntents.java | 33 ++++++++ 10 files changed, 247 insertions(+), 27 deletions(-) diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 263f9279e69ad..76156147b0d5a 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1112,11 +1112,17 @@ public class Intent implements Parcelable { /** * Broadcast Action: Sent after the screen turns off. + * + *

This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF"; /** * Broadcast Action: Sent after the screen turns on. + * + *

This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON"; @@ -1124,6 +1130,9 @@ public class Intent implements Parcelable { /** * Broadcast Action: Sent when the user is present after device wakes up (e.g when the * keyguard is gone). + * + *

This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_USER_PRESENT= "android.intent.action.USER_PRESENT"; @@ -1134,6 +1143,9 @@ public class Intent implements Parcelable { * in manifests, only by exlicitly registering for it with * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) * Context.registerReceiver()}. + * + *

This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_TIME_TICK = "android.intent.action.TIME_TICK"; @@ -1152,6 +1164,9 @@ public class Intent implements Parcelable { *

+ * + *

This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED"; @@ -1177,6 +1192,9 @@ public class Intent implements Parcelable { * such as installing alarms. You must hold the * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission * in order to receive this broadcast. + * + *

This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; @@ -1184,12 +1202,18 @@ public class Intent implements Parcelable { * Broadcast Action: This is broadcast when a user action should request a * temporary system dialog to dismiss. Some examples of temporary system * dialogs are the notification window-shade and the recent tasks dialog. + * + *

This is a protected intent that can only be sent + * by the system. */ public static final String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS"; /** * Broadcast Action: Trigger the download and eventual installation * of a package. *

Input: {@link #getData} is the URI of the package file to download. + * + *

This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL"; @@ -1203,6 +1227,9 @@ public class Intent implements Parcelable { *

  • {@link #EXTRA_REPLACING} is set to true if this is following * an {@link #ACTION_PACKAGE_REMOVED} broadcast for the same package. * + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED"; @@ -1214,6 +1241,9 @@ public class Intent implements Parcelable { *

    + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED"; @@ -1229,6 +1259,9 @@ public class Intent implements Parcelable { *

  • {@link #EXTRA_REPLACING} is set to true if this will be followed * by an {@link #ACTION_PACKAGE_ADDED} broadcast for the same package. * + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED"; @@ -1238,6 +1271,9 @@ public class Intent implements Parcelable { *

    + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED"; @@ -1251,6 +1287,9 @@ public class Intent implements Parcelable { *

    + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED"; @@ -1263,12 +1302,18 @@ public class Intent implements Parcelable { *

    + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED"; /** * Broadcast Action: A user ID has been removed from the system. The user * ID number is stored in the extra data under {@link #EXTRA_UID}. + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED"; @@ -1287,6 +1332,9 @@ public class Intent implements Parcelable { * application to make sure it sees the new changes. Some system code that * can not be restarted will need to watch for this action and handle it * appropriately. + * + *

    This is a protected intent that can only be sent + * by the system. * * @see android.content.res.Configuration */ @@ -1298,15 +1346,21 @@ public class Intent implements Parcelable { * *

    * You can not receive this through components declared - * in manifests, only by exlicitly registering for it with + * in manifests, only by explicitly registering for it with * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) * Context.registerReceiver()}. + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED"; /** * Broadcast Action: Indicates low battery condition on the device. * This broadcast corresponds to the "Low battery warning" system dialog. + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW"; @@ -1314,6 +1368,9 @@ public class Intent implements Parcelable { * Broadcast Action: Indicates the battery is now okay after being low. * This will be sent after {@link #ACTION_BATTERY_LOW} once the battery has * gone back up to an okay state. + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY"; @@ -1323,6 +1380,9 @@ public class Intent implements Parcelable { * Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to * stay active to receive this notification. This action can be used to implement actions * that wait until power is available to trigger. + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED"; @@ -1332,6 +1392,9 @@ public class Intent implements Parcelable { * Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to * stay active to receive this notification. This action can be used to implement actions * that wait until power is available to trigger. + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED"; @@ -1341,16 +1404,25 @@ public class Intent implements Parcelable { * off, not sleeping). Once the broadcast is complete, the final shutdown * will proceed and all unsaved data lost. Apps will not normally need * to handle this, since the forground activity will be paused as well. + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN"; /** * Broadcast Action: Indicates low memory condition on the device + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW"; /** * Broadcast Action: Indicates low memory condition on the device no longer exists + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK"; @@ -1515,6 +1587,9 @@ public class Intent implements Parcelable { * then cell radio and possibly other radios such as bluetooth or WiFi may have also been * turned off

  • * + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE"; @@ -1593,6 +1668,9 @@ public class Intent implements Parcelable { *

    You must hold the * {@link android.Manifest.permission#PROCESS_OUTGOING_CALLS} * permission to receive this Intent.

    + * + *

    This is a protected intent that can only be sent + * by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_NEW_OUTGOING_CALL = @@ -1601,6 +1679,9 @@ public class Intent implements Parcelable { /** * 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 = diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index bf2a8959c7f4c..e587ca7597601 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -71,6 +71,8 @@ interface IPackageManager { void removePermission(String name); + boolean isProtectedBroadcast(String actionName); + int checkSignatures(String pkg1, String pkg2); String[] getPackagesForUid(int uid); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 0e2deed4d5e7e..cebb696867b05 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -720,7 +720,7 @@ public class PackageParser { sa.recycle(); if (name != null && !pkg.requestedPermissions.contains(name)) { - pkg.requestedPermissions.add(name); + pkg.requestedPermissions.add(name.intern()); } XmlUtils.skipCurrentTag(parser); @@ -851,21 +851,6 @@ public class PackageParser { XmlUtils.skipCurrentTag(parser); - } else if (tagName.equals("instrumentation")) { - if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) { - return null; - } - } else if (tagName.equals("eat-comment")) { - // Just skip this tag - XmlUtils.skipCurrentTag(parser); - continue; - } else if (RIGID_PARSER) { - outError[0] = "Bad element under : " - + parser.getName(); - mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; - return null; - - } else if (tagName.equals("supports-density")) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestSupportsDensity); @@ -900,6 +885,43 @@ public class PackageParser { sa.recycle(); XmlUtils.skipCurrentTag(parser); + + } else if (tagName.equals("protected-broadcast")) { + sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.AndroidManifestProtectedBroadcast); + + String name = sa.getNonResourceString( + com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name); + + sa.recycle(); + + if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { + if (pkg.protectedBroadcasts == null) { + pkg.protectedBroadcasts = new ArrayList(); + } + if (!pkg.protectedBroadcasts.contains(name)) { + pkg.protectedBroadcasts.add(name.intern()); + } + } + + XmlUtils.skipCurrentTag(parser); + + } else if (tagName.equals("instrumentation")) { + if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) { + return null; + } + + } else if (tagName.equals("eat-comment")) { + // Just skip this tag + XmlUtils.skipCurrentTag(parser); + continue; + + } else if (RIGID_PARSER) { + outError[0] = "Bad element under : " + + parser.getName(); + mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; + return null; + } else { Log.w(TAG, "Bad element under : " + parser.getName()); @@ -1429,7 +1451,7 @@ public class PackageParser { sa.recycle(); if (lname != null && !owner.usesLibraries.contains(lname)) { - owner.usesLibraries.add(lname); + owner.usesLibraries.add(lname.intern()); } XmlUtils.skipCurrentTag(parser); @@ -2210,8 +2232,8 @@ public class PackageParser { return null; } - boolean success = true; - + name = name.intern(); + TypedValue v = sa.peekValue( com.android.internal.R.styleable.AndroidManifestMetaData_resource); if (v != null && v.resourceId != 0) { @@ -2224,7 +2246,7 @@ public class PackageParser { if (v != null) { if (v.type == TypedValue.TYPE_STRING) { CharSequence cs = v.coerceToString(); - data.putString(name, cs != null ? cs.toString() : null); + data.putString(name, cs != null ? cs.toString().intern() : null); } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { data.putBoolean(name, v.data != 0); } else if (v.type >= TypedValue.TYPE_FIRST_INT @@ -2405,6 +2427,8 @@ public class PackageParser { public final ArrayList requestedPermissions = new ArrayList(); + public ArrayList protectedBroadcasts; + public final ArrayList usesLibraries = new ArrayList(); public String[] usesLibraryFiles = null; diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 51e6c1e198015..480519386e488 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -67,6 +67,12 @@ public class Process { */ public static final int PHONE_UID = 1001; + /** + * Defines the UID/GID for the user shell. + * @hide + */ + public static final int SHELL_UID = 2000; + /** * Defines the UID/GID for the WIFI supplicant process. * @hide diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 4078fa6d5a734..0cfa5068017b3 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -1620,6 +1620,9 @@ public final class Telephony { * * It is recommended to display plmn before / above spn if * both are displayed. + * + *

    Note this is a protected intent that can only be sent + * by the system. */ public static final String SPN_STRINGS_UPDATED_ACTION = "android.provider.Telephony.SPN_STRINGS_UPDATED"; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 23967f4f8dfcb..e964cda8ed4e8 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -21,6 +21,39 @@ package="android" android:sharedUserId="android.uid.system" android:sharedUserLabel="@string/android_system_label"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 12a76ba520266..9dc483c468857 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -887,11 +887,12 @@ - - + +