• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

frameworks/base


Commit MetaInfo

Revisioncefaefa4f447a51a717e7cca750461d3f19b68fc (tree)
Time2017-01-25 09:41:14
AuthorJeff Sharkey <jsharkey@andr...>
Commitergitbuildkicker

Log Message

DO NOT MERGE: Check provider access for content changes.

For an app to either send or receive content change notifications,
require that they have some level of access to the underlying
provider.

Without these checks, a malicious app could sniff sensitive user data
from the notifications of otherwise private providers.

Test: builds, boots, PoC app now fails
Bug: 32555637
Change-Id: If2dcd45cb0a9f1fb3b93e39fc7b8ae9c34c2fdef
(cherry picked from commit ff2fede0ddd9464d4c65e6218a032036adb73099)

Change Summary

Incremental Difference

--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -25,6 +25,11 @@ import android.content.ComponentName;
2525 * @hide Only for use within the system server.
2626 */
2727 public abstract class ActivityManagerInternal {
28+ /**
29+ * Verify that calling app has access to the given provider.
30+ */
31+ public abstract String checkContentProviderAccess(String authority, int userId);
32+
2833 // Called by the power manager.
2934 public abstract void onWakefulnessChanged(int wakefulness);
3035
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9303,6 +9303,43 @@ public final class ActivityManagerService extends ActivityManagerNative
93039303 }
93049304
93059305 /**
9306+ * Check if the calling UID has a possible chance at accessing the provider
9307+ * at the given authority and user.
9308+ */
9309+ public String checkContentProviderAccess(String authority, int userId) {
9310+ if (userId == UserHandle.USER_ALL) {
9311+ mContext.enforceCallingOrSelfPermission(
9312+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
9313+ userId = UserHandle.getCallingUserId();
9314+ }
9315+
9316+ ProviderInfo cpi = null;
9317+ try {
9318+ cpi = AppGlobals.getPackageManager().resolveContentProvider(authority,
9319+ STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
9320+ } catch (RemoteException ignored) {
9321+ }
9322+ if (cpi == null) {
9323+ // TODO: make this an outright failure in a future platform release;
9324+ // until then anonymous content notifications are unprotected
9325+ //return "Failed to find provider " + authority + " for user " + userId;
9326+ return null;
9327+ }
9328+
9329+ ProcessRecord r = null;
9330+ synchronized (mPidsSelfLocked) {
9331+ r = mPidsSelfLocked.get(Binder.getCallingPid());
9332+ }
9333+ if (r == null) {
9334+ return "Failed to find PID " + Binder.getCallingPid();
9335+ }
9336+
9337+ synchronized (this) {
9338+ return checkContentProviderPermissionLocked(cpi, r, userId, true);
9339+ }
9340+ }
9341+
9342+ /**
93069343 * Check if {@link ProcessRecord} has a possible chance at accessing the
93079344 * given {@link ProviderInfo}. Final permission checking is always done
93089345 * in {@link ContentProvider}.
@@ -20624,6 +20661,11 @@ public final class ActivityManagerService extends ActivityManagerNative
2062420661
2062520662 private final class LocalService extends ActivityManagerInternal {
2062620663 @Override
20664+ public String checkContentProviderAccess(String authority, int userId) {
20665+ return ActivityManagerService.this.checkContentProviderAccess(authority, userId);
20666+ }
20667+
20668+ @Override
2062720669 public void onWakefulnessChanged(int wakefulness) {
2062820670 ActivityManagerService.this.onWakefulnessChanged(wakefulness);
2062920671 }
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -19,6 +19,8 @@ package com.android.server.content;
1919 import android.Manifest;
2020 import android.accounts.Account;
2121 import android.app.ActivityManager;
22+import android.app.ActivityManagerInternal;
23+import android.app.ActivityManagerNative;
2224 import android.content.ComponentName;
2325 import android.content.ContentResolver;
2426 import android.content.Context;
@@ -51,7 +53,6 @@ import com.android.server.LocalServices;
5153
5254 import java.io.FileDescriptor;
5355 import java.io.PrintWriter;
54-import java.security.InvalidParameterException;
5556 import java.util.ArrayList;
5657 import java.util.Collections;
5758 import java.util.Comparator;
@@ -190,23 +191,15 @@ public final class ContentService extends IContentService.Stub {
190191
191192 final int uid = Binder.getCallingUid();
192193 final int pid = Binder.getCallingPid();
193- final int callingUserHandle = UserHandle.getCallingUserId();
194- // Registering an observer for any user other than the calling user requires uri grant or
195- // cross user permission
196- if (callingUserHandle != userHandle &&
197- mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
198- != PackageManager.PERMISSION_GRANTED) {
199- enforceCrossUserPermission(userHandle,
200- "no permission to observe other users' provider view");
201- }
202194
203- if (userHandle < 0) {
204- if (userHandle == UserHandle.USER_CURRENT) {
205- userHandle = ActivityManager.getCurrentUser();
206- } else if (userHandle != UserHandle.USER_ALL) {
207- throw new InvalidParameterException("Bad user handle for registerContentObserver: "
208- + userHandle);
209- }
195+ userHandle = handleIncomingUser(uri, pid, uid,
196+ Intent.FLAG_GRANT_READ_URI_PERMISSION, userHandle);
197+
198+ final String msg = LocalServices.getService(ActivityManagerInternal.class)
199+ .checkContentProviderAccess(uri.getAuthority(), userHandle);
200+ if (msg != null) {
201+ Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
202+ return;
210203 }
211204
212205 synchronized (mRootNode) {
@@ -253,21 +246,15 @@ public final class ContentService extends IContentService.Stub {
253246 final int uid = Binder.getCallingUid();
254247 final int pid = Binder.getCallingPid();
255248 final int callingUserHandle = UserHandle.getCallingUserId();
256- // Notify for any user other than the caller requires uri grant or cross user permission
257- if (callingUserHandle != userHandle &&
258- mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
259- != PackageManager.PERMISSION_GRANTED) {
260- enforceCrossUserPermission(userHandle, "no permission to notify other users");
261- }
262249
263- // We passed the permission check; resolve pseudouser targets as appropriate
264- if (userHandle < 0) {
265- if (userHandle == UserHandle.USER_CURRENT) {
266- userHandle = ActivityManager.getCurrentUser();
267- } else if (userHandle != UserHandle.USER_ALL) {
268- throw new InvalidParameterException("Bad user handle for notifyChange: "
269- + userHandle);
270- }
250+ userHandle = handleIncomingUser(uri, pid, uid,
251+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION, userHandle);
252+
253+ final String msg = LocalServices.getService(ActivityManagerInternal.class)
254+ .checkContentProviderAccess(uri.getAuthority(), userHandle);
255+ if (msg != null) {
256+ Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
257+ return;
271258 }
272259
273260 // This makes it so that future permission checks will be in the context of this
@@ -317,6 +304,15 @@ public final class ContentService extends IContentService.Stub {
317304 }
318305 }
319306
307+ private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) {
308+ try {
309+ return ActivityManagerNative.getDefault().checkUriPermission(
310+ uri, pid, uid, modeFlags, userHandle, null);
311+ } catch (RemoteException e) {
312+ return PackageManager.PERMISSION_DENIED;
313+ }
314+ }
315+
320316 public void notifyChange(Uri uri, IContentObserver observer,
321317 boolean observerWantsSelfNotifications, boolean syncToNetwork) {
322318 notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
@@ -924,6 +920,27 @@ public final class ContentService extends IContentService.Stub {
924920 return service;
925921 }
926922
923+ private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, int userId) {
924+ if (userId == UserHandle.USER_CURRENT) {
925+ userId = ActivityManager.getCurrentUser();
926+ }
927+
928+ if (userId == UserHandle.USER_ALL) {
929+ mContext.enforceCallingOrSelfPermission(
930+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
931+ } else if (userId < 0) {
932+ throw new IllegalArgumentException("Invalid user: " + userId);
933+ } else if (userId != UserHandle.getCallingUserId()) {
934+ if (checkUriPermission(uri, pid, uid, modeFlags,
935+ userId) != PackageManager.PERMISSION_GRANTED) {
936+ mContext.enforceCallingOrSelfPermission(
937+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
938+ }
939+ }
940+
941+ return userId;
942+ }
943+
927944 /**
928945 * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
929946 * permission, if the userHandle is not for the caller.