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

Commit 16175f00 authored by Azhara Assanova's avatar Azhara Assanova
Browse files

Add EXTRA_STREAM to requireContentUriPermissionFromCaller

The Activity Manifest attribute requireContentUriPermissionFromCaller
only works for content URIs passed in Intent#getData and
Intent#getClipData. This change adds Intent#EXTRA_STREAM to that list as
it is one of the common ways for apps to pass URIs.

EXTRA_STREAM only works for URIs that the system can unparcel. If
unparcel fails, i.e. a BadParcelableException is thrown, the item is
still preserved as a LazyValue with the underlying parcel.

Bug: 293467489
Test: atest CtsContentTestCases:android.content.cts.ActivityRequireContentUriPermissionFromCallerTest
Change-Id: Idcd3b38adfd3e2ebad7e69f40d1cb822c4a0e6e4
parent 1bb44936
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -3287,7 +3287,8 @@
             {@link java.lang.SecurityException}.

             <p> Note that the enforcement works for content URIs inside
             {@link android.content.Intent#getData} and {@link android.content.Intent#getClipData}.
             {@link android.content.Intent#getData}, {@link android.content.Intent#EXTRA_STREAM},
             and {@link android.content.Intent#getClipData}.
             @FlaggedApi("android.security.content_uri_permission_apis") -->
        <attr name="requireContentUriPermissionFromCaller" format="string">
            <!-- Default, no specific permissions are required. -->
+45 −5
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.PathPermission;
import android.content.pm.ProviderInfo;
import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -630,16 +631,24 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements
        if (intent == null) {
            return null;
        }
        Uri data = intent.getData();
        ClipData clip = intent.getClipData();
        if (data == null && clip == null) {
            return null;
        }

        // Default userId for uris in the intent (if they don't specify it themselves)
        int contentUserHint = intent.getContentUserHint();
        if (contentUserHint == UserHandle.USER_CURRENT) {
            contentUserHint = UserHandle.getUserId(callingUid);
        }

        if (android.security.Flags.contentUriPermissionApis()) {
            enforceRequireContentUriPermissionFromCallerOnIntentExtraStream(intent, contentUserHint,
                    mode, callingUid, requireContentUriPermissionFromCaller);
        }

        Uri data = intent.getData();
        ClipData clip = intent.getClipData();
        if (data == null && clip == null) {
            return null;
        }

        int targetUid;
        if (needed != null) {
            targetUid = needed.targetUid;
@@ -733,6 +742,37 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements
        }
    }

    private void enforceRequireContentUriPermissionFromCallerOnIntentExtraStream(Intent intent,
            int contentUserHint, int mode, int callingUid,
            @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller) {
        try {
            final Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri.class);
            if (uri != null) {
                final GrantUri grantUri = GrantUri.resolve(contentUserHint, uri, mode);
                enforceRequireContentUriPermissionFromCaller(
                        requireContentUriPermissionFromCaller, grantUri, callingUid);
            }
        } catch (BadParcelableException e) {
            Slog.w(TAG, "Failed to unparcel an URI in EXTRA_STREAM, skipping"
                    + " requireContentUriPermissionFromCaller: " + e);
        }

        try {
            final ArrayList<Uri> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM,
                    Uri.class);
            if (uris != null) {
                for (int i = uris.size() - 1; i >= 0; i--) {
                    final GrantUri grantUri = GrantUri.resolve(contentUserHint, uris.get(i), mode);
                    enforceRequireContentUriPermissionFromCaller(
                            requireContentUriPermissionFromCaller, grantUri, callingUid);
                }
            }
        } catch (BadParcelableException e) {
            Slog.w(TAG, "Failed to unparcel an ArrayList of URIs in EXTRA_STREAM, skipping"
                    + " requireContentUriPermissionFromCaller: " + e);
        }
    }

    @GuardedBy("mLock")
    private void readGrantedUriPermissionsLocked() {
        if (DEBUG) Slog.v(TAG, "readGrantedUriPermissions()");