diff options
17 files changed, 419 insertions, 119 deletions
diff --git a/api/current.txt b/api/current.txt index df668114c0cd..33043179929d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3855,6 +3855,8 @@ package android.app { method public void finishOp(java.lang.String, int, java.lang.String); method public int noteOp(java.lang.String, int, java.lang.String); method public int noteOpNoThrow(java.lang.String, int, java.lang.String); + method public int noteProxyOp(java.lang.String, java.lang.String); + method public int noteProxyOpNoThrow(java.lang.String, java.lang.String); method public static java.lang.String permissionToOp(java.lang.String); method public int startOp(java.lang.String, int, java.lang.String); method public int startOpNoThrow(java.lang.String, int, java.lang.String); diff --git a/api/system-current.txt b/api/system-current.txt index f6301e80fb76..e3f003c68554 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3964,6 +3964,8 @@ package android.app { method public void finishOp(java.lang.String, int, java.lang.String); method public int noteOp(java.lang.String, int, java.lang.String); method public int noteOpNoThrow(java.lang.String, int, java.lang.String); + method public int noteProxyOp(java.lang.String, java.lang.String); + method public int noteProxyOpNoThrow(java.lang.String, java.lang.String); method public static java.lang.String permissionToOp(java.lang.String); method public int startOp(java.lang.String, int, java.lang.String); method public int startOpNoThrow(java.lang.String, int, java.lang.String); diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 13fda59240a6..ca6c6ca3da2c 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -767,7 +767,7 @@ public class Am extends BaseCommand { return; } System.out.println("Starting service: " + intent); - ComponentName cn = mAm.startService(null, intent, intent.getType(), mUserId); + ComponentName cn = mAm.startService(null, intent, intent.getType(), null, mUserId); if (cn == null) { System.err.println("Error: Not found; no service started."); } else if (cn.getPackageName().equals("!")) { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 2bb4e760f7d4..cc93ac906d06 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -921,8 +921,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IApplicationThread app = ApplicationThreadNative.asInterface(b); Intent service = Intent.CREATOR.createFromParcel(data); String resolvedType = data.readString(); + String callingPackage = data.readString(); int userId = data.readInt(); - ComponentName cn = startService(app, service, resolvedType, userId); + ComponentName cn = startService(app, service, resolvedType, callingPackage, userId); reply.writeNoException(); ComponentName.writeToParcel(cn, reply); return true; @@ -976,9 +977,11 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String resolvedType = data.readString(); b = data.readStrongBinder(); int fl = data.readInt(); + String callingPackage = data.readString(); int userId = data.readInt(); IServiceConnection conn = IServiceConnection.Stub.asInterface(b); - int res = bindService(app, token, service, resolvedType, conn, fl, userId); + int res = bindService(app, token, service, resolvedType, conn, fl, + callingPackage, userId); reply.writeNoException(); reply.writeInt(res); return true; @@ -1568,7 +1571,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); Intent service = Intent.CREATOR.createFromParcel(data); String resolvedType = data.readString(); - IBinder binder = peekService(service, resolvedType); + String callingPackage = data.readString(); + IBinder binder = peekService(service, resolvedType, callingPackage); reply.writeNoException(); reply.writeStrongBinder(binder); return true; @@ -3638,7 +3642,7 @@ class ActivityManagerProxy implements IActivityManager } public ComponentName startService(IApplicationThread caller, Intent service, - String resolvedType, int userId) throws RemoteException + String resolvedType, String callingPackage, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -3646,6 +3650,7 @@ class ActivityManagerProxy implements IActivityManager data.writeStrongBinder(caller != null ? caller.asBinder() : null); service.writeToParcel(data, 0); data.writeString(resolvedType); + data.writeString(callingPackage); data.writeInt(userId); mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0); reply.readException(); @@ -3708,7 +3713,7 @@ class ActivityManagerProxy implements IActivityManager } public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, - int flags, int userId) throws RemoteException { + int flags, String callingPackage, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -3718,6 +3723,7 @@ class ActivityManagerProxy implements IActivityManager data.writeString(resolvedType); data.writeStrongBinder(connection.asBinder()); data.writeInt(flags); + data.writeString(callingPackage); data.writeInt(userId); mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0); reply.readException(); @@ -3783,12 +3789,14 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } - public IBinder peekService(Intent service, String resolvedType) throws RemoteException { + public IBinder peekService(Intent service, String resolvedType, String callingPackage) + throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); service.writeToParcel(data, 0); data.writeString(resolvedType); + data.writeString(callingPackage); mRemote.transact(PEEK_SERVICE_TRANSACTION, data, reply, 0); reply.readException(); IBinder binder = reply.readStrongBinder(); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 9faadd34da11..bf3bfaea11ff 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1082,13 +1082,18 @@ public class AppOpsManager { private final long mTime; private final long mRejectTime; private final int mDuration; + private final int mProxyUid; + private final String mProxyPackageName; - public OpEntry(int op, int mode, long time, long rejectTime, int duration) { + public OpEntry(int op, int mode, long time, long rejectTime, int duration, + int proxyUid, String proxyPackage) { mOp = op; mMode = mode; mTime = time; mRejectTime = rejectTime; mDuration = duration; + mProxyUid = proxyUid; + mProxyPackageName = proxyPackage; } public int getOp() { @@ -1115,6 +1120,14 @@ public class AppOpsManager { return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration; } + public int getProxyUid() { + return mProxyUid; + } + + public String getProxyPackageName() { + return mProxyPackageName; + } + @Override public int describeContents() { return 0; @@ -1127,6 +1140,8 @@ public class AppOpsManager { dest.writeLong(mTime); dest.writeLong(mRejectTime); dest.writeInt(mDuration); + dest.writeInt(mProxyUid); + dest.writeString(mProxyPackageName); } OpEntry(Parcel source) { @@ -1135,6 +1150,8 @@ public class AppOpsManager { mTime = source.readLong(); mRejectTime = source.readLong(); mDuration = source.readInt(); + mProxyUid = source.readInt(); + mProxyPackageName = source.readString(); } public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() { @@ -1379,6 +1396,33 @@ public class AppOpsManager { } /** + * Make note of an application performing an operation on behalf of another + * application when handling an IPC. Note that you must pass the package name + * of the application that is being proxied while its UID will be inferred from + * the IPC state; this function will verify that the calling uid and proxied + * package name match, and if not, return {@link #MODE_IGNORED}. If this call + * succeeds, the last execution time of the operation for the proxied app and + * your app will be updated to the current time. + * @param op The operation to note. One of the OPSTR_* constants. + * @param proxiedPackageName The name of the application calling into the proxy application. + * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or + * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without + * causing the app to crash). + * @throws SecurityException If the app has been configured to crash on this op. + */ + public int noteProxyOp(String op, String proxiedPackageName) { + return noteProxyOp(strOpToOp(op), proxiedPackageName); + } + + /** + * Like {@link #noteProxyOp(String, String)} but instead + * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}. + */ + public int noteProxyOpNoThrow(String op, String proxiedPackageName) { + return noteProxyOpNoThrow(strOpToOp(op), proxiedPackageName); + } + + /** * Report that an application has started executing a long-running operation. Note that you * must pass in both the uid and name of the application to be checked; this function will * verify that these two match, and if not, return {@link #MODE_IGNORED}. If this call @@ -1455,7 +1499,7 @@ public class AppOpsManager { return mService.checkOperation(op, uid, packageName); } catch (RemoteException e) { } - return MODE_IGNORED; + return MODE_ERRORED; } /** @@ -1501,7 +1545,7 @@ public class AppOpsManager { return mService.checkAudioOperation(op, stream, uid, packageName); } catch (RemoteException e) { } - return MODE_IGNORED; + return MODE_ERRORED; } /** @@ -1532,6 +1576,49 @@ public class AppOpsManager { } /** + * Make note of an application performing an operation on behalf of another + * application when handling an IPC. Note that you must pass the package name + * of the application that is being proxied while its UID will be inferred from + * the IPC state; this function will verify that the calling uid and proxied + * package name match, and if not, return {@link #MODE_IGNORED}. If this call + * succeeds, the last execution time of the operation for the proxied app and + * your app will be updated to the current time. + * @param op The operation to note. One of the OPSTR_* constants. + * @param proxiedPackageName The name of the application calling into the proxy application. + * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or + * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without + * causing the app to crash). + * @throws SecurityException If the proxy or proxied app has been configured to + * crash on this op. + * + * @hide + */ + public int noteProxyOp(int op, String proxiedPackageName) { + int mode = noteProxyOpNoThrow(op, proxiedPackageName); + if (mode == MODE_ERRORED) { + throw new SecurityException("Proxy package " + mContext.getOpPackageName() + + " from uid " + Process.myUid() + " or calling package " + + proxiedPackageName + " from uid " + Binder.getCallingUid() + + " not allowed to perform " + sOpNames[op]); + } + return mode; + } + + /** + * Like {@link #noteProxyOp(int, String)} but instead + * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}. + * @hide + */ + public int noteProxyOpNoThrow(int op, String proxiedPackageName) { + try { + return mService.noteProxyOperation(op, mContext.getOpPackageName(), + Binder.getCallingUid(), proxiedPackageName); + } catch (RemoteException e) { + } + return MODE_ERRORED; + } + + /** * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. * @hide @@ -1541,7 +1628,7 @@ public class AppOpsManager { return mService.noteOperation(op, uid, packageName); } catch (RemoteException e) { } - return MODE_IGNORED; + return MODE_ERRORED; } /** @hide */ @@ -1603,7 +1690,7 @@ public class AppOpsManager { return mService.startOperation(getToken(mService), op, uid, packageName); } catch (RemoteException e) { } - return MODE_IGNORED; + return MODE_ERRORED; } /** @hide */ diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 0420fb66aff8..6639486e26bb 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1202,8 +1202,8 @@ class ContextImpl extends Context { validateServiceIntent(service); service.prepareToLeaveProcess(); ComponentName cn = ActivityManagerNative.getDefault().startService( - mMainThread.getApplicationThread(), service, - service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier()); + mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( + getContentResolver()), getOpPackageName(), user.getIdentifier()); if (cn != null) { if (cn.getPackageName().equals("!")) { throw new SecurityException( @@ -1279,9 +1279,9 @@ class ContextImpl extends Context { } service.prepareToLeaveProcess(); int res = ActivityManagerNative.getDefault().bindService( - mMainThread.getApplicationThread(), getActivityToken(), - service, service.resolveTypeIfNeeded(getContentResolver()), - sd, flags, user.getIdentifier()); + mMainThread.getApplicationThread(), getActivityToken(), service, + service.resolveTypeIfNeeded(getContentResolver()), + sd, flags, getOpPackageName(), user.getIdentifier()); if (res < 0) { throw new SecurityException( "Not allowed to bind to service " + service); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 1423e4bae4de..acce81c9fe5d 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -160,16 +160,16 @@ public interface IActivityManager extends IInterface { public PendingIntent getRunningServiceControlPanel(ComponentName service) throws RemoteException; public ComponentName startService(IApplicationThread caller, Intent service, - String resolvedType, int userId) throws RemoteException; + String resolvedType, String callingPackage, int userId) throws RemoteException; public int stopService(IApplicationThread caller, Intent service, String resolvedType, int userId) throws RemoteException; public boolean stopServiceToken(ComponentName className, IBinder token, int startId) throws RemoteException; public void setServiceForeground(ComponentName className, IBinder token, int id, Notification notification, boolean keepNotification) throws RemoteException; - public int bindService(IApplicationThread caller, IBinder token, - Intent service, String resolvedType, - IServiceConnection connection, int flags, int userId) throws RemoteException; + public int bindService(IApplicationThread caller, IBinder token, Intent service, + String resolvedType, IServiceConnection connection, int flags, + String callingPackage, int userId) throws RemoteException; public boolean unbindService(IServiceConnection connection) throws RemoteException; public void publishService(IBinder token, Intent intent, IBinder service) throws RemoteException; @@ -178,7 +178,8 @@ public interface IActivityManager extends IInterface { /* oneway */ public void serviceDoneExecuting(IBinder token, int type, int startId, int res) throws RemoteException; - public IBinder peekService(Intent service, String resolvedType) throws RemoteException; + public IBinder peekService(Intent service, String resolvedType, String callingPackage) + throws RemoteException; public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode) throws RemoteException; diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index af74e7314f6e..2260d7e07e03 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -524,7 +524,7 @@ public abstract class BroadcastReceiver { try { service.prepareToLeaveProcess(); binder = am.peekService(service, service.resolveTypeIfNeeded( - myContext.getContentResolver())); + myContext.getContentResolver()), myContext.getOpPackageName()); } catch (RemoteException e) { } return binder; diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index d4c443779d71..3cc76841bd70 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -475,18 +475,38 @@ public abstract class ContentProvider implements ComponentCallbacks2 { private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken) throws SecurityException { enforceReadPermissionInner(uri, callerToken); + + final int permOp = AppOpsManager.permissionToOpCode(mReadPermission); + if (permOp != AppOpsManager.OP_NONE) { + final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg); + if (mode != AppOpsManager.MODE_ALLOWED) { + return mode; + } + } + if (mReadOp != AppOpsManager.OP_NONE) { - return mAppOpsManager.noteOp(mReadOp, Binder.getCallingUid(), callingPkg); + return mAppOpsManager.noteProxyOp(mReadOp, callingPkg); } + return AppOpsManager.MODE_ALLOWED; } private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken) throws SecurityException { enforceWritePermissionInner(uri, callerToken); + + final int permOp = AppOpsManager.permissionToOpCode(mWritePermission); + if (permOp != AppOpsManager.OP_NONE) { + final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg); + if (mode != AppOpsManager.MODE_ALLOWED) { + return mode; + } + } + if (mWriteOp != AppOpsManager.OP_NONE) { - return mAppOpsManager.noteOp(mWriteOp, Binder.getCallingUid(), callingPkg); + return mAppOpsManager.noteProxyOp(mWriteOp, callingPkg); } + return AppOpsManager.MODE_ALLOWED; } } diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index 86c1b2f65873..201a124aab3b 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -25,6 +25,8 @@ interface IAppOpsService { // be kept in sync with frameworks/native/include/binder/IAppOpsService.h int checkOperation(int code, int uid, String packageName); int noteOperation(int code, int uid, String packageName); + int noteProxyOperation(int code, String proxyPackageName, + int callingUid, String callingPackageName); int startOperation(IBinder token, int code, int uid, String packageName); void finishOperation(IBinder token, int code, int uid, String packageName); void startWatchingMode(int op, String packageName, IAppOpsCallback callback); diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 79c66b9346ef..f0fc399613e6 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -116,6 +116,8 @@ public class AppOpsService extends IAppOpsService.Stub { public final static class Op { public final int uid; public final String packageName; + public int proxyUid = -1; + public String proxyPackageName; public final int op; public int mode; public int duration; @@ -289,7 +291,8 @@ public class AppOpsService extends IAppOpsService.Stub { for (int j=0; j<pkgOps.size(); j++) { Op curOp = pkgOps.valueAt(j); resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time, - curOp.rejectTime, curOp.duration)); + curOp.rejectTime, curOp.duration, curOp.proxyUid, + curOp.proxyPackageName)); } } else { for (int j=0; j<ops.length; j++) { @@ -299,7 +302,8 @@ public class AppOpsService extends IAppOpsService.Stub { resOps = new ArrayList<AppOpsManager.OpEntry>(); } resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time, - curOp.rejectTime, curOp.duration)); + curOp.rejectTime, curOp.duration, curOp.proxyUid, + curOp.proxyPackageName)); } } } @@ -659,9 +663,28 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override + public int noteProxyOperation(int code, String proxyPackageName, + int proxiedUid, String proxiedPackageName) { + verifyIncomingOp(code); + final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(), + proxyPackageName, -1, null); + if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) { + return proxyMode; + } + return noteOperationUnchecked(code, proxiedUid, proxiedPackageName, + Binder.getCallingUid(), proxyPackageName); + + } + + @Override public int noteOperation(int code, int uid, String packageName) { verifyIncomingUid(uid); verifyIncomingOp(code); + return noteOperationUnchecked(code, uid, packageName, 0, null); + } + + private int noteOperationUnchecked(int code, int uid, String packageName, + int proxyUid, String proxyPackageName) { synchronized (this) { Ops ops = getOpsLocked(uid, packageName, true); if (ops == null) { @@ -690,6 +713,8 @@ public class AppOpsService extends IAppOpsService.Stub { + " package " + packageName); op.time = System.currentTimeMillis(); op.rejectTime = 0; + op.proxyUid = proxyUid; + op.proxyPackageName = proxyPackageName; return AppOpsManager.MODE_ALLOWED; } } @@ -1051,6 +1076,14 @@ public class AppOpsService extends IAppOpsService.Stub { if (dur != null) { op.duration = Integer.parseInt(dur); } + String proxyUid = parser.getAttributeValue(null, "pu"); + if (proxyUid != null) { + op.proxyUid = Integer.parseInt(proxyUid); + } + String proxyPackageName = parser.getAttributeValue(null, "pp"); + if (proxyPackageName != null) { + op.proxyPackageName = proxyPackageName; + } HashMap<String, Ops> pkgOps = mUidOps.get(uid); if (pkgOps == null) { pkgOps = new HashMap<String, Ops>(); @@ -1132,6 +1165,14 @@ public class AppOpsService extends IAppOpsService.Stub { if (dur != 0) { out.attribute(null, "d", Integer.toString(dur)); } + int proxyUid = op.getProxyUid(); + if (proxyUid != -1) { + out.attribute(null, "pu", Integer.toString(proxyUid)); + } + String proxyPackageName = op.getProxyPackageName(); + if (proxyPackageName != null) { + out.attribute(null, "pp", proxyPackageName); + } out.endTag(null, "op"); } out.endTag(null, "uid"); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 333db5d6dd33..899139f7844b 100755 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Set; import android.app.ActivityThread; +import android.app.AppOpsManager; import android.os.Build; import android.os.DeadObjectException; import android.os.Handler; @@ -302,8 +303,8 @@ public final class ActiveServices { return getServiceMap(callingUser).mServicesByName; } - ComponentName startServiceLocked(IApplicationThread caller, Intent service, - String resolvedType, int callingPid, int callingUid, int userId) + ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, + int callingPid, int callingUid, String callingPackage, int userId) throws TransactionTooLargeException { if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service + " type=" + resolvedType + " args=" + service.getExtras()); @@ -324,7 +325,7 @@ public final class ActiveServices { ServiceLookupResult res = - retrieveServiceLocked(service, resolvedType, + retrieveServiceLocked(service, resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg); if (res == null) { return null; @@ -490,7 +491,7 @@ public final class ActiveServices { } // If this service is active, make sure it is stopped. - ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, + ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, null, Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false); if (r != null) { if (r.record != null) { @@ -508,8 +509,8 @@ public final class ActiveServices { return 0; } - IBinder peekServiceLocked(Intent service, String resolvedType) { - ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, + IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) { + ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(), Binder.getCallingUid(), UserHandle.getCallingUserId(), false, false); @@ -694,8 +695,8 @@ public final class ActiveServices { } int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, - String resolvedType, IServiceConnection connection, int flags, int userId) - throws TransactionTooLargeException { + String resolvedType, IServiceConnection connection, int flags, + String callingPackage, int userId) throws TransactionTooLargeException { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service + " type=" + resolvedType + " conn=" + connection.asBinder() + " flags=0x" + Integer.toHexString(flags)); @@ -746,7 +747,7 @@ public final class ActiveServices { final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE; ServiceLookupResult res = - retrieveServiceLocked(service, resolvedType, + retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg); if (res == null) { return 0; @@ -1022,7 +1023,7 @@ public final class ActiveServices { } private ServiceLookupResult retrieveServiceLocked(Intent service, - String resolvedType, int callingPid, int callingUid, int userId, + String resolvedType, String callingPackage, int callingPid, int callingUid, int userId, boolean createIfNeeded, boolean callingFromFg) { ServiceRecord r = null; if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service @@ -1112,7 +1113,18 @@ public final class ActiveServices { + ", uid=" + callingUid + " requires " + r.permission); return new ServiceLookupResult(null, r.permission); + } else if (r.permission != null && callingPackage != null) { + final int opCode = AppOpsManager.permissionToOpCode(r.permission); + if (opCode != AppOpsManager.OP_NONE && mAm.mAppOpsService.noteOperation( + opCode, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: Accessing service " + r.name + + " from pid=" + callingPid + + ", uid=" + callingUid + + " requires appop " + AppOpsManager.opToName(opCode)); + return null; + } } + if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid, resolvedType, r.appInfo)) { return null; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c7fbc7640603..477c26cdd257 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15552,13 +15552,18 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public ComponentName startService(IApplicationThread caller, Intent service, - String resolvedType, int userId) throws TransactionTooLargeException { + String resolvedType, String callingPackage, int userId) + throws TransactionTooLargeException { enforceNotIsolatedCaller("startService"); // Refuse possible leaked file descriptors if (service != null && service.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } + if (callingPackage == null) { + throw new IllegalArgumentException("callingPackage cannot be null"); + } + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "startService: " + service + " type=" + resolvedType); synchronized(this) { @@ -15566,20 +15571,21 @@ public final class ActivityManagerService extends ActivityManagerNative final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); ComponentName res = mServices.startServiceLocked(caller, service, - resolvedType, callingPid, callingUid, userId); + resolvedType, callingPid, callingUid, callingPackage, userId); Binder.restoreCallingIdentity(origId); return res; } } - ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, int userId) + ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, + String callingPackage, int userId) throws TransactionTooLargeException { synchronized(this) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "startServiceInPackage: " + service + " type=" + resolvedType); final long origId = Binder.clearCallingIdentity(); ComponentName res = mServices.startServiceLocked(null, service, - resolvedType, -1, uid, userId); + resolvedType, -1, uid, callingPackage, userId); Binder.restoreCallingIdentity(origId); return res; } @@ -15600,14 +15606,19 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public IBinder peekService(Intent service, String resolvedType) { + public IBinder peekService(Intent service, String resolvedType, String callingPackage) { enforceNotIsolatedCaller("peekService"); // Refuse possible leaked file descriptors if (service != null && service.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } + + if (callingPackage == null) { + throw new IllegalArgumentException("callingPackage cannot be null"); + } + synchronized(this) { - return mServices.peekServiceLocked(service, resolvedType); + return mServices.peekServiceLocked(service, resolvedType, callingPackage); } } @@ -15777,8 +15788,8 @@ public final class ActivityManagerService extends ActivityManagerNative } public int bindService(IApplicationThread caller, IBinder token, Intent service, - String resolvedType, IServiceConnection connection, int flags, int userId) - throws TransactionTooLargeException { + String resolvedType, IServiceConnection connection, int flags, String callingPackage, + int userId) throws TransactionTooLargeException { enforceNotIsolatedCaller("bindService"); // Refuse possible leaked file descriptors @@ -15786,9 +15797,13 @@ public final class ActivityManagerService extends ActivityManagerNative throw new IllegalArgumentException("File descriptors passed in Intent"); } + if (callingPackage == null) { + throw new IllegalArgumentException("callingPackage cannot be null"); + } + synchronized(this) { - return mServices.bindServiceLocked(caller, token, service, resolvedType, - connection, flags, userId); + return mServices.bindServiceLocked(caller, token, service, + resolvedType, connection, flags, callingPackage, userId); } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 4ce5c7ef7fca..c12aff6b626d 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -187,12 +187,12 @@ public final class ActivityStackSupervisor implements DisplayListener { 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; + /** Action restriction: launching the activity is not restricted. */ + private static final int ACTIVITY_RESTRICTION_NONE = 0; + /** Action restriction: launching the activity is restricted by a permission. */ + private static final int ACTIVITY_RESTRICTION_PERMISSION = 1; + /** Action restriction: launching the activity is restricted by an app op. */ + private static final int ACTIVITY_RESTRICTION_APPOP = 2; /** Status Bar Service **/ private IBinder mToken = new Binder(); @@ -1539,51 +1539,61 @@ public final class ActivityStackSupervisor implements DisplayListener { return err; } + boolean abort = false; + final int startAnyPerm = mService.checkPermission( START_ANY_ACTIVITY, callingPid, callingUid); - final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid, - callingUid, aInfo.applicationInfo.uid, aInfo.exported); - 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); + if (startAnyPerm != PERMISSION_GRANTED) { + final int componentRestriction = getComponentRestrictionForCallingPackage( + aInfo, callingPackage, callingPid, callingUid); + final int actionRestriction = getActionRestrictionForCallingPackage( + intent.getAction(), callingPackage, callingPid, callingUid); + + if (componentRestriction == ACTIVITY_RESTRICTION_PERMISSION + || actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) { + if (resultRecord != null) { + resultStack.sendActivityResultLocked(-1, + resultRecord, resultWho, requestCode, + Activity.RESULT_CANCELED, null); + } + String msg; + if (actionRestriction == ACTIVITY_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 + ")" + + " not exported from uid " + aInfo.applicationInfo.uid; + } else { + msg = "Permission Denial: starting " + intent.toString() + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ")" + + " requires " + aInfo.permission; + } + Slog.w(TAG, msg); + throw new SecurityException(msg); } - String msg; - 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() + + if (actionRestriction == ACTIVITY_RESTRICTION_APPOP) { + String message = "Appop Denial: starting " + intent.toString() + " from " + callerApp + " (pid=" + callingPid + ", uid=" + callingUid + ")" - + " not exported from uid " + aInfo.applicationInfo.uid; - } else { - msg = "Permission Denial: starting " + intent.toString() + + " requires " + AppOpsManager.permissionToOp( + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction())); + Slog.w(TAG, message); + abort = true; + } else if (componentRestriction == ACTIVITY_RESTRICTION_APPOP) { + String message = "Appop Denial: starting " + intent.toString() + " from " + callerApp + " (pid=" + callingPid + ", uid=" + callingUid + ")" - + " requires " + aInfo.permission; + + " requires appop " + AppOpsManager.permissionToOp(aInfo.permission); + Slog.w(TAG, message); + abort = true; } - Slog.w(TAG, msg); - throw new SecurityException(msg); - } - - 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, @@ -1664,15 +1674,40 @@ public final class ActivityStackSupervisor implements DisplayListener { return err; } + private int getComponentRestrictionForCallingPackage(ActivityInfo activityInfo, + String callingPackage, int callingPid, int callingUid) { + if (activityInfo.permission == null) { + return ACTIVITY_RESTRICTION_NONE; + } + + if (mService.checkComponentPermission(activityInfo.permission, callingPid, callingUid, + activityInfo.applicationInfo.uid, activityInfo.exported) + == PackageManager.PERMISSION_DENIED) { + return ACTIVITY_RESTRICTION_PERMISSION; + } + + final int opCode = AppOpsManager.permissionToOpCode(activityInfo.permission); + if (opCode == AppOpsManager.OP_NONE) { + return ACTIVITY_RESTRICTION_NONE; + } + + if (mService.mAppOpsService.noteOperation(opCode, callingUid, + callingPackage) != AppOpsManager.MODE_ALLOWED) { + return ACTIVITY_RESTRICTION_APPOP; + } + + return ACTIVITY_RESTRICTION_NONE; + } + private int getActionRestrictionForCallingPackage(String action, String callingPackage, int callingPid, int callingUid) { if (action == null) { - return ACTION_RESTRICTION_NONE; + return ACTIVITY_RESTRICTION_NONE; } String permission = ACTION_TO_RUNTIME_PERMISSION.get(action); if (permission == null) { - return ACTION_RESTRICTION_NONE; + return ACTIVITY_RESTRICTION_NONE; } final PackageInfo packageInfo; @@ -1681,29 +1716,29 @@ public final class ActivityStackSupervisor implements DisplayListener { .getPackageInfo(callingPackage, PackageManager.GET_PERMISSIONS); } catch (PackageManager.NameNotFoundException e) { Slog.i(TAG, "Cannot find package info for " + callingPackage); - return ACTION_RESTRICTION_NONE; + return ACTIVITY_RESTRICTION_NONE; } if (!ArrayUtils.contains(packageInfo.requestedPermissions, permission)) { - return ACTION_RESTRICTION_NONE; + return ACTIVITY_RESTRICTION_NONE; } if (mService.checkPermission(permission, callingPid, callingUid) == PackageManager.PERMISSION_DENIED) { - return ACTION_RESTRICTION_PERMISSION; + return ACTIVITY_RESTRICTION_PERMISSION; } final int opCode = AppOpsManager.permissionToOpCode(permission); if (opCode == AppOpsManager.OP_NONE) { - return ACTION_RESTRICTION_NONE; + return ACTIVITY_RESTRICTION_NONE; } if (mService.mAppOpsService.noteOperation(opCode, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) { - return ACTION_RESTRICTION_APPOP; + return ACTIVITY_RESTRICTION_APPOP; } - return ACTION_RESTRICTION_NONE; + return ACTIVITY_RESTRICTION_NONE; } ActivityStack computeStackFocus(ActivityRecord r, boolean newTask) { diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 23350711a123..30aa4110b643 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -463,7 +463,7 @@ public final class BroadcastQueue { } } - private final void deliverToRegisteredReceiverLocked(BroadcastRecord r, + private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered) { boolean skip = false; if (filter.requiredPermission != null) { @@ -477,9 +477,23 @@ public final class BroadcastQueue { + " requires " + filter.requiredPermission + " due to registered receiver " + filter); skip = true; + } else { + final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission); + if (opCode != AppOpsManager.OP_NONE + && mService.mAppOpsService.noteOperation(opCode, r.callingUid, + r.callerPackage) != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + + r.callingPid + ", uid=" + r.callingUid + ")" + + " requires appop " + AppOpsManager.permissionToOp( + filter.requiredPermission) + + " due to registered receiver " + filter); + skip = true; + } } } - if (!skip && r.requiredPermission != null) { + if (!skip) { int perm = mService.checkComponentPermission(r.requiredPermission, filter.receiverList.pid, filter.receiverList.uid, -1, true); if (perm != PackageManager.PERMISSION_GRANTED) { @@ -493,17 +507,42 @@ public final class BroadcastQueue { + " (uid " + r.callingUid + ")"); skip = true; } - } - if (r.appOp != AppOpsManager.OP_NONE) { - int mode = mService.mAppOpsService.noteOperation(r.appOp, - filter.receiverList.uid, filter.packageName); - if (mode != AppOpsManager.MODE_ALLOWED) { - if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, - "App op " + r.appOp + " not allowed for broadcast to uid " - + filter.receiverList.uid + " pkg " + filter.packageName); - skip = true; + int appOp = AppOpsManager.OP_NONE; + if (r.requiredPermission != null) { + appOp = AppOpsManager.permissionToOpCode(r.requiredPermission); + if (appOp != AppOpsManager.OP_NONE + && mService.mAppOpsService.noteOperation(appOp, + filter.receiverList.uid, filter.packageName) + != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: receiving " + + r.intent.toString() + + " to " + filter.receiverList.app + + " (pid=" + filter.receiverList.pid + + ", uid=" + filter.receiverList.uid + ")" + + " requires appop " + AppOpsManager.permissionToOp( + r.requiredPermission) + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; + } + } + if (!skip && r.appOp != appOp && r.appOp != AppOpsManager.OP_NONE + && mService.mAppOpsService.noteOperation(r.appOp, + filter.receiverList.uid, filter.packageName) + != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: receiving " + + r.intent.toString() + + " to " + filter.receiverList.app + + " (pid=" + filter.receiverList.pid + + ", uid=" + filter.receiverList.uid + ")" + + " requires appop " + AppOpsManager.permissionToOp( + r.requiredPermission) + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; } } + if (!skip) { skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, r.callingPid, r.resolvedType, filter.receiverList.uid); @@ -804,8 +843,23 @@ public final class BroadcastQueue { + " due to receiver " + component.flattenToShortString()); } skip = true; + } else if (info.activityInfo.permission != null) { + final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission); + if (opCode != AppOpsManager.OP_NONE + && mService.mAppOpsService.noteOperation(opCode, r.callingUid, + r.callerPackage) != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + + r.callingPid + ", uid=" + r.callingUid + ")" + + " requires appop " + AppOpsManager.permissionToOp( + info.activityInfo.permission) + + " due to registered receiver " + + component.flattenToShortString()); + skip = true; + } } - if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID && + if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID && r.requiredPermission != null) { try { perm = AppGlobals.getPackageManager(). @@ -825,17 +879,36 @@ public final class BroadcastQueue { skip = true; } } - if (r.appOp != AppOpsManager.OP_NONE) { - int mode = mService.mAppOpsService.noteOperation(r.appOp, - info.activityInfo.applicationInfo.uid, info.activityInfo.packageName); - if (mode != AppOpsManager.MODE_ALLOWED) { - if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, - "App op " + r.appOp + " not allowed for broadcast to uid " - + info.activityInfo.applicationInfo.uid + " pkg " - + info.activityInfo.packageName); + int appOp = AppOpsManager.OP_NONE; + if (!skip && r.requiredPermission != null) { + appOp = AppOpsManager.permissionToOpCode(r.requiredPermission); + if (appOp != AppOpsManager.OP_NONE + && mService.mAppOpsService.noteOperation(appOp, + info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) + != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: receiving " + + r.intent + " to " + + component.flattenToShortString() + + " requires appop " + AppOpsManager.permissionToOp( + r.requiredPermission) + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); skip = true; } } + if (!skip && r.appOp != appOp && r.appOp != AppOpsManager.OP_NONE + && mService.mAppOpsService.noteOperation(r.appOp, + info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) + != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: receiving " + + r.intent + " to " + + component.flattenToShortString() + + " requires appop " + AppOpsManager.permissionToOp( + r.requiredPermission) + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; + } if (!skip) { skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid); diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index ece3ffbd2312..5b46799f1aee 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -305,7 +305,8 @@ final class PendingIntentRecord extends IIntentSender.Stub { break; case ActivityManager.INTENT_SENDER_SERVICE: try { - owner.startServiceInPackage(uid, finalIntent, resolvedType, userId); + owner.startServiceInPackage(uid, finalIntent, + resolvedType, key.packageName, userId); } catch (RuntimeException e) { Slog.w(TAG, "Unable to send startService intent", e); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 352e953622a8..305eb8e8cb80 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9198,7 +9198,8 @@ public class PackageManagerService extends IPackageManager.Stub { IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { try { - am.startService(null, intent, null, UserHandle.USER_OWNER); + am.startService(null, intent, null, mContext.getOpPackageName(), + UserHandle.USER_OWNER); } catch (RemoteException e) { } } |