Commit 019a7eab authored by Robin Lee's avatar Robin Lee Committed by Vasyl Gello

Pass userId through to singleton ContentProviders

System content providers like SettingsProvider run as singleUser but
on receipt of a call make decisions based on the calling user ID.

This is right up until the caller is a system service or a cross-user-
-aware app like Settings, where putStringForUser etc. provide a
workaround for most settings but not for the few files SettingsProvider
exposes.

Change-Id: I90060c9c13e274edd71f8a16ab3a026a58b98e3e
parent b3f380d3
......@@ -208,7 +208,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
uri = maybeGetUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
// The caller has no access to the data, so return an empty cursor with
// the columns in the requested order. The caller may ask for an invalid
......@@ -247,7 +247,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
@Override
public String getType(Uri uri) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
uri = maybeGetUriWithoutUserId(uri);
return ContentProvider.this.getType(uri);
}
......@@ -255,7 +255,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
validateIncomingUri(uri);
int userId = getUserIdFromUri(uri);
uri = getUriWithoutUserId(uri);
uri = maybeGetUriWithoutUserId(uri);
if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return rejectInsert(uri, initialValues);
}
......@@ -270,7 +270,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
@Override
public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
uri = maybeGetUriWithoutUserId(uri);
if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
......@@ -331,7 +331,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
@Override
public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
uri = maybeGetUriWithoutUserId(uri);
if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
......@@ -347,7 +347,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public int update(String callingPkg, Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
uri = maybeGetUriWithoutUserId(uri);
if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
......@@ -364,7 +364,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal,
IBinder callerToken) throws FileNotFoundException {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
uri = maybeGetUriWithoutUserId(uri);
enforceFilePermission(callingPkg, uri, mode, callerToken);
final String original = setCallingPackage(callingPkg);
try {
......@@ -380,7 +380,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
uri = maybeGetUriWithoutUserId(uri);
enforceFilePermission(callingPkg, uri, mode, null);
final String original = setCallingPackage(callingPkg);
try {
......@@ -406,7 +406,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
@Override
public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
uri = maybeGetUriWithoutUserId(uri);
return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter);
}
......@@ -415,7 +415,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
Bundle.setDefusable(opts, true);
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
uri = maybeGetUriWithoutUserId(uri);
enforceFilePermission(callingPkg, uri, "r", null);
final String original = setCallingPackage(callingPkg);
try {
......@@ -1846,10 +1846,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
/** @hide */
private void validateIncomingUri(Uri uri) throws SecurityException {
String auth = uri.getAuthority();
int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId()) {
throw new SecurityException("trying to query a ContentProvider in user "
+ mContext.getUserId() + " with a uri belonging to user " + userId);
if (!mSingleUser) {
int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId()) {
throw new SecurityException("trying to query a ContentProvider in user "
+ mContext.getUserId() + " with a uri belonging to user " + userId);
}
}
if (!matchesOurAuthorities(getAuthorityWithoutUserId(auth))) {
String message = "The authority of the uri " + uri + " does not match the one of the "
......@@ -1863,6 +1865,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
}
/** @hide */
private Uri maybeGetUriWithoutUserId(Uri uri) {
if (mSingleUser) {
return uri;
}
return getUriWithoutUserId(uri);
}
/** @hide */
public static int getUserIdFromAuthority(String auth, int defaultUserId) {
if (auth == null) return defaultUserId;
......
......@@ -516,6 +516,13 @@ public class SettingsProvider extends ContentProvider {
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
final int userId = getUserIdFromUri(uri, UserHandle.getCallingUserId());
if (userId != UserHandle.getCallingUserId()) {
getContext().enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS,
"Access files from the settings of another user");
}
uri = ContentProvider.getUriWithoutUserId(uri);
final String cacheName;
if (Settings.System.RINGTONE_CACHE_URI.equals(uri)) {
cacheName = Settings.System.RINGTONE_CACHE;
......@@ -528,8 +535,7 @@ public class SettingsProvider extends ContentProvider {
+ "ringtone playback is available through android.media.Ringtone");
}
final File cacheFile = new File(
getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
final File cacheFile = new File(getRingtoneCacheDir(userId), cacheName);
return ParcelFileDescriptor.open(cacheFile, ParcelFileDescriptor.parseMode(mode));
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment