diff options
| author | Svet Ganov <svetoslavganov@google.com> | 2021-03-30 20:43:33 +0000 |
|---|---|---|
| committer | Svetoslav Ganov <svetoslavganov@google.com> | 2021-03-31 02:11:46 +0000 |
| commit | 7d058d62e5bfc2893e297ece9094665d628127c2 (patch) | |
| tree | ff7f274617a7a2313979e1a7e709aeb562e4ce38 /core/java/android | |
| parent | 6564529264063b185c93b033687ae900a332083d (diff) | |
Addressing comments from commit:8d2ed5
bug:158792096
bug:180647319
bug:184051153
bug:184027531
Test:atest CtsPermissionTestCases
atest CtsPermission2TestCases
atest CtsPermission3TestCases
atest CtsPermission4TestCases
atest CtsPermission5TestCases
atest CtsAppOpsTestCases
atest CtsAppOps2TestCases
atest CtsAlarmManagerTestCases
Change-Id: Id324ed0e2a653dface6ba273bba27e92bea14f99
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/app/AppOpsManager.java | 26 | ||||
| -rw-r--r-- | core/java/android/app/ContextImpl.java | 17 | ||||
| -rw-r--r-- | core/java/android/content/ContentResolver.java | 1 | ||||
| -rw-r--r-- | core/java/android/content/Context.java | 2 | ||||
| -rw-r--r-- | core/java/android/content/ContextParams.java | 14 | ||||
| -rw-r--r-- | core/java/android/content/PermissionChecker.java | 73 |
6 files changed, 79 insertions, 54 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index f76e1c0e50fb..6ce0b2283603 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -7404,6 +7404,32 @@ public class AppOpsManager { } /** + * Resolves special UID's pakcages such as root, shell, media, etc. + * + * @param uid The uid to resolve. + * @param packageName Optional package. If caller system and null returns "android" + * @return The resolved package name. + * + * @hide + */ + public static @Nullable String resolvePackageName(int uid, @Nullable String packageName) { + if (uid == Process.ROOT_UID) { + return "root"; + } else if (uid == Process.SHELL_UID) { + return "com.android.shell"; + } else if (uid == Process.MEDIA_UID) { + return "media"; + } else if (uid == Process.AUDIOSERVER_UID) { + return "audioserver"; + } else if (uid == Process.CAMERASERVER_UID) { + return "cameraserver"; + } else if (uid == Process.SYSTEM_UID && packageName == null) { + return "android"; + } + return packageName; + } + + /** * Monitor for changes to the operating mode for the given op in the given app package. * You can watch op changes only for your UID. * diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index f8165e9a7cf6..eb31b5294a26 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -226,7 +226,7 @@ class ContextImpl extends Context { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final String mOpPackageName; private final @NonNull ContextParams mParams; - private @NonNull AttributionSource mAttributionSource; + private final @NonNull AttributionSource mAttributionSource; private final @NonNull ResourcesManager mResourcesManager; @UnsupportedAppUsage @@ -3074,25 +3074,26 @@ class ContextImpl extends Context { mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName; mParams = Objects.requireNonNull(params); - initializeAttributionSource(attributionTag, nextAttributionSource); + mAttributionSource = createAttributionSource(attributionTag, nextAttributionSource); mContentResolver = new ApplicationContentResolver(this, mainThread); } - private void initializeAttributionSource(@Nullable String attributionTag, + private @NonNull AttributionSource createAttributionSource(@Nullable String attributionTag, @Nullable AttributionSource nextAttributionSource) { - mAttributionSource = new AttributionSource(Process.myUid(), mOpPackageName, + AttributionSource attributionSource = new AttributionSource(Process.myUid(), mOpPackageName, attributionTag, nextAttributionSource); // If we want to access protected data on behalf of another app we need to // tell the OS that we opt in to participate in the attribution chain. if (nextAttributionSource != null) { // If an app happened to stub the internal OS for testing the registration method // can return null. In this case we keep the current untrusted attribution source. - final AttributionSource attributionSource = getSystemService(PermissionManager.class) - .registerAttributionSource(mAttributionSource); - if (attributionSource != null) { - mAttributionSource = attributionSource; + final AttributionSource registeredAttributionSource = getSystemService( + PermissionManager.class).registerAttributionSource(attributionSource); + if (registeredAttributionSource != null) { + return registeredAttributionSource; } } + return attributionSource; } void setResources(Resources r) { diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 14b2a65c4da6..aec39da973f0 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -3884,6 +3884,7 @@ public abstract class ContentResolver implements ContentInterface { @UnsupportedAppUsage private final Context mContext; + @Deprecated @UnsupportedAppUsage final String mPackageName; final int mTargetSdkVersion; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 8531d341ee9b..232daa8f8b47 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -6475,7 +6475,7 @@ public abstract class Context { */ @Deprecated public @NonNull Context createFeatureContext(@Nullable String attributionTag) { - return createContext(new ContextParams.Builder() + return createContext(new ContextParams.Builder(getParams()) .setAttributionTag(attributionTag) .build()); } diff --git a/core/java/android/content/ContextParams.java b/core/java/android/content/ContextParams.java index 2b2db8fca2ca..bd3eaea24126 100644 --- a/core/java/android/content/ContextParams.java +++ b/core/java/android/content/ContextParams.java @@ -53,10 +53,11 @@ public final class ContextParams { private ContextParams(@Nullable String attributionTag, @Nullable AttributionSource next, - @NonNull Set<String> renouncedPermissions) { + @Nullable Set<String> renouncedPermissions) { mAttributionTag = attributionTag; mNext = next; - mRenouncedPermissions = renouncedPermissions; + mRenouncedPermissions = (renouncedPermissions != null) + ? renouncedPermissions : Collections.emptySet(); } /** @@ -149,8 +150,8 @@ public final class ContextParams { * @see AttributionSource */ @NonNull - public Builder setNextAttributionSource(@NonNull AttributionSource next) { - mNext = Objects.requireNonNull(next); + public Builder setNextAttributionSource(@Nullable AttributionSource next) { + mNext = next; return this; } @@ -177,9 +178,8 @@ public final class ContextParams { @SystemApi @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public @NonNull Builder setRenouncedPermissions( - @NonNull Set<String> renouncedPermissions) { - mRenouncedPermissions = Collections.unmodifiableSet( - Objects.requireNonNull(renouncedPermissions)); + @Nullable Set<String> renouncedPermissions) { + mRenouncedPermissions = renouncedPermissions; return this; } diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java index 08eac5aff655..6a254bd0465e 100644 --- a/core/java/android/content/PermissionChecker.java +++ b/core/java/android/content/PermissionChecker.java @@ -24,6 +24,7 @@ import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.os.Binder; import android.os.Process; +import android.util.Slog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -70,6 +71,8 @@ import java.util.concurrent.ConcurrentHashMap; * @hide */ public final class PermissionChecker { + private static final String LOG_TAG = PermissionChecker.class.getName(); + private static final String PLATFORM_PACKAGE_NAME = "android"; /** The permission is granted. */ @@ -92,6 +95,7 @@ public final class PermissionChecker { /** Constant when the PID for which we check permissions is unknown. */ public static final int PID_UNKNOWN = -1; + // Cache for platform defined runtime permissions to avoid multi lookup (name -> info) private static final ConcurrentHashMap<String, PermissionInfo> sPlatformPermissions = new ConcurrentHashMap<>(); @@ -840,12 +844,11 @@ public final class PermissionChecker { @NonNull AttributionSource attributionSource, @Nullable String message, boolean forDataDelivery, boolean fromDatasource) { final int op = AppOpsManager.permissionToOpCode(permission); - if (op < 0 || attributionSource.getPackageName() == null) { + if (op < 0) { + Slog.wtf(LOG_TAG, "Appop permission " + permission + "with no app op defined:!"); return PERMISSION_HARD_DENIED; } - final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); - AttributionSource current = attributionSource; AttributionSource next = null; @@ -856,28 +859,21 @@ public final class PermissionChecker { // If the call is from a datasource we need to vet only the chain before it. This // way we can avoid the datasource creating an attribution context for every call. - if ((!fromDatasource || current != attributionSource) + if (!(fromDatasource && current == attributionSource) && next != null && !current.isTrusted(context)) { return PERMISSION_HARD_DENIED; } - int opMode; - if (forDataDelivery) { - if (next == null) { - opMode = appOpsManager.noteOpNoThrow(op, current.getUid(), - current.getPackageName(), current.getAttributionTag(), message); - } else { - opMode = appOpsManager.noteProxyOpNoThrow(op, current, message, - skipCurrentChecks); - } - } else { - opMode = appOpsManager.unsafeCheckOpRawNoThrow(op, current.getUid(), - current.getPackageName()); - if (next != null && opMode == AppOpsManager.MODE_ALLOWED) { - opMode = appOpsManager.unsafeCheckOpRawNoThrow(op, next.getUid(), - next.getPackageName()); - } - } + // The access is for oneself if this is the single receiver of data + // after the data source or if this is the single attribution source + // in the chain if not from a datasource. + final boolean singleReceiverFromDatasource = (fromDatasource + && current == attributionSource && next != null && next.getNext() == null); + final boolean selfAccess = singleReceiverFromDatasource || next == null; + + final int opMode = performOpTransaction(context, op, current, message, + forDataDelivery, /*startDataDelivery*/ false, skipCurrentChecks, + selfAccess, singleReceiverFromDatasource); switch (opMode) { case AppOpsManager.MODE_IGNORED: @@ -920,7 +916,7 @@ public final class PermissionChecker { // If the call is from a datasource we need to vet only the chain before it. This // way we can avoid the datasource creating an attribution context for every call. - if ((!fromDatasource || current != attributionSource) + if (!(fromDatasource && current == attributionSource) && next != null && !current.isTrusted(context)) { return PERMISSION_HARD_DENIED; } @@ -937,6 +933,8 @@ public final class PermissionChecker { } if (op < 0) { + Slog.wtf(LOG_TAG, "Runtime permission " + permission + "with no app op defined:!"); + current = next; continue; } @@ -1021,7 +1019,7 @@ public final class PermissionChecker { current = next; } } - // If from data source and there is next app after that we need to note SELF of (noteOp) for the app vs proxy + private static int performOpTransaction(@NonNull Context context, int op, @NonNull AttributionSource attributionSource, @Nullable String message, boolean forDataDelivery, boolean startDataDelivery, boolean skipProxyOperation, @@ -1031,27 +1029,26 @@ public final class PermissionChecker { // do a best effort to resolve the package from the UID (pick first without a loss // of generality - they are in the same security sandbox). final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); + final AttributionSource accessorSource = (!singleReceiverFromDatasource) + ? attributionSource : attributionSource.getNext(); if (!forDataDelivery) { - final String resolvedPackageName = resolvePackageName(context, attributionSource); - if (resolvedPackageName == null) { + final String resolvedAccessorPackageName = resolvePackageName(context, accessorSource); + if (resolvedAccessorPackageName == null) { return AppOpsManager.MODE_ERRORED; } final int opMode = appOpsManager.unsafeCheckOpRawNoThrow(op, - attributionSource.getUid(), resolvedPackageName); - final AttributionSource previous = attributionSource.getNext(); - if (opMode == AppOpsManager.MODE_ALLOWED && previous != null) { - final String resolvedPreviousPackageName = resolvePackageName(context, - previous); - if (resolvedPreviousPackageName == null) { + accessorSource.getUid(), resolvedAccessorPackageName); + final AttributionSource next = accessorSource.getNext(); + if (!selfAccess && opMode == AppOpsManager.MODE_ALLOWED && next != null) { + final String resolvedNextPackageName = resolvePackageName(context, next); + if (resolvedNextPackageName == null) { return AppOpsManager.MODE_ERRORED; } - return appOpsManager.unsafeCheckOpRawNoThrow(op, previous.getUid(), - resolvedPreviousPackageName); + return appOpsManager.unsafeCheckOpRawNoThrow(op, next.getUid(), + resolvedNextPackageName); } return opMode; } else if (startDataDelivery) { - final AttributionSource accessorSource = (!singleReceiverFromDatasource) - ? attributionSource : attributionSource.getNext(); final AttributionSource resolvedAttributionSource = resolveAttributionSource( context, accessorSource); if (resolvedAttributionSource.getPackageName() == null) { @@ -1068,8 +1065,6 @@ public final class PermissionChecker { skipProxyOperation); } } else { - final AttributionSource accessorSource = (!singleReceiverFromDatasource) - ? attributionSource : attributionSource.getNext(); final AttributionSource resolvedAttributionSource = resolveAttributionSource( context, accessorSource); if (resolvedAttributionSource.getPackageName() == null) { @@ -1099,7 +1094,9 @@ public final class PermissionChecker { // sandbox is UID, therefore we pick an arbitrary package. return packageNames[0]; } - return null; + // Last resort to handle special UIDs like root, etc. + return AppOpsManager.resolvePackageName(attributionSource.getUid(), + attributionSource.getPackageName()); } private static @NonNull AttributionSource resolveAttributionSource( |
