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

Commit 95d78534 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #10688644: Java crash in com.android.phone:

java.lang.SecurityException: Operation not allowed

There was a situation I wasn't taking into account -- components
declared by the system has a special ability to run in the processes
of other uids.  This means that if that code loaded into another
process tries to do anything needing an app op verification, it will
fail, because it will say it is calling as the system package name but
it is not actually coming from the system uid.

To fix this, we add a new Context.getOpPackageName() to go along-side
getBasePackageName().  This is a special call for use by all app ops
verification, which will be initialized with either the base package
name, the actual package name, or now the default package name of the
process if we are creating a context for system code being loaded into
a non-system process.

I had to update all of the code doing app ops checks to switch to this
method to get the calling package name.

Also improve the security exception throw to have a more descriptive
error message.

Change-Id: Ic04f77b3938585b02fccabbc12d2f0dc62b9ef25
parent ec7a6ea8
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -575,6 +575,10 @@ public class AppOpsManager {
        }
    }

    private String buildSecurityExceptionMsg(int op, int uid, String packageName) {
        return packageName + " from uid " + uid + " not allowed to perform " + sOpNames[op];
    }

    /**
     * Do a quick check for whether an application might be able to perform an operation.
     * This is <em>not</em> a security check; you must use {@link #noteOp(int, int, String)}
@@ -595,7 +599,7 @@ public class AppOpsManager {
        try {
            int mode = mService.checkOperation(op, uid, packageName);
            if (mode == MODE_ERRORED) {
                throw new SecurityException("Operation not allowed");
                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
            }
            return mode;
        } catch (RemoteException e) {
@@ -650,7 +654,7 @@ public class AppOpsManager {
        try {
            int mode = mService.noteOperation(op, uid, packageName);
            if (mode == MODE_ERRORED) {
                throw new SecurityException("Operation not allowed");
                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
            }
            return mode;
        } catch (RemoteException e) {
@@ -672,7 +676,7 @@ public class AppOpsManager {

    /** @hide */
    public int noteOp(int op) {
        return noteOp(op, Process.myUid(), mContext.getBasePackageName());
        return noteOp(op, Process.myUid(), mContext.getOpPackageName());
    }

    /** @hide */
@@ -710,7 +714,7 @@ public class AppOpsManager {
        try {
            int mode = mService.startOperation(getToken(mService), op, uid, packageName);
            if (mode == MODE_ERRORED) {
                throw new SecurityException("Operation not allowed");
                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
            }
            return mode;
        } catch (RemoteException e) {
@@ -732,7 +736,7 @@ public class AppOpsManager {

    /** @hide */
    public int startOp(int op) {
        return startOp(op, Process.myUid(), mContext.getBasePackageName());
        return startOp(op, Process.myUid(), mContext.getOpPackageName());
    }

    /**
@@ -749,6 +753,6 @@ public class AppOpsManager {
    }

    public void finishOp(int op) {
        finishOp(op, Process.myUid(), mContext.getBasePackageName());
        finishOp(op, Process.myUid(), mContext.getOpPackageName());
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -1275,7 +1275,7 @@ final class ApplicationPackageManager extends PackageManager {
                                             int newState, int flags) {
        try {
            mPM.setApplicationEnabledSetting(packageName, newState, flags,
                    mContext.getUserId(), mContext.getBasePackageName());
                    mContext.getUserId(), mContext.getOpPackageName());
        } catch (RemoteException e) {
            // Should never happen!
        }
+24 −1
Original line number Diff line number Diff line
@@ -183,6 +183,7 @@ class ContextImpl extends Context {

    /*package*/ LoadedApk mPackageInfo;
    private String mBasePackageName;
    private String mOpPackageName;
    private Resources mResources;
    /*package*/ ActivityThread mMainThread;
    private Context mOuterContext;
@@ -679,6 +680,12 @@ class ContextImpl extends Context {
        return mBasePackageName != null ? mBasePackageName : getPackageName();
    }

    /** @hide */
    @Override
    public String getOpPackageName() {
        return mOpPackageName != null ? mOpPackageName : getBasePackageName();
    }

    @Override
    public ApplicationInfo getApplicationInfo() {
        if (mPackageInfo != null) {
@@ -1961,6 +1968,7 @@ class ContextImpl extends Context {
    public ContextImpl(ContextImpl context) {
        mPackageInfo = context.mPackageInfo;
        mBasePackageName = context.mBasePackageName;
        mOpPackageName = context.mOpPackageName;
        mResources = context.mResources;
        mMainThread = context.mMainThread;
        mContentResolver = context.mContentResolver;
@@ -1977,7 +1985,21 @@ class ContextImpl extends Context {
    final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread,
            Resources container, String basePackageName, UserHandle user) {
        mPackageInfo = packageInfo;
        mBasePackageName = basePackageName != null ? basePackageName : packageInfo.mPackageName;
        if (basePackageName != null) {
            mBasePackageName = mOpPackageName = basePackageName;
        } else {
            mBasePackageName = packageInfo.mPackageName;
            ApplicationInfo ainfo = packageInfo.getApplicationInfo();
            if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) {
                // Special case: system components allow themselves to be loaded in to other
                // processes.  For purposes of app ops, we must then consider the context as
                // belonging to the package of this process, not the system itself, otherwise
                // the package+uid verifications in app ops will fail.
                mOpPackageName = ActivityThread.currentPackageName();
            } else {
                mOpPackageName = mBasePackageName;
            }
        }
        mResources = mPackageInfo.getResources(mainThread);
        mResourcesManager = ResourcesManager.getInstance();

@@ -2011,6 +2033,7 @@ class ContextImpl extends Context {
    final void init(Resources resources, ActivityThread mainThread, UserHandle user) {
        mPackageInfo = null;
        mBasePackageName = null;
        mOpPackageName = null;
        mResources = resources;
        mMainThread = mainThread;
        mContentResolver = new ApplicationContentResolver(this, mainThread, user);
+2 −2
Original line number Diff line number Diff line
@@ -133,7 +133,7 @@ public class NotificationManager
        }
        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
        try {
            service.enqueueNotificationWithTag(pkg, mContext.getBasePackageName(), tag, id,
            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                    notification, idOut, UserHandle.myUserId());
            if (id != idOut[0]) {
                Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
@@ -158,7 +158,7 @@ public class NotificationManager
        }
        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
        try {
            service.enqueueNotificationWithTag(pkg, mContext.getBasePackageName(), tag, id,
            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                    notification, idOut, user.getIdentifier());
            if (id != idOut[0]) {
                Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
+6 −6
Original line number Diff line number Diff line
@@ -122,7 +122,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
            if (clip != null) {
                clip.prepareToLeaveProcess();
            }
            getService().setPrimaryClip(clip, mContext.getBasePackageName());
            getService().setPrimaryClip(clip, mContext.getOpPackageName());
        } catch (RemoteException e) {
        }
    }
@@ -132,7 +132,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
     */
    public ClipData getPrimaryClip() {
        try {
            return getService().getPrimaryClip(mContext.getBasePackageName());
            return getService().getPrimaryClip(mContext.getOpPackageName());
        } catch (RemoteException e) {
            return null;
        }
@@ -144,7 +144,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
     */
    public ClipDescription getPrimaryClipDescription() {
        try {
            return getService().getPrimaryClipDescription(mContext.getBasePackageName());
            return getService().getPrimaryClipDescription(mContext.getOpPackageName());
        } catch (RemoteException e) {
            return null;
        }
@@ -155,7 +155,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
     */
    public boolean hasPrimaryClip() {
        try {
            return getService().hasPrimaryClip(mContext.getBasePackageName());
            return getService().hasPrimaryClip(mContext.getOpPackageName());
        } catch (RemoteException e) {
            return false;
        }
@@ -166,7 +166,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
            if (mPrimaryClipChangedListeners.size() == 0) {
                try {
                    getService().addPrimaryClipChangedListener(
                            mPrimaryClipChangedServiceListener, mContext.getBasePackageName());
                            mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
                } catch (RemoteException e) {
                }
            }
@@ -213,7 +213,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
     */
    public boolean hasText() {
        try {
            return getService().hasClipboardText(mContext.getBasePackageName());
            return getService().hasClipboardText(mContext.getOpPackageName());
        } catch (RemoteException e) {
            return false;
        }
Loading