Skip to content

Commit 950b1dd

Browse files
Tim YuAndroid Build Coastguard Worker
authored andcommitted
[DO NOT MERGE] Verify URI Permissions in Autofill RemoteViews
Check permissions of URI inside of FillResponse's RemoteViews. If the current user does not have the required permissions to view the URI, the RemoteView is dropped from displaying. This fixes a security spill in which a user can view content of another user through a malicious Autofill provider. Bug: 283137865 Fixes: b/283264674 b/281666022 b/281665050 b/281848557 b/281533566 b/281534749 b/283101289 Test: Verified by POC app attached in bugs (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:60a0e4f12a1e1ebc609e200ecbb7f80dcb5c1319) Merged-In: I6f4d2a35e89bbed7bd9e07bf5cd3e2d68b20af9a Change-Id: I6f4d2a35e89bbed7bd9e07bf5cd3e2d68b20af9a
1 parent 3d27bd3 commit 950b1dd

4 files changed

Lines changed: 60 additions & 9 deletions

File tree

services/autofill/java/com/android/server/autofill/Helper.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import android.annotation.NonNull;
2020
import android.annotation.Nullable;
21+
import android.annotation.UserIdInt;
22+
import android.app.ActivityManager;
2123
import android.app.assist.AssistStructure;
2224
import android.app.assist.AssistStructure.ViewNode;
2325
import android.app.assist.AssistStructure.WindowNode;
@@ -34,6 +36,7 @@
3436
import android.view.WindowManager;
3537
import android.view.autofill.AutofillId;
3638
import android.view.autofill.AutofillValue;
39+
import android.widget.RemoteViews;
3740

3841
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
3942
import com.android.internal.util.ArrayUtils;
@@ -42,6 +45,8 @@
4245
import java.util.ArrayDeque;
4346
import java.util.ArrayList;
4447
import java.util.Arrays;
48+
import java.util.concurrent.atomic.AtomicBoolean;
49+
4550

4651
public final class Helper {
4752

@@ -75,6 +80,44 @@ private Helper() {
7580
throw new UnsupportedOperationException("contains static members only");
7681
}
7782

83+
private static boolean checkRemoteViewUriPermissions(
84+
@UserIdInt int userId, @NonNull RemoteViews rView) {
85+
final AtomicBoolean permissionsOk = new AtomicBoolean(true);
86+
87+
rView.visitUris(uri -> {
88+
int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri);
89+
boolean allowed = uriOwnerId == userId;
90+
permissionsOk.set(allowed && permissionsOk.get());
91+
});
92+
93+
return permissionsOk.get();
94+
}
95+
96+
/**
97+
* Checks the URI permissions of the remote view,
98+
* to see if the current userId is able to access it.
99+
*
100+
* Returns the RemoteView that is passed if user is able, null otherwise.
101+
*
102+
* TODO: instead of returning a null remoteview when
103+
* the current userId cannot access an URI,
104+
* return a new RemoteView with the URI removed.
105+
*/
106+
public static @Nullable RemoteViews sanitizeRemoteView(RemoteViews rView) {
107+
if (rView == null) return null;
108+
109+
int userId = ActivityManager.getCurrentUser();
110+
111+
boolean ok = checkRemoteViewUriPermissions(userId, rView);
112+
if (!ok) {
113+
Slog.w(TAG,
114+
"sanitizeRemoteView() user: " + userId
115+
+ " tried accessing resource that does not belong to them");
116+
}
117+
return (ok ? rView : null);
118+
}
119+
120+
78121
@Nullable
79122
static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) {
80123
if (set == null) return null;

services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252

5353
import com.android.internal.R;
5454
import com.android.server.autofill.AutofillManagerService;
55+
import com.android.server.autofill.Helper;
5556

5657
import java.io.PrintWriter;
5758
import java.util.ArrayList;
@@ -197,7 +198,8 @@ private void setServiceIcon(View decor, Drawable serviceIcon) {
197198
}
198199

199200
private void setHeader(View decor, FillResponse response) {
200-
final RemoteViews presentation = response.getDialogHeader();
201+
final RemoteViews presentation =
202+
Helper.sanitizeRemoteView(response.getDialogHeader());
201203
if (presentation == null) {
202204
return;
203205
}
@@ -232,9 +234,10 @@ private void setContinueButton(View decor, View.OnClickListener listener) {
232234
}
233235

234236
private void initialAuthenticationLayout(View decor, FillResponse response) {
235-
RemoteViews presentation = response.getDialogPresentation();
237+
RemoteViews presentation = Helper.sanitizeRemoteView(
238+
response.getDialogPresentation());
236239
if (presentation == null) {
237-
presentation = response.getPresentation();
240+
presentation = Helper.sanitizeRemoteView(response.getPresentation());
238241
}
239242
if (presentation == null) {
240243
throw new RuntimeException("No presentation for fill dialog authentication");
@@ -278,7 +281,8 @@ private ArrayList<ViewItem> createDatasetItems(FillResponse response,
278281
final Dataset dataset = response.getDatasets().get(i);
279282
final int index = dataset.getFieldIds().indexOf(focusedViewId);
280283
if (index >= 0) {
281-
RemoteViews presentation = dataset.getFieldDialogPresentation(index);
284+
RemoteViews presentation = Helper.sanitizeRemoteView(
285+
dataset.getFieldDialogPresentation(index));
282286
if (presentation == null) {
283287
if (sDebug) {
284288
Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because "

services/autofill/java/com/android/server/autofill/ui/FillUi.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,9 @@ public static boolean isFullScreen(Context context) {
144144

145145
final LayoutInflater inflater = LayoutInflater.from(mContext);
146146

147-
final RemoteViews headerPresentation = response.getHeader();
148-
final RemoteViews footerPresentation = response.getFooter();
147+
final RemoteViews headerPresentation = Helper.sanitizeRemoteView(response.getHeader());
148+
final RemoteViews footerPresentation = Helper.sanitizeRemoteView(response.getFooter());
149+
149150
final ViewGroup decor;
150151
if (mFullScreen) {
151152
decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null);
@@ -223,6 +224,9 @@ public static boolean isFullScreen(Context context) {
223224
ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker);
224225
final View content;
225226
try {
227+
if (Helper.sanitizeRemoteView(response.getPresentation()) == null) {
228+
throw new RuntimeException("Permission error accessing RemoteView");
229+
}
226230
content = response.getPresentation().applyWithTheme(
227231
mContext, decor, interceptionHandler, mThemeId);
228232
container.addView(content);
@@ -302,7 +306,8 @@ public static boolean isFullScreen(Context context) {
302306
final Dataset dataset = response.getDatasets().get(i);
303307
final int index = dataset.getFieldIds().indexOf(focusedViewId);
304308
if (index >= 0) {
305-
final RemoteViews presentation = dataset.getFieldPresentation(index);
309+
final RemoteViews presentation = Helper.sanitizeRemoteView(
310+
dataset.getFieldPresentation(index));
306311
if (presentation == null) {
307312
Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because "
308313
+ "service didn't provide a presentation for it on " + dataset);

services/autofill/java/com/android/server/autofill/ui/SaveUi.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,7 @@ private boolean applyCustomDescription(@NonNull Context context, @NonNull View s
368368
return false;
369369
}
370370
writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION);
371-
372-
final RemoteViews template = customDescription.getPresentation();
371+
final RemoteViews template = Helper.sanitizeRemoteView(customDescription.getPresentation());
373372
if (template == null) {
374373
Slog.w(TAG, "No remote view on custom description");
375374
return false;

0 commit comments

Comments
 (0)