DO NOT MERGE Redact Account info from getCurrentSyncs

BUG:26094635
If the caller to ContentResolver#getCurrentSyncs does not hold the
GET_ACCOUNTS permission, return a SyncInfo object that does not
contain any Account information.

Change-Id: I5628ebe1f56c8e3f784aaf1b3281e6b829d19314
(cherry picked from commit b63057e698)
This commit is contained in:
Matthew Williams
2016-01-19 23:04:04 +00:00
parent 2f137b7705
commit a5cafd2a93
3 changed files with 61 additions and 6 deletions

View File

@@ -25,6 +25,13 @@ import android.os.Parcelable.Creator;
* Information about the sync operation that is currently underway.
*/
public class SyncInfo implements Parcelable {
/**
* Used when the caller receiving this object doesn't have permission to access the accounts
* on device.
* @See Manifest.permission.GET_ACCOUNTS
*/
private static final Account REDACTED_ACCOUNT = new Account("*****", "*****");
/** @hide */
public final int authorityId;
@@ -45,6 +52,17 @@ public class SyncInfo implements Parcelable {
*/
public final long startTime;
/**
* Creates a SyncInfo object with an unusable Account. Used when the caller receiving this
* object doesn't have access to the accounts on the device.
* @See Manifest.permission.GET_ACCOUNTS
* @hide
*/
public static SyncInfo createAccountRedacted(
int authorityId, String authority, long startTime) {
return new SyncInfo(authorityId, REDACTED_ACCOUNT, authority, startTime);
}
/** @hide */
public SyncInfo(int authorityId, Account account, String authority,
long startTime) {

View File

@@ -28,6 +28,7 @@ import android.content.SyncAdapterType;
import android.content.SyncInfo;
import android.content.SyncRequest;
import android.content.SyncStatusInfo;
import android.content.pm.PackageManager;
import android.database.IContentObserver;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
@@ -654,13 +655,26 @@ public final class ContentService extends IContentService.Stub {
}
public List<SyncInfo> getCurrentSyncs() {
return getCurrentSyncsAsUser(UserHandle.getCallingUserId());
}
/**
* If the user id supplied is different to the calling user, the caller must hold the
* INTERACT_ACROSS_USERS_FULL permission.
*/
public List<SyncInfo> getCurrentSyncsAsUser(int userId) {
enforceCrossUserPermission(userId,
"no permission to read the sync settings for user " + userId);
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
int userId = UserHandle.getCallingUserId();
final boolean canAccessAccounts =
mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
== PackageManager.PERMISSION_GRANTED;
long identityToken = clearCallingIdentity();
try {
return getSyncManager().getSyncStorageEngine().getCurrentSyncsCopy(userId);
return getSyncManager().getSyncStorageEngine()
.getCurrentSyncsCopy(userId, canAccessAccounts);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -734,6 +748,21 @@ public final class ContentService extends IContentService.Stub {
return service;
}
/**
* Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
* permission, if the userHandle is not for the caller.
*
* @param userHandle the user handle of the user we want to act on behalf of.
* @param message the message to log on security exception.
*/
private void enforceCrossUserPermission(int userHandle, String message) {
final int callingUser = UserHandle.getCallingUserId();
if (callingUser != userHandle) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
}
}
/**
* Hide this class since it is not part of api,
* but current unittest framework requires it to be public

View File

@@ -1306,15 +1306,23 @@ public class SyncStorageEngine extends Handler {
}
/**
* @return a copy of the current syncs data structure. Will not return
* null.
* @param userId Id of user to return current sync info.
* @param canAccessAccounts Determines whether to redact Account information from the result.
* @return a copy of the current syncs data structure. Will not return null.
*/
public List<SyncInfo> getCurrentSyncsCopy(int userId) {
public List<SyncInfo> getCurrentSyncsCopy(int userId, boolean canAccessAccounts) {
synchronized (mAuthorities) {
final List<SyncInfo> syncs = getCurrentSyncsLocked(userId);
final List<SyncInfo> syncsCopy = new ArrayList<SyncInfo>();
for (SyncInfo sync : syncs) {
syncsCopy.add(new SyncInfo(sync));
SyncInfo copy;
if (!canAccessAccounts) {
copy = SyncInfo.createAccountRedacted(
sync.authorityId, sync.authority, sync.startTime);
} else {
copy = new SyncInfo(sync);
}
syncsCopy.add(copy);
}
return syncsCopy;
}