diff options
author | Svetoslav <svetoslavganov@google.com> | 2015-06-24 18:47:07 -0700 |
---|---|---|
committer | Svetoslav <svetoslavganov@google.com> | 2015-06-25 10:55:11 -0700 |
commit | 7008b51817361443fc6f136c5b187e1d471c94f5 (patch) | |
tree | f32a7204125ad6bd68afeaa160c5faf84a5217f5 | |
parent | d4e9e0e1d6b860c7cc93d06d8b5fdc0004e56b80 (diff) | |
download | frameworks_base-7008b51817361443fc6f136c5b187e1d471c94f5.zip frameworks_base-7008b51817361443fc6f136c5b187e1d471c94f5.tar.gz frameworks_base-7008b51817361443fc6f136c5b187e1d471c94f5.tar.bz2 |
Prevent certain actions of app has revoked permissions
bug:21808294
Change-Id: I7214c1fe47c15fe185423a54a74b58caf8d82daa
-rw-r--r-- | core/java/android/content/Intent.java | 5 | ||||
-rw-r--r-- | core/java/android/provider/MediaStore.java | 14 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityStackSupervisor.java | 95 |
3 files changed, 109 insertions, 5 deletions
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 5190037..83d6cb0 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1020,6 +1020,11 @@ public class Intent implements Parcelable, Cloneable { * <p>Note: this Intent <strong>cannot</strong> be used to call emergency * numbers. Applications can <strong>dial</strong> emergency numbers using * {@link #ACTION_DIAL}, however. + * + * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#MNC MNC} + * and above and declares as using the {@link android.Manifest.permission#CALL_PHONE} + * permission which is not granted, then atempting to use this action will + * result in a {@link java.lang.SecurityException}. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_CALL = "android.intent.action.CALL"; diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 51dbdee..e63fb04 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -283,7 +283,13 @@ public final class MediaStore { * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications. * If you don't set a ClipData, it will be copied there for you when calling * {@link Context#startActivity(Intent)}. - * @see #EXTRA_OUTPUT + * + * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#MNC MNC} and above + * and declares as using the {@link android.Manifest.permission#CAMERA} permission which + * is not granted, then atempting to use this action will result in a {@link + * java.lang.SecurityException}. + * + * @see #EXTRA_OUTPUT */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; @@ -331,6 +337,12 @@ public final class MediaStore { * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications. * If you don't set a ClipData, it will be copied there for you when calling * {@link Context#startActivity(Intent)}. + * + * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#MNC MNC} and above + * and declares as using the {@link android.Manifest.permission#CAMERA} permission which + * is not granted, then atempting to use this action will result in a {@link + * java.lang.SecurityException}. + * * @see #EXTRA_OUTPUT * @see #EXTRA_VIDEO_QUALITY * @see #EXTRA_SIZE_LIMIT diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index f967aef..4ce5c7e 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -25,7 +25,6 @@ import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG; @@ -39,11 +38,13 @@ import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; +import android.Manifest; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.StackInfo; import android.app.ActivityOptions; import android.app.AppGlobals; +import android.app.AppOpsManager; import android.app.IActivityContainer; import android.app.IActivityContainerCallback; import android.app.IActivityManager; @@ -62,6 +63,7 @@ import android.content.Intent; import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; @@ -90,9 +92,11 @@ import android.os.SystemClock; import android.os.TransactionTooLargeException; import android.os.UserHandle; import android.os.WorkSource; +import android.provider.MediaStore; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.service.voice.IVoiceInteractionSession; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; import android.util.Slog; @@ -108,6 +112,7 @@ import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; import com.android.internal.os.TransferPipe; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.util.ArrayUtils; import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.am.ActivityStack.ActivityState; @@ -170,6 +175,25 @@ public final class ActivityStackSupervisor implements DisplayListener { private static final String LOCK_TASK_TAG = "Lock-to-App"; + // Activity actions an app cannot start if it uses a permission which is not granted. + private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION = + new ArrayMap<>(); + static { + ACTION_TO_RUNTIME_PERMISSION.put(MediaStore.ACTION_IMAGE_CAPTURE, + Manifest.permission.CAMERA); + ACTION_TO_RUNTIME_PERMISSION.put(MediaStore.ACTION_VIDEO_CAPTURE, + Manifest.permission.CAMERA); + ACTION_TO_RUNTIME_PERMISSION.put(Intent.ACTION_CALL, + Manifest.permission.CALL_PHONE); + } + + /** Action not restricted for the calling package. */ + private static final int ACTION_RESTRICTION_NONE = 0; + /** Action restricted for the calling package by not granting a used permission. */ + private static final int ACTION_RESTRICTION_PERMISSION = 1; + /** Action restricted for the calling package by not allowing a used permission's app op. */ + private static final int ACTION_RESTRICTION_APPOP = 2; + /** Status Bar Service **/ private IBinder mToken = new Binder(); private IStatusBarService mStatusBarService; @@ -1519,14 +1543,23 @@ public final class ActivityStackSupervisor implements DisplayListener { START_ANY_ACTIVITY, callingPid, callingUid); final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid, callingUid, aInfo.applicationInfo.uid, aInfo.exported); - if (startAnyPerm != PERMISSION_GRANTED && componentPerm != PERMISSION_GRANTED) { + final int actionRestriction = getActionRestrictionForCallingPackage( + intent.getAction(), callingPackage, callingPid, callingUid); + + if (startAnyPerm != PERMISSION_GRANTED && (componentPerm != PERMISSION_GRANTED + || actionRestriction == ACTION_RESTRICTION_PERMISSION)) { if (resultRecord != null) { resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode, Activity.RESULT_CANCELED, null); } String msg; - if (!aInfo.exported) { + if (actionRestriction == ACTION_RESTRICTION_PERMISSION) { + msg = "Permission Denial: starting " + intent.toString() + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ")" + " with revoked permission " + + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction()); + } else if (!aInfo.exported) { msg = "Permission Denial: starting " + intent.toString() + " from " + callerApp + " (pid=" + callingPid + ", uid=" + callingUid + ")" @@ -1541,7 +1574,19 @@ public final class ActivityStackSupervisor implements DisplayListener { throw new SecurityException(msg); } - boolean abort = !mService.mIntentFirewall.checkStartActivity(intent, callingUid, + boolean abort = false; + + if (startAnyPerm != PERMISSION_GRANTED + && actionRestriction == ACTION_RESTRICTION_APPOP) { + String msg = "Permission Denial: starting " + intent.toString() + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ")" + + " requires " + aInfo.permission; + Slog.w(TAG, msg); + abort = true; + } + + abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid, callingPid, resolvedType, aInfo.applicationInfo); if (mService.mController != null) { @@ -1619,6 +1664,48 @@ public final class ActivityStackSupervisor implements DisplayListener { return err; } + private int getActionRestrictionForCallingPackage(String action, + String callingPackage, int callingPid, int callingUid) { + if (action == null) { + return ACTION_RESTRICTION_NONE; + } + + String permission = ACTION_TO_RUNTIME_PERMISSION.get(action); + if (permission == null) { + return ACTION_RESTRICTION_NONE; + } + + final PackageInfo packageInfo; + try { + packageInfo = mService.mContext.getPackageManager() + .getPackageInfo(callingPackage, PackageManager.GET_PERMISSIONS); + } catch (PackageManager.NameNotFoundException e) { + Slog.i(TAG, "Cannot find package info for " + callingPackage); + return ACTION_RESTRICTION_NONE; + } + + if (!ArrayUtils.contains(packageInfo.requestedPermissions, permission)) { + return ACTION_RESTRICTION_NONE; + } + + if (mService.checkPermission(permission, callingPid, callingUid) == + PackageManager.PERMISSION_DENIED) { + return ACTION_RESTRICTION_PERMISSION; + } + + final int opCode = AppOpsManager.permissionToOpCode(permission); + if (opCode == AppOpsManager.OP_NONE) { + return ACTION_RESTRICTION_NONE; + } + + if (mService.mAppOpsService.noteOperation(opCode, callingUid, + callingPackage) != AppOpsManager.MODE_ALLOWED) { + return ACTION_RESTRICTION_APPOP; + } + + return ACTION_RESTRICTION_NONE; + } + ActivityStack computeStackFocus(ActivityRecord r, boolean newTask) { final TaskRecord task = r.task; |