summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/appwidget/flags.aconfig10
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java41
2 files changed, 51 insertions, 0 deletions
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index ce515761551c..fb33348d9c26 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -92,3 +92,13 @@ flag {
is_exported: true
is_fixed_read_only: true
}
+
+flag {
+ name: "check_remote_views_uri_permission"
+ namespace: "app_widgets"
+ description: "Check that the widget provider has permissions to access any URIs within its RemoteViews"
+ bug: "369137473"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 827e3effcf32..762665c00e05 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.appwidget;
+import static android.appwidget.flags.Flags.checkRemoteViewsUriPermission;
import static android.appwidget.flags.Flags.remoteAdapterConversion;
import static android.appwidget.flags.Flags.remoteViewsProto;
import static android.appwidget.flags.Flags.removeAppWidgetServiceIoFromCriticalPath;
@@ -62,6 +63,7 @@ import android.appwidget.AppWidgetProviderInfo;
import android.appwidget.PendingHostUpdate;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.Intent.FilterComparison;
@@ -150,6 +152,8 @@ import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.WidgetBackupProvider;
+import com.android.server.uri.GrantUri;
+import com.android.server.uri.UriGrantsManagerInternal;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -2548,6 +2552,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// Make sure the package runs under the caller uid.
mSecurityPolicy.enforceCallFromPackage(callingPackage);
+ // Make sure RemoteViews do not contain URIs that the caller cannot access.
+ if (checkRemoteViewsUriPermission()) {
+ checkRemoteViewsUris(views);
+ }
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
@@ -2568,6 +2576,39 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
/**
+ * Checks that all of the Uris in the given RemoteViews are accessible to the caller.
+ */
+ private void checkRemoteViewsUris(RemoteViews views) {
+ UriGrantsManagerInternal uriGrantsManager = LocalServices.getService(
+ UriGrantsManagerInternal.class);
+ int callingUid = Binder.getCallingUid();
+ int callingUser = UserHandle.getCallingUserId();
+ views.visitUris(uri -> {
+ switch (uri.getScheme()) {
+ // Check that content:// URIs are accessible to the caller.
+ case ContentResolver.SCHEME_CONTENT:
+ boolean canAccessUri = uriGrantsManager.checkUriPermission(
+ GrantUri.resolve(callingUser, uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION), callingUid,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ /* isFullAccessForContentUri= */ true);
+ if (!canAccessUri) {
+ throw new SecurityException(
+ "Provider uid " + callingUid + " cannot access URI " + uri);
+ }
+ break;
+ // android.resource:// URIs are always allowed.
+ case ContentResolver.SCHEME_ANDROID_RESOURCE:
+ break;
+ // file:// and any other schemes are disallowed.
+ case ContentResolver.SCHEME_FILE:
+ default:
+ throw new SecurityException("Disallowed URI " + uri + " in RemoteViews.");
+ }
+ });
+ }
+
+ /**
* Increment the counter of widget ids and return the new id.
*
* Typically called by {@link #allocateAppWidgetId} when a instance of widget is created,