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

Commit 4914447e authored by Himanshu Gupta's avatar Himanshu Gupta
Browse files

Allowing content uris with cloneUserId to be accessed by parent user.

In some cases a userId maybe appended to the contentUri, to determine
the storage location of the content, ex: `content://10@media/external/images/media/000001.png`

This has started in systemui/screenshot, where ag/19783114 appended the userId of the
foreground user in ScreenShot Content Uris. However, this change gives error while
saving screenshots in cloned apps, as the userId appended is different from the
MediaProvider Process trying to save the content (MP of user 0 is used for clonedProfile).
The error is triggerred from `ContentProvider.validateIncomingUri`

We add the check that if the ContentAuthorityUser shares Media with a parentUser,
and the latter is same as the MP process user, we do not throw the above error.

Bug: b/270350104
Test: Manual verification on device
Change-Id: I62e87c4f04840573138ed59918cc869d1ab12dea
parent 7871be0c
Loading
Loading
Loading
Loading
+34 −22
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
    private boolean mExported;
    private boolean mNoPerms;
    private boolean mSingleUser;
    private SparseBooleanArray mUsersRedirectedToOwner = new SparseBooleanArray();
    private SparseBooleanArray mUsersRedirectedToOwnerForMedia = new SparseBooleanArray();

    private ThreadLocal<AttributionSource> mCallingAttributionSource;

@@ -874,34 +874,42 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            return true;
        }

        if (isAuthorityRedirectedForCloneProfile(mAuthority)) {
            if (mUsersRedirectedToOwner.indexOfKey(callingUserId) >= 0) {
                return mUsersRedirectedToOwner.get(callingUserId);
        // Provider user-id will be determined from User Space of the calling app.
        return isContentRedirectionAllowedForUser(callingUserId);
    }

            // Haven't seen this user yet, look it up
            try {
                UserHandle callingUser = UserHandle.getUserHandleForUid(uid);
                Context callingUserContext = mContext.createPackageContextAsUser("system",
                        0, callingUser);
                UserManager um = callingUserContext.getSystemService(UserManager.class);

                if (um != null && um.isCloneProfile()) {
                    UserHandle parent = um.getProfileParent(callingUser);
    /**
     * Verify that content redirection is allowed or not.
     * We check:
     * 1. Type of Authority
     * 2. UserProperties allow content sharing
     *
     * @param incomingUserId - Provider's user-id to be passed should be based upon:
     *                       1. If client is a cloned app running in user 10, it should be that (10)
     *                       2. If client is accessing content by hinting user space of content,
     *                       like sysUi (residing in user 0) accessing 'content://11@media/external'
     *                       then it should be 11.
     */
    private boolean isContentRedirectionAllowedForUser(int incomingUserId) {
        if (MediaStore.AUTHORITY.equals(mAuthority)) {
            if (mUsersRedirectedToOwnerForMedia.indexOfKey(incomingUserId) >= 0) {
                return mUsersRedirectedToOwnerForMedia.valueAt(incomingUserId);
            }

            // Haven't seen this user yet, look it up
            UserManager um = mContext.getSystemService(UserManager.class);
            if (um != null && um.getUserProperties(UserHandle.of(incomingUserId))
                    .isMediaSharedWithParent()) {
                UserHandle parent = um.getProfileParent(UserHandle.of(incomingUserId));
                if (parent != null && parent.equals(myUserHandle())) {
                        mUsersRedirectedToOwner.put(callingUserId, true);
                    mUsersRedirectedToOwnerForMedia.put(incomingUserId, true);
                    return true;
                }
            }
            } catch (PackageManager.NameNotFoundException e) {
                // ignore
            }

            mUsersRedirectedToOwner.put(callingUserId, false);
            mUsersRedirectedToOwnerForMedia.put(incomingUserId, false);
            return false;
        }

        return false;
    }

@@ -2729,7 +2737,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
        String auth = uri.getAuthority();
        if (!mSingleUser) {
            int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
            if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId()) {
            if (userId != UserHandle.USER_CURRENT
                    && userId != mContext.getUserId()
                    // Since userId specified in content uri, the provider userId would be
                    // determined from it.
                    && !isContentRedirectionAllowedForUser(userId)) {
                throw new SecurityException("trying to query a ContentProvider in user "
                        + mContext.getUserId() + " with a uri belonging to user " + userId);
            }