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

Commit 23e2ccbb authored by Jackal Guo's avatar Jackal Guo
Browse files

Honor app visibility when get MIME type from ContentProvider

APIs getProviderMimeType and getProviderMimeTypeAsync from Activity-
ManagerService don't check whether the ContentProvider holder of the
given URI is visible to the callers.

Bug: 185126503
Bug: 185126713
Test: atest CtsContentTestCases
Test: atest CtsProviderTestCases
Test: manually using the PoC in the buganizer to ensure the symptom
      no longer exists.
Change-Id: I73427c7909f56e51d7aabeebb1bfa841b5fd6ffe
parent 14c60531
Loading
Loading
Loading
Loading
+40 −26
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerService.TAG_MU;
import static com.android.server.am.ActivityManagerService.TAG_MU;
import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_PROVIDER;
import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_PROVIDER;


import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal;
@@ -48,7 +49,6 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PathPermission;
import android.content.pm.PathPermission;
import android.content.pm.ProviderInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
@@ -958,20 +958,22 @@ public class ContentProviderHelper {
    String getProviderMimeType(Uri uri, int userId) {
    String getProviderMimeType(Uri uri, int userId) {
        mService.enforceNotIsolatedCaller("getProviderMimeType");
        mService.enforceNotIsolatedCaller("getProviderMimeType");
        final String name = uri.getAuthority();
        final String name = uri.getAuthority();
        int callingUid = Binder.getCallingUid();
        final int callingUid = Binder.getCallingUid();
        int callingPid = Binder.getCallingPid();
        final int callingPid = Binder.getCallingPid();
        long ident = 0;
        final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId);
        boolean clearedIdentity = false;
        final long ident = canClearIdentity(callingPid, callingUid, safeUserId)
        userId = mService.mUserController.unsafeConvertIncomingUser(userId);
                ? Binder.clearCallingIdentity() : 0;
        if (canClearIdentity(callingPid, callingUid, userId)) {
        final ContentProviderHolder holder;
            clearedIdentity = true;
            ident = Binder.clearCallingIdentity();
        }
        ContentProviderHolder holder = null;
        try {
        try {
            holder = getContentProviderExternalUnchecked(name, null, callingUid,
            holder = getContentProviderExternalUnchecked(name, null, callingUid,
                    "*getmimetype*", userId);
                    "*getmimetype*", safeUserId);
            if (holder != null) {
        } finally {
            if (ident != 0) {
                Binder.restoreCallingIdentity(ident);
            }
        }
        try {
            if (isHolderVisibleToCaller(holder, callingUid, safeUserId)) {
                final IBinder providerConnection = holder.connection;
                final IBinder providerConnection = holder.connection;
                final ComponentName providerName = holder.info.getComponentName();
                final ComponentName providerName = holder.info.getComponentName();
                // Note: creating a new Runnable instead of using a lambda here since lambdas in
                // Note: creating a new Runnable instead of using a lambda here since lambdas in
@@ -1000,15 +1002,13 @@ public class ContentProviderHelper {
            return null;
            return null;
        } finally {
        } finally {
            // We need to clear the identity to call removeContentProviderExternalUnchecked
            // We need to clear the identity to call removeContentProviderExternalUnchecked
            if (!clearedIdentity) {
            final long token = Binder.clearCallingIdentity();
                ident = Binder.clearCallingIdentity();
            }
            try {
            try {
                if (holder != null) {
                if (holder != null) {
                    removeContentProviderExternalUnchecked(name, null, userId);
                    removeContentProviderExternalUnchecked(name, null /* token */, safeUserId);
                }
                }
            } finally {
            } finally {
                Binder.restoreCallingIdentity(ident);
                Binder.restoreCallingIdentity(token);
            }
            }
        }
        }


@@ -1027,12 +1027,20 @@ public class ContentProviderHelper {
        final int callingUid = Binder.getCallingUid();
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();
        final int callingPid = Binder.getCallingPid();
        final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId);
        final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId);
        final long ident = canClearIdentity(callingPid, callingUid, userId)
        final long ident = canClearIdentity(callingPid, callingUid, safeUserId)
                ? Binder.clearCallingIdentity() : 0;
                ? Binder.clearCallingIdentity() : 0;
        final ContentProviderHolder holder;
        try {
        try {
            final ContentProviderHolder holder = getContentProviderExternalUnchecked(name, null,
            holder = getContentProviderExternalUnchecked(name, null /* token */,
                    callingUid, "*getmimetype*", safeUserId);
                    callingUid, "*getmimetype*", safeUserId);
            if (holder != null) {
        } finally {
            if (ident != 0) {
                Binder.restoreCallingIdentity(ident);
            }
        }

        try {
            if (isHolderVisibleToCaller(holder, callingUid, safeUserId)) {
                holder.provider.getTypeAsync(uri, new RemoteCallback(result -> {
                holder.provider.getTypeAsync(uri, new RemoteCallback(result -> {
                    final long identity = Binder.clearCallingIdentity();
                    final long identity = Binder.clearCallingIdentity();
                    try {
                    try {
@@ -1048,8 +1056,6 @@ public class ContentProviderHelper {
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            Log.w(TAG, "Content provider dead retrieving " + uri, e);
            Log.w(TAG, "Content provider dead retrieving " + uri, e);
            resultCallback.sendResult(Bundle.EMPTY);
            resultCallback.sendResult(Bundle.EMPTY);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        }
    }
    }


@@ -1065,6 +1071,16 @@ public class ContentProviderHelper {
                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
    }
    }


    private boolean isHolderVisibleToCaller(@Nullable ContentProviderHolder holder, int callingUid,
            @UserIdInt int userId) {
        if (holder == null || holder.info == null) {
            return false;
        }

        return !mService.getPackageManagerInternal()
                .filterAppAccess(holder.info.packageName, callingUid, userId);
    }

    /**
    /**
     * Check if the calling UID has a possible chance at accessing the provider
     * Check if the calling UID has a possible chance at accessing the provider
     * at the given authority and user.
     * at the given authority and user.
@@ -1133,9 +1149,7 @@ public class ContentProviderHelper {
                    "*checkContentProviderUriPermission*", userId);
                    "*checkContentProviderUriPermission*", userId);
            if (holder != null) {
            if (holder != null) {


                final PackageManagerInternal packageManagerInt = LocalServices.getService(
                final AndroidPackage androidPackage = mService.getPackageManagerInternal()
                        PackageManagerInternal.class);
                final AndroidPackage androidPackage = packageManagerInt
                        .getPackage(Binder.getCallingUid());
                        .getPackage(Binder.getCallingUid());
                if (androidPackage == null) {
                if (androidPackage == null) {
                    return PackageManager.PERMISSION_DENIED;
                    return PackageManager.PERMISSION_DENIED;