From 65712b0ad3b03e65d4949e2cd749441b33576818 Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Thu, 1 Sep 2016 10:24:11 -0700 Subject: [PATCH] White-list grandfathered sync adapters Sync adapters were able to access the synced account without the accounts permission which circumvents our permission model. Therefore, we require sync adapters that don't have access to the account to get user consent. This can be noisy, therefore we will white-list sync adapters installed before we started checking for account access because they already know the account (they run before) which is the genie is out of the bottle. bug:31162498 Change-Id: I815e521778892ec592d53d086273743f1711bd17 --- .../android/server/content/SyncManager.java | 31 +++++++++++++++++++ .../server/content/SyncStorageEngine.java | 13 +++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index f739fa81d5aa9..705eae677d2ba 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -645,6 +645,37 @@ public class SyncManager { mContext.startService(startServiceIntent); } }); + + // Sync adapters were able to access the synced account without the accounts + // permission which circumvents our permission model. Therefore, we require + // sync adapters that don't have access to the account to get user consent. + // This can be noisy, therefore we will white-list sync adapters installed + // before we started checking for account access because they already know + // the account (they run before) which is the genie is out of the bottle. + whiteListExistingSyncAdaptersIfNeeded(); + } + + private void whiteListExistingSyncAdaptersIfNeeded() { + if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) { + return; + } + List users = mUserManager.getUsers(true); + final int userCount = users.size(); + for (int i = 0; i < userCount; i++) { + UserHandle userHandle = users.get(i).getUserHandle(); + final int userId = userHandle.getIdentifier(); + for (RegisteredServicesCache.ServiceInfo service + : mSyncAdapters.getAllServices(userId)) { + String packageName = service.componentName.getPackageName(); + for (Account account : mAccountManager.getAccountsByTypeAsUser( + service.type.accountType, userHandle)) { + if (!canAccessAccount(account, packageName, userId)) { + mAccountManager.updateAppPermission(account, + AccountManager.ACCOUNT_ACCESS_TOKEN, service.uid, true); + } + } + } + } } private boolean isDeviceProvisioned() { diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index 64849aa321da1..8289bae8793bd 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -137,7 +137,7 @@ public class SyncStorageEngine extends Handler { private static final boolean SYNC_ENABLED_DEFAULT = false; // the version of the accounts xml file format - private static final int ACCOUNTS_VERSION = 2; + private static final int ACCOUNTS_VERSION = 3; private static HashMap sAuthorityRenames; private static PeriodicSyncAddedListener mPeriodicSyncAddedListener; @@ -408,6 +408,8 @@ public class SyncStorageEngine extends Handler { private OnSyncRequestListener mSyncRequestListener; private OnAuthorityRemovedListener mAuthorityRemovedListener; + private boolean mGrantSyncAdaptersAccountAccess; + private SyncStorageEngine(Context context, File dataDir) { mContext = context; sSyncStorageEngine = this; @@ -1410,6 +1412,10 @@ public class SyncStorageEngine extends Handler { } } + public boolean shouldGrantSyncAdaptersAccountAccess() { + return mGrantSyncAdaptersAccountAccess; + } + /** * public for testing */ @@ -1464,6 +1470,11 @@ public class SyncStorageEngine extends Handler { } catch (NumberFormatException e) { version = 0; } + + if (version < 3) { + mGrantSyncAdaptersAccountAccess = true; + } + String nextIdString = parser.getAttributeValue(null, XML_ATTR_NEXT_AUTHORITY_ID); try { int id = (nextIdString == null) ? 0 : Integer.parseInt(nextIdString);