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

Commit 659da379 authored by Tim Yu's avatar Tim Yu Committed by Android Build Coastguard Worker
Browse files

[RESTRICT AUTOMERGE] Check permission of Autofill icon URIs

* SaveUI's template
* Inline Suggestions slices

Fixes: b/286235483
Fixes: b/292104015

Test: atest CtsAutoFillServiceTestCases
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:91fb94942778c8907575a0eed674187dde854a5b)
Merged-In: I48879174664b70ced90492bb0991dc91cbf89b79
Change-Id: I48879174664b70ced90492bb0991dc91cbf89b79
parent a93c50cd
Loading
Loading
Loading
Loading
+46 −2
Original line number Original line Diff line number Diff line
@@ -23,7 +23,10 @@ import android.app.ActivityManager;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.app.assist.AssistStructure.ViewNode;
import android.app.assist.AssistStructure.WindowNode;
import android.app.assist.AssistStructure.WindowNode;
import android.app.slice.Slice;
import android.app.slice.SliceItem;
import android.content.ComponentName;
import android.content.ComponentName;
import android.graphics.drawable.Icon;
import android.metrics.LogMaker;
import android.metrics.LogMaker;
import android.service.autofill.Dataset;
import android.service.autofill.Dataset;
import android.util.ArrayMap;
import android.util.ArrayMap;
@@ -45,7 +48,6 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicBoolean;



public final class Helper {
public final class Helper {


    private static final String TAG = "AutofillHelper";
    private static final String TAG = "AutofillHelper";
@@ -83,7 +85,7 @@ public final class Helper {
        final AtomicBoolean permissionsOk = new AtomicBoolean(true);
        final AtomicBoolean permissionsOk = new AtomicBoolean(true);


        rView.visitUris(uri -> {
        rView.visitUris(uri -> {
            int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri);
            int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri, userId);
            boolean allowed = uriOwnerId == userId;
            boolean allowed = uriOwnerId == userId;
            permissionsOk.set(allowed && permissionsOk.get());
            permissionsOk.set(allowed && permissionsOk.get());
        });
        });
@@ -115,6 +117,48 @@ public final class Helper {
        return (ok ? rView : null);
        return (ok ? rView : null);
    }
    }


    /**
     * Checks the URI permissions of the icon in the slice, to see if the current userId is able to
     * access it.
     *
     * <p>Returns null if slice contains user inaccessible icons
     *
     * <p>TODO: instead of returning a null Slice when the current userId cannot access an icon,
     * return a reconstructed Slice without the icons. This is currently non-trivial since there are
     * no public methods to generically add SliceItems to Slices
     */
    public static @Nullable Slice sanitizeSlice(Slice slice) {
        if (slice == null) {
            return null;
        }

        int userId = ActivityManager.getCurrentUser();

        // Recontruct the Slice, filtering out bad icons
        for (SliceItem sliceItem : slice.getItems()) {
            if (!sliceItem.getFormat().equals(SliceItem.FORMAT_IMAGE)) {
                // Not an image slice
                continue;
            }

            Icon icon = sliceItem.getIcon();
            if (icon.getType() !=  Icon.TYPE_URI
                    && icon.getType() != Icon.TYPE_URI_ADAPTIVE_BITMAP) {
                // No URIs to sanitize
                continue;
            }

            int iconUriId = android.content.ContentProvider.getUserIdFromUri(icon.getUri(), userId);

            if (iconUriId != userId) {
                Slog.w(TAG, "sanitizeSlice() user: " + userId + " cannot access icons in Slice");
                return null;
            }
        }

        return slice;
    }



    @Nullable
    @Nullable
    static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) {
    static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) {
+10 −8
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ import android.service.autofill.InlinePresentation;
import android.util.Slog;
import android.util.Slog;


import com.android.server.LocalServices;
import com.android.server.LocalServices;
import com.android.server.autofill.Helper;
import com.android.server.autofill.RemoteInlineSuggestionRenderService;
import com.android.server.autofill.RemoteInlineSuggestionRenderService;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.inputmethod.InputMethodManagerInternal;


@@ -39,12 +40,9 @@ import java.util.function.Consumer;
final class RemoteInlineSuggestionViewConnector {
final class RemoteInlineSuggestionViewConnector {
    private static final String TAG = RemoteInlineSuggestionViewConnector.class.getSimpleName();
    private static final String TAG = RemoteInlineSuggestionViewConnector.class.getSimpleName();


    @Nullable
    @Nullable private final RemoteInlineSuggestionRenderService mRemoteRenderService;
    private final RemoteInlineSuggestionRenderService mRemoteRenderService;
    @NonNull private final InlinePresentation mInlinePresentation;
    @NonNull
    @Nullable private final IBinder mHostInputToken;
    private final InlinePresentation mInlinePresentation;
    @Nullable
    private final IBinder mHostInputToken;
    private final int mDisplayId;
    private final int mDisplayId;
    private final int mUserId;
    private final int mUserId;
    private final int mSessionId;
    private final int mSessionId;
@@ -82,8 +80,12 @@ final class RemoteInlineSuggestionViewConnector {
     *
     *
     * @return true if the call is made to the remote renderer service, false otherwise.
     * @return true if the call is made to the remote renderer service, false otherwise.
     */
     */
    public boolean renderSuggestion(int width, int height,
    public boolean renderSuggestion(
            @NonNull IInlineSuggestionUiCallback callback) {
            int width, int height, @NonNull IInlineSuggestionUiCallback callback) {
        if (Helper.sanitizeSlice(mInlinePresentation.getSlice()) == null) {
            if (sDebug) Slog.d(TAG, "Skipped rendering inline suggestion.");
            return false;
        }
        if (mRemoteRenderService != null) {
        if (mRemoteRenderService != null) {
            if (sDebug) Slog.d(TAG, "Request to recreate the UI");
            if (sDebug) Slog.d(TAG, "Request to recreate the UI");
            mRemoteRenderService.renderSuggestion(callback, mInlinePresentation, width, height,
            mRemoteRenderService.renderSuggestion(callback, mInlinePresentation, width, height,
+2 −1
Original line number Original line Diff line number Diff line
@@ -418,7 +418,8 @@ final class SaveUi {
                    }
                    }
                    final BatchUpdates batchUpdates = pair.second;
                    final BatchUpdates batchUpdates = pair.second;
                    // First apply the updates...
                    // First apply the updates...
                    final RemoteViews templateUpdates = batchUpdates.getUpdates();
                    final RemoteViews templateUpdates =
                            Helper.sanitizeRemoteView(batchUpdates.getUpdates());
                    if (templateUpdates != null) {
                    if (templateUpdates != null) {
                        if (sDebug) Slog.d(TAG, "Applying template updates for batch update #" + i);
                        if (sDebug) Slog.d(TAG, "Applying template updates for batch update #" + i);
                        templateUpdates.reapply(context, customSubtitleView);
                        templateUpdates.reapply(context, customSubtitleView);