Loading core/java/android/appwidget/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -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 } } services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +41 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -2567,6 +2575,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. * Loading Loading
core/java/android/appwidget/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -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 } }
services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +41 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -2567,6 +2575,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. * Loading