Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a01c7ff authored by Svetoslav's avatar Svetoslav Committed by Android Git Automerger
Browse files

am 263b6e69: Merge "Prevent certain actions of app has revoked permissions" into mnc-dev

* commit '263b6e69':
  Prevent certain actions of app has revoked permissions
parents cc45eeff 263b6e69
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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";
+13 −1
Original line number Diff line number Diff line
@@ -283,6 +283,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
     */
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -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
+91 −4
Original line number Diff line number Diff line
@@ -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;