Loading services/autofill/java/com/android/server/autofill/Helper.java +45 −0 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.server.autofill; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.UserIdInt; 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; Loading @@ -31,13 +33,18 @@ import android.view.View; import android.view.WindowManager; import android.view.WindowManager; import android.view.autofill.AutofillId; import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; import android.view.autofill.AutofillValue; import android.widget.RemoteViews; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.Arrays; import java.util.ArrayDeque; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; public final class Helper { public final class Helper { Loading Loading @@ -71,6 +78,44 @@ public final class Helper { throw new UnsupportedOperationException("contains static members only"); throw new UnsupportedOperationException("contains static members only"); } } private static boolean checkRemoteViewUriPermissions( @UserIdInt int userId, @NonNull RemoteViews rView) { final AtomicBoolean permissionsOk = new AtomicBoolean(true); rView.visitUris(uri -> { int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri); boolean allowed = uriOwnerId == userId; permissionsOk.set(allowed && permissionsOk.get()); }); return permissionsOk.get(); } /** * Checks the URI permissions of the remote view, * to see if the current userId is able to access it. * * Returns the RemoteView that is passed if user is able, null otherwise. * * TODO: instead of returning a null remoteview when * the current userId cannot access an URI, * return a new RemoteView with the URI removed. */ public static @Nullable RemoteViews sanitizeRemoteView(RemoteViews rView) { if (rView == null) return null; int userId = ActivityManager.getCurrentUser(); boolean ok = checkRemoteViewUriPermissions(userId, rView); if (!ok) { Slog.w(TAG, "sanitizeRemoteView() user: " + userId + " tried accessing resource that does not belong to them"); } return (ok ? rView : null); } @Nullable @Nullable static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) { static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) { if (set == null) return null; if (set == null) return null; Loading services/autofill/java/com/android/server/autofill/ui/FillUi.java +8 −3 Original line number Original line Diff line number Diff line Loading @@ -141,8 +141,9 @@ final class FillUi { final LayoutInflater inflater = LayoutInflater.from(mContext); final LayoutInflater inflater = LayoutInflater.from(mContext); final RemoteViews headerPresentation = response.getHeader(); final RemoteViews headerPresentation = Helper.sanitizeRemoteView(response.getHeader()); final RemoteViews footerPresentation = response.getFooter(); final RemoteViews footerPresentation = Helper.sanitizeRemoteView(response.getFooter()); final ViewGroup decor; final ViewGroup decor; if (mFullScreen) { if (mFullScreen) { decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null); decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null); Loading Loading @@ -220,6 +221,9 @@ final class FillUi { ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker); ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker); final View content; final View content; try { try { if (Helper.sanitizeRemoteView(response.getPresentation()) == null) { throw new RuntimeException("Permission error accessing RemoteView"); } content = response.getPresentation().applyWithTheme( content = response.getPresentation().applyWithTheme( mContext, decor, interceptionHandler, mThemeId); mContext, decor, interceptionHandler, mThemeId); container.addView(content); container.addView(content); Loading Loading @@ -298,7 +302,8 @@ final class FillUi { final Dataset dataset = response.getDatasets().get(i); final Dataset dataset = response.getDatasets().get(i); final int index = dataset.getFieldIds().indexOf(focusedViewId); final int index = dataset.getFieldIds().indexOf(focusedViewId); if (index >= 0) { if (index >= 0) { final RemoteViews presentation = dataset.getFieldPresentation(index); final RemoteViews presentation = Helper.sanitizeRemoteView( dataset.getFieldPresentation(index)); if (presentation == null) { if (presentation == null) { Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because " Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because " + "service didn't provide a presentation for it on " + dataset); + "service didn't provide a presentation for it on " + dataset); Loading services/autofill/java/com/android/server/autofill/ui/SaveUi.java +1 −2 Original line number Original line Diff line number Diff line Loading @@ -361,8 +361,7 @@ final class SaveUi { return false; return false; } } writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION); writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION); final RemoteViews template = Helper.sanitizeRemoteView(customDescription.getPresentation()); final RemoteViews template = customDescription.getPresentation(); if (template == null) { if (template == null) { Slog.w(TAG, "No remote view on custom description"); Slog.w(TAG, "No remote view on custom description"); return false; return false; Loading Loading
services/autofill/java/com/android/server/autofill/Helper.java +45 −0 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.server.autofill; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.UserIdInt; 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; Loading @@ -31,13 +33,18 @@ import android.view.View; import android.view.WindowManager; import android.view.WindowManager; import android.view.autofill.AutofillId; import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; import android.view.autofill.AutofillValue; import android.widget.RemoteViews; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.Arrays; import java.util.ArrayDeque; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; public final class Helper { public final class Helper { Loading Loading @@ -71,6 +78,44 @@ public final class Helper { throw new UnsupportedOperationException("contains static members only"); throw new UnsupportedOperationException("contains static members only"); } } private static boolean checkRemoteViewUriPermissions( @UserIdInt int userId, @NonNull RemoteViews rView) { final AtomicBoolean permissionsOk = new AtomicBoolean(true); rView.visitUris(uri -> { int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri); boolean allowed = uriOwnerId == userId; permissionsOk.set(allowed && permissionsOk.get()); }); return permissionsOk.get(); } /** * Checks the URI permissions of the remote view, * to see if the current userId is able to access it. * * Returns the RemoteView that is passed if user is able, null otherwise. * * TODO: instead of returning a null remoteview when * the current userId cannot access an URI, * return a new RemoteView with the URI removed. */ public static @Nullable RemoteViews sanitizeRemoteView(RemoteViews rView) { if (rView == null) return null; int userId = ActivityManager.getCurrentUser(); boolean ok = checkRemoteViewUriPermissions(userId, rView); if (!ok) { Slog.w(TAG, "sanitizeRemoteView() user: " + userId + " tried accessing resource that does not belong to them"); } return (ok ? rView : null); } @Nullable @Nullable static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) { static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) { if (set == null) return null; if (set == null) return null; Loading
services/autofill/java/com/android/server/autofill/ui/FillUi.java +8 −3 Original line number Original line Diff line number Diff line Loading @@ -141,8 +141,9 @@ final class FillUi { final LayoutInflater inflater = LayoutInflater.from(mContext); final LayoutInflater inflater = LayoutInflater.from(mContext); final RemoteViews headerPresentation = response.getHeader(); final RemoteViews headerPresentation = Helper.sanitizeRemoteView(response.getHeader()); final RemoteViews footerPresentation = response.getFooter(); final RemoteViews footerPresentation = Helper.sanitizeRemoteView(response.getFooter()); final ViewGroup decor; final ViewGroup decor; if (mFullScreen) { if (mFullScreen) { decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null); decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null); Loading Loading @@ -220,6 +221,9 @@ final class FillUi { ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker); ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker); final View content; final View content; try { try { if (Helper.sanitizeRemoteView(response.getPresentation()) == null) { throw new RuntimeException("Permission error accessing RemoteView"); } content = response.getPresentation().applyWithTheme( content = response.getPresentation().applyWithTheme( mContext, decor, interceptionHandler, mThemeId); mContext, decor, interceptionHandler, mThemeId); container.addView(content); container.addView(content); Loading Loading @@ -298,7 +302,8 @@ final class FillUi { final Dataset dataset = response.getDatasets().get(i); final Dataset dataset = response.getDatasets().get(i); final int index = dataset.getFieldIds().indexOf(focusedViewId); final int index = dataset.getFieldIds().indexOf(focusedViewId); if (index >= 0) { if (index >= 0) { final RemoteViews presentation = dataset.getFieldPresentation(index); final RemoteViews presentation = Helper.sanitizeRemoteView( dataset.getFieldPresentation(index)); if (presentation == null) { if (presentation == null) { Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because " Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because " + "service didn't provide a presentation for it on " + dataset); + "service didn't provide a presentation for it on " + dataset); Loading
services/autofill/java/com/android/server/autofill/ui/SaveUi.java +1 −2 Original line number Original line Diff line number Diff line Loading @@ -361,8 +361,7 @@ final class SaveUi { return false; return false; } } writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION); writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION); final RemoteViews template = Helper.sanitizeRemoteView(customDescription.getPresentation()); final RemoteViews template = customDescription.getPresentation(); if (template == null) { if (template == null) { Slog.w(TAG, "No remote view on custom description"); Slog.w(TAG, "No remote view on custom description"); return false; return false; Loading