Loading services/core/java/com/android/server/content/ContentService.java +86 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.content.PermissionChecker.PERMISSION_GRANTED; import android.Manifest; import android.accounts.Account; import android.accounts.AccountManagerInternal; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; Loading @@ -28,7 +29,10 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.compat.CompatChanges; import android.app.job.JobInfo; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; Loading Loading @@ -106,6 +110,13 @@ public final class ContentService extends IContentService.Stub { */ private static final long BACKGROUND_OBSERVER_DELAY = 10 * DateUtils.SECOND_IN_MILLIS; /** * Enables checking for account access for the calling uid on all sync-related APIs. */ @ChangeId @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2) public static final long ACCOUNT_ACCESS_CHECK_CHANGE_ID = 201794303L; public static class Lifecycle extends SystemService { private ContentService mService; Loading Loading @@ -157,6 +168,8 @@ public final class ContentService extends IContentService.Stub { private SyncManager mSyncManager = null; private final Object mSyncManagerLock = new Object(); private final AccountManagerInternal mAccountManagerInternal; private static final BinderDeathDispatcher<IContentObserver> sObserverDeathDispatcher = new BinderDeathDispatcher<>(); Loading Loading @@ -317,6 +330,8 @@ public final class ContentService extends IContentService.Stub { localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED); mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL, localeFilter, null, null); mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class); } void onBootPhase(int phase) { Loading Loading @@ -593,6 +608,10 @@ public final class ContentService extends IContentService.Stub { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); if (!hasAccountAccess(true, account, callingUid)) { return; } validateExtras(callingUid, extras); final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras); Loading Loading @@ -642,11 +661,14 @@ public final class ContentService extends IContentService.Stub { @Override public void syncAsUser(SyncRequest request, int userId, String callingPackage) { enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); if (!hasAccountAccess(true, request.getAccount(), callingUid)) { return; } final Bundle extras = request.getBundle(); validateExtras(callingUid, extras); final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras); Loading Loading @@ -853,6 +875,9 @@ public final class ContentService extends IContentService.Stub { "no permission to read the sync settings for user " + userId); mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, "no permission to read the sync settings"); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return false; } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -882,8 +907,13 @@ public final class ContentService extends IContentService.Stub { "no permission to write the sync settings"); enforceCrossUserPermission(userId, "no permission to modify the sync settings for user " + userId); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); if (!hasAccountAccess(true, account, callingUid)) { return; } final int syncExemptionFlag = getSyncExemptionForCaller(callingUid); final long identityToken = clearCallingIdentity(); Loading Loading @@ -912,7 +942,11 @@ public final class ContentService extends IContentService.Stub { mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, "no permission to write the sync settings"); validateExtras(Binder.getCallingUid(), extras); final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return; } validateExtras(callingUid, extras); int userId = UserHandle.getCallingUserId(); Loading Loading @@ -942,9 +976,11 @@ public final class ContentService extends IContentService.Stub { mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, "no permission to write the sync settings"); validateExtras(Binder.getCallingUid(), extras); final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return; } validateExtras(callingUid, extras); int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); Loading @@ -969,6 +1005,9 @@ public final class ContentService extends IContentService.Stub { } mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, "no permission to read the sync settings"); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return new ArrayList<>(); // return a new empty list for consistent behavior } int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); Loading @@ -995,6 +1034,9 @@ public final class ContentService extends IContentService.Stub { "no permission to read the sync settings for user " + userId); mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, "no permission to read the sync settings"); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; // to keep behavior consistent } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1031,6 +1073,9 @@ public final class ContentService extends IContentService.Stub { syncable = normalizeSyncable(syncable); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); if (!hasAccountAccess(true, account, callingUid)) { return; } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1103,6 +1148,10 @@ public final class ContentService extends IContentService.Stub { public boolean isSyncActive(Account account, String authority, ComponentName cname) { mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, "no permission to read the sync stats"); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return false; } int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1165,6 +1214,9 @@ public final class ContentService extends IContentService.Stub { "no permission to read the sync stats for user " + userId); mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, "no permission to read the sync stats"); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return null; } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1196,6 +1248,10 @@ public final class ContentService extends IContentService.Stub { "no permission to read the sync stats"); enforceCrossUserPermission(userId, "no permission to retrieve the sync settings for user " + userId); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return false; } final long identityToken = clearCallingIdentity(); SyncManager syncManager = getSyncManager(); if (syncManager == null) return false; Loading Loading @@ -1405,6 +1461,32 @@ public final class ContentService extends IContentService.Stub { Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); } /** * Checks to see if the given account is accessible by the provided uid. * * @param checkCompatFlag whether to check if the ACCOUNT_ACCESS_CHECK_CHANGE_ID flag is enabled * @param account the account trying to be accessed * @param uid the uid trying to access the account * @return {@code true} if the account is accessible by the given uid, {@code false} otherwise */ private boolean hasAccountAccess(boolean checkCompatFlag, Account account, int uid) { if (account == null) { // If the account is null, it means to check for all accounts hence skip the check here. return true; } if (checkCompatFlag && !CompatChanges.isChangeEnabled(ACCOUNT_ACCESS_CHECK_CHANGE_ID, uid)) { return true; } final long identityToken = clearCallingIdentity(); try { return mAccountManagerInternal.hasAccountAccess(account, uid); } finally { restoreCallingIdentity(identityToken); } } private static int normalizeSyncable(int syncable) { if (syncable > 0) { return SyncStorageEngine.AuthorityInfo.SYNCABLE; Loading Loading
services/core/java/com/android/server/content/ContentService.java +86 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.content.PermissionChecker.PERMISSION_GRANTED; import android.Manifest; import android.accounts.Account; import android.accounts.AccountManagerInternal; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; Loading @@ -28,7 +29,10 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.compat.CompatChanges; import android.app.job.JobInfo; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; Loading Loading @@ -106,6 +110,13 @@ public final class ContentService extends IContentService.Stub { */ private static final long BACKGROUND_OBSERVER_DELAY = 10 * DateUtils.SECOND_IN_MILLIS; /** * Enables checking for account access for the calling uid on all sync-related APIs. */ @ChangeId @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2) public static final long ACCOUNT_ACCESS_CHECK_CHANGE_ID = 201794303L; public static class Lifecycle extends SystemService { private ContentService mService; Loading Loading @@ -157,6 +168,8 @@ public final class ContentService extends IContentService.Stub { private SyncManager mSyncManager = null; private final Object mSyncManagerLock = new Object(); private final AccountManagerInternal mAccountManagerInternal; private static final BinderDeathDispatcher<IContentObserver> sObserverDeathDispatcher = new BinderDeathDispatcher<>(); Loading Loading @@ -317,6 +330,8 @@ public final class ContentService extends IContentService.Stub { localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED); mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL, localeFilter, null, null); mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class); } void onBootPhase(int phase) { Loading Loading @@ -593,6 +608,10 @@ public final class ContentService extends IContentService.Stub { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); if (!hasAccountAccess(true, account, callingUid)) { return; } validateExtras(callingUid, extras); final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras); Loading Loading @@ -642,11 +661,14 @@ public final class ContentService extends IContentService.Stub { @Override public void syncAsUser(SyncRequest request, int userId, String callingPackage) { enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); if (!hasAccountAccess(true, request.getAccount(), callingUid)) { return; } final Bundle extras = request.getBundle(); validateExtras(callingUid, extras); final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras); Loading Loading @@ -853,6 +875,9 @@ public final class ContentService extends IContentService.Stub { "no permission to read the sync settings for user " + userId); mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, "no permission to read the sync settings"); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return false; } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -882,8 +907,13 @@ public final class ContentService extends IContentService.Stub { "no permission to write the sync settings"); enforceCrossUserPermission(userId, "no permission to modify the sync settings for user " + userId); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); if (!hasAccountAccess(true, account, callingUid)) { return; } final int syncExemptionFlag = getSyncExemptionForCaller(callingUid); final long identityToken = clearCallingIdentity(); Loading Loading @@ -912,7 +942,11 @@ public final class ContentService extends IContentService.Stub { mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, "no permission to write the sync settings"); validateExtras(Binder.getCallingUid(), extras); final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return; } validateExtras(callingUid, extras); int userId = UserHandle.getCallingUserId(); Loading Loading @@ -942,9 +976,11 @@ public final class ContentService extends IContentService.Stub { mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, "no permission to write the sync settings"); validateExtras(Binder.getCallingUid(), extras); final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return; } validateExtras(callingUid, extras); int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); Loading @@ -969,6 +1005,9 @@ public final class ContentService extends IContentService.Stub { } mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, "no permission to read the sync settings"); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return new ArrayList<>(); // return a new empty list for consistent behavior } int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); Loading @@ -995,6 +1034,9 @@ public final class ContentService extends IContentService.Stub { "no permission to read the sync settings for user " + userId); mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, "no permission to read the sync settings"); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; // to keep behavior consistent } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1031,6 +1073,9 @@ public final class ContentService extends IContentService.Stub { syncable = normalizeSyncable(syncable); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); if (!hasAccountAccess(true, account, callingUid)) { return; } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1103,6 +1148,10 @@ public final class ContentService extends IContentService.Stub { public boolean isSyncActive(Account account, String authority, ComponentName cname) { mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, "no permission to read the sync stats"); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return false; } int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1165,6 +1214,9 @@ public final class ContentService extends IContentService.Stub { "no permission to read the sync stats for user " + userId); mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, "no permission to read the sync stats"); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return null; } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1196,6 +1248,10 @@ public final class ContentService extends IContentService.Stub { "no permission to read the sync stats"); enforceCrossUserPermission(userId, "no permission to retrieve the sync settings for user " + userId); if (!hasAccountAccess(true, account, Binder.getCallingUid())) { return false; } final long identityToken = clearCallingIdentity(); SyncManager syncManager = getSyncManager(); if (syncManager == null) return false; Loading Loading @@ -1405,6 +1461,32 @@ public final class ContentService extends IContentService.Stub { Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); } /** * Checks to see if the given account is accessible by the provided uid. * * @param checkCompatFlag whether to check if the ACCOUNT_ACCESS_CHECK_CHANGE_ID flag is enabled * @param account the account trying to be accessed * @param uid the uid trying to access the account * @return {@code true} if the account is accessible by the given uid, {@code false} otherwise */ private boolean hasAccountAccess(boolean checkCompatFlag, Account account, int uid) { if (account == null) { // If the account is null, it means to check for all accounts hence skip the check here. return true; } if (checkCompatFlag && !CompatChanges.isChangeEnabled(ACCOUNT_ACCESS_CHECK_CHANGE_ID, uid)) { return true; } final long identityToken = clearCallingIdentity(); try { return mAccountManagerInternal.hasAccountAccess(account, uid); } finally { restoreCallingIdentity(identityToken); } } private static int normalizeSyncable(int syncable) { if (syncable > 0) { return SyncStorageEngine.AuthorityInfo.SYNCABLE; Loading