Loading services/core/java/com/android/server/content/ContentService.java +94 −11 Original line number Diff line number Diff line Loading @@ -119,6 +119,13 @@ public final class ContentService extends IContentService.Stub { @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2) public static final long ACCOUNT_ACCESS_CHECK_CHANGE_ID = 201794303L; /** * Enables checking for authority access for the calling uid on all sync-related APIs. */ @ChangeId @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU) public static final long AUTHORITY_ACCESS_CHECK_CHANGE_ID = 207133734L; public static class Lifecycle extends SystemService { private ContentService mService; Loading Loading @@ -608,6 +615,9 @@ public final class ContentService extends IContentService.Stub { if (!hasAccountAccess(true, account, callingUid)) { return; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return; } validateExtras(callingUid, extras); final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras); Loading Loading @@ -661,6 +671,9 @@ public final class ContentService extends IContentService.Stub { if (!hasAccountAccess(true, request.getAccount(), callingUid)) { return; } if (!hasAuthorityAccess(request.getProvider(), callingUid, userId)) { return; } final Bundle extras = request.getBundle(); validateExtras(callingUid, extras); Loading Loading @@ -863,7 +876,12 @@ 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())) { final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return false; } if (!hasAuthorityAccess(providerName, callingUid, userId)) { return false; } Loading Loading @@ -897,6 +915,9 @@ public final class ContentService extends IContentService.Stub { if (!hasAccountAccess(true, account, callingUid)) { return; } if (!hasAuthorityAccess(providerName, callingUid, userId)) { return; } final int syncExemptionFlag = getSyncExemptionForCaller(callingUid); Loading Loading @@ -924,16 +945,19 @@ public final class ContentService extends IContentService.Stub { "no permission to write the sync settings"); final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getCallingUserId(); if (!hasAccountAccess(true, account, callingUid)) { return; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return; } validateExtras(callingUid, extras); pollFrequency = clampPeriod(pollFrequency); long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency); int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); try { SyncStorageEngine.EndPoint info = Loading @@ -958,13 +982,16 @@ public final class ContentService extends IContentService.Stub { "no permission to write the sync settings"); final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getCallingUserId(); if (!hasAccountAccess(true, account, callingUid)) { return; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return; } validateExtras(callingUid, extras); int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); try { getSyncManager().removePeriodicSync( Loading @@ -986,11 +1013,16 @@ 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())) { final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getCallingUserId(); if (!hasAccountAccess(true, account, callingUid)) { return new ArrayList<>(); // return a new empty list for consistent behavior } if (!hasAuthorityAccess(providerName, callingUid, userId)) { return new ArrayList<>(); } int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); try { return getSyncManager().getPeriodicSyncs( Loading @@ -1015,9 +1047,14 @@ 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())) { final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; // to keep behavior consistent } if (!hasAuthorityAccess(providerName, callingUid, userId)) { return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1052,6 +1089,9 @@ public final class ContentService extends IContentService.Stub { if (!hasAccountAccess(true, account, callingUid)) { return; } if (!hasAuthorityAccess(providerName, callingUid, userId)) { return; } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1114,11 +1154,16 @@ 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())) { final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getCallingUserId(); if (!hasAccountAccess(true, account, callingUid)) { return false; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return false; } int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); try { return getSyncManager().getSyncStorageEngine().isSyncActive( Loading Loading @@ -1147,13 +1192,17 @@ public final class ContentService extends IContentService.Stub { final boolean canAccessAccounts = mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS) == PackageManager.PERMISSION_GRANTED; final List<SyncInfo> results; final int callingUid = Binder.getCallingUid(); final long identityToken = clearCallingIdentity(); try { return getSyncManager().getSyncStorageEngine() results = getSyncManager().getSyncStorageEngine() .getCurrentSyncsCopy(userId, canAccessAccounts); } finally { restoreCallingIdentity(identityToken); } results.removeIf(i -> !hasAuthorityAccess(i.authority, callingUid, userId)); return results; } @Override Loading @@ -1177,7 +1226,12 @@ 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())) { final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return null; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return null; } Loading Loading @@ -1207,7 +1261,12 @@ 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())) { final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return false; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return false; } Loading Loading @@ -1441,6 +1500,30 @@ public final class ContentService extends IContentService.Stub { } } /** * Checks to see if the given authority is accessible by the caller. * * @param authority the authority to be accessed * @param uid the uid trying to access the authority * @param userId the user id for which to access the authority * @return {@code true} if the authority is accessible by the caller, {@code false} otherwise */ private boolean hasAuthorityAccess(@Nullable String authority, int uid, @UserIdInt int userId) { if (TextUtils.isEmpty(authority)) { return true; } if (!CompatChanges.isChangeEnabled(AUTHORITY_ACCESS_CHECK_CHANGE_ID, uid)) { return true; } // Since #getSyncAdapterPackagesForAuthorityAsUser would filter out the packages // that aren't visible to the callers, using this to check if the given authority // is accessible by the callers. final String[] syncAdapterPackages = getSyncAdapterPackagesForAuthorityAsUser(authority, userId); return !ArrayUtils.isEmpty(syncAdapterPackages); } private static int normalizeSyncable(int syncable) { if (syncable > 0) { return SyncStorageEngine.AuthorityInfo.SYNCABLE; Loading Loading
services/core/java/com/android/server/content/ContentService.java +94 −11 Original line number Diff line number Diff line Loading @@ -119,6 +119,13 @@ public final class ContentService extends IContentService.Stub { @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2) public static final long ACCOUNT_ACCESS_CHECK_CHANGE_ID = 201794303L; /** * Enables checking for authority access for the calling uid on all sync-related APIs. */ @ChangeId @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU) public static final long AUTHORITY_ACCESS_CHECK_CHANGE_ID = 207133734L; public static class Lifecycle extends SystemService { private ContentService mService; Loading Loading @@ -608,6 +615,9 @@ public final class ContentService extends IContentService.Stub { if (!hasAccountAccess(true, account, callingUid)) { return; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return; } validateExtras(callingUid, extras); final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras); Loading Loading @@ -661,6 +671,9 @@ public final class ContentService extends IContentService.Stub { if (!hasAccountAccess(true, request.getAccount(), callingUid)) { return; } if (!hasAuthorityAccess(request.getProvider(), callingUid, userId)) { return; } final Bundle extras = request.getBundle(); validateExtras(callingUid, extras); Loading Loading @@ -863,7 +876,12 @@ 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())) { final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return false; } if (!hasAuthorityAccess(providerName, callingUid, userId)) { return false; } Loading Loading @@ -897,6 +915,9 @@ public final class ContentService extends IContentService.Stub { if (!hasAccountAccess(true, account, callingUid)) { return; } if (!hasAuthorityAccess(providerName, callingUid, userId)) { return; } final int syncExemptionFlag = getSyncExemptionForCaller(callingUid); Loading Loading @@ -924,16 +945,19 @@ public final class ContentService extends IContentService.Stub { "no permission to write the sync settings"); final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getCallingUserId(); if (!hasAccountAccess(true, account, callingUid)) { return; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return; } validateExtras(callingUid, extras); pollFrequency = clampPeriod(pollFrequency); long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency); int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); try { SyncStorageEngine.EndPoint info = Loading @@ -958,13 +982,16 @@ public final class ContentService extends IContentService.Stub { "no permission to write the sync settings"); final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getCallingUserId(); if (!hasAccountAccess(true, account, callingUid)) { return; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return; } validateExtras(callingUid, extras); int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); try { getSyncManager().removePeriodicSync( Loading @@ -986,11 +1013,16 @@ 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())) { final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getCallingUserId(); if (!hasAccountAccess(true, account, callingUid)) { return new ArrayList<>(); // return a new empty list for consistent behavior } if (!hasAuthorityAccess(providerName, callingUid, userId)) { return new ArrayList<>(); } int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); try { return getSyncManager().getPeriodicSyncs( Loading @@ -1015,9 +1047,14 @@ 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())) { final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; // to keep behavior consistent } if (!hasAuthorityAccess(providerName, callingUid, userId)) { return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1052,6 +1089,9 @@ public final class ContentService extends IContentService.Stub { if (!hasAccountAccess(true, account, callingUid)) { return; } if (!hasAuthorityAccess(providerName, callingUid, userId)) { return; } final long identityToken = clearCallingIdentity(); try { Loading Loading @@ -1114,11 +1154,16 @@ 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())) { final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getCallingUserId(); if (!hasAccountAccess(true, account, callingUid)) { return false; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return false; } int userId = UserHandle.getCallingUserId(); final long identityToken = clearCallingIdentity(); try { return getSyncManager().getSyncStorageEngine().isSyncActive( Loading Loading @@ -1147,13 +1192,17 @@ public final class ContentService extends IContentService.Stub { final boolean canAccessAccounts = mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS) == PackageManager.PERMISSION_GRANTED; final List<SyncInfo> results; final int callingUid = Binder.getCallingUid(); final long identityToken = clearCallingIdentity(); try { return getSyncManager().getSyncStorageEngine() results = getSyncManager().getSyncStorageEngine() .getCurrentSyncsCopy(userId, canAccessAccounts); } finally { restoreCallingIdentity(identityToken); } results.removeIf(i -> !hasAuthorityAccess(i.authority, callingUid, userId)); return results; } @Override Loading @@ -1177,7 +1226,12 @@ 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())) { final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return null; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return null; } Loading Loading @@ -1207,7 +1261,12 @@ 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())) { final int callingUid = Binder.getCallingUid(); if (!hasAccountAccess(true, account, callingUid)) { return false; } if (!hasAuthorityAccess(authority, callingUid, userId)) { return false; } Loading Loading @@ -1441,6 +1500,30 @@ public final class ContentService extends IContentService.Stub { } } /** * Checks to see if the given authority is accessible by the caller. * * @param authority the authority to be accessed * @param uid the uid trying to access the authority * @param userId the user id for which to access the authority * @return {@code true} if the authority is accessible by the caller, {@code false} otherwise */ private boolean hasAuthorityAccess(@Nullable String authority, int uid, @UserIdInt int userId) { if (TextUtils.isEmpty(authority)) { return true; } if (!CompatChanges.isChangeEnabled(AUTHORITY_ACCESS_CHECK_CHANGE_ID, uid)) { return true; } // Since #getSyncAdapterPackagesForAuthorityAsUser would filter out the packages // that aren't visible to the callers, using this to check if the given authority // is accessible by the callers. final String[] syncAdapterPackages = getSyncAdapterPackagesForAuthorityAsUser(authority, userId); return !ArrayUtils.isEmpty(syncAdapterPackages); } private static int normalizeSyncable(int syncable) { if (syncable > 0) { return SyncStorageEngine.AuthorityInfo.SYNCABLE; Loading