Commit e07acb9f authored by Ye Wen's avatar Ye Wen
Browse files

Make CREATOR columns read-only and auto set them in provider

- If an app (not SYSTEM or PHONE) tries to set CREATOR column when
inserting a message, it will be silently overridden by the true pacakge
name of the caller. Or if it tries to update the column, it will be
sliently dropped.
- Also fixed some PII issues

b/18393308

Change-Id: I4ac739b9a6cb78797f006f17c0eed3eeb64cc65e
parent 89bfa753
......@@ -28,6 +28,7 @@ import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Binder;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
......@@ -35,10 +36,11 @@ import android.provider.BaseColumns;
import android.provider.Telephony;
import android.provider.Telephony.CanonicalAddressesColumns;
import android.provider.Telephony.Mms;
import android.provider.Telephony.MmsSms;
import android.provider.Telephony.Mms.Addr;
import android.provider.Telephony.Mms.Part;
import android.provider.Telephony.Mms.Rate;
import android.provider.Telephony.MmsSms;
import android.provider.Telephony.Threads;
import android.text.TextUtils;
import android.util.Log;
......@@ -49,8 +51,6 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import android.provider.Telephony.Threads;
/**
* The class to provide base facility to access MMS related content,
* which is stored in a SQLite database and in the file system.
......@@ -279,6 +279,7 @@ public class MmsProvider extends ContentProvider {
if (values != null && values.containsKey(Part._DATA)) {
return null;
}
final int callerUid = Binder.getCallingUid();
int msgBox = Mms.MESSAGE_BOX_ALL;
boolean notify = true;
......@@ -371,19 +372,27 @@ public class MmsProvider extends ContentProvider {
finalValues.put(Mms.THREAD_ID, Threads.getOrCreateThreadId(getContext(), address));
}
if (ProviderUtil.shouldSetCreator(finalValues, callerUid)) {
// Only SYSTEM or PHONE can set CREATOR
// If caller is not SYSTEM or PHONE, or SYSTEM or PHONE does not set CREATOR
// set CREATOR using the truth on caller.
// Note: Inferring package name from UID may include unrelated package names
finalValues.put(Telephony.Mms.CREATOR,
ProviderUtil.getPackageNamesByUid(getContext(), callerUid));
}
if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Log.e(TAG, "MmsProvider.insert: failed! " + finalValues);
Log.e(TAG, "MmsProvider.insert: failed!");
return null;
}
res = Uri.parse(res + "/" + rowId);
} else if (table.equals(TABLE_ADDR)) {
finalValues = new ContentValues(values);
finalValues.put(Addr.MSG_ID, uri.getPathSegments().get(0));
if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Log.e(TAG, "Failed to insert address: " + finalValues);
Log.e(TAG, "Failed to insert address");
return null;
}
......@@ -452,7 +461,7 @@ public class MmsProvider extends ContentProvider {
}
if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Log.e(TAG, "MmsProvider.insert: failed! " + finalValues);
Log.e(TAG, "MmsProvider.insert: failed!");
return null;
}
......@@ -504,7 +513,7 @@ public class MmsProvider extends ContentProvider {
}
if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Log.e(TAG, "MmsProvider.insert: failed! " + finalValues);
Log.e(TAG, "MmsProvider.insert: failed!");
return null;
}
res = Uri.parse(res + "/drm/" + rowId);
......@@ -697,6 +706,7 @@ public class MmsProvider extends ContentProvider {
if (values != null && values.containsKey(Part._DATA)) {
return 0;
}
final int callerUid = Binder.getCallingUid();
int match = sURLMatcher.match(uri);
if (LOCAL_LOGV) {
Log.v(TAG, "Update uri=" + uri + ", match=" + match);
......@@ -749,6 +759,12 @@ public class MmsProvider extends ContentProvider {
if (table.equals(TABLE_PDU)) {
// Filter keys that we don't support yet.
filterUnsupportedKeys(values);
if (ProviderUtil.shouldRemoveCreator(values, callerUid)) {
// CREATOR should not be changed by non-SYSTEM/PHONE apps
Log.w(TAG, ProviderUtil.getPackageNamesByUid(getContext(), callerUid) +
" tries to update CREATOR");
values.remove(Mms.CREATOR);
}
finalValues = new ContentValues(values);
if (msgId != null) {
......
......@@ -16,11 +16,6 @@
package com.android.providers.telephony;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import android.app.AppOpsManager;
import android.content.ContentProvider;
import android.content.ContentValues;
......@@ -32,22 +27,27 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Binder;
import android.os.UserHandle;
import android.provider.BaseColumns;
import android.provider.Telephony;
import android.provider.Telephony.CanonicalAddressesColumns;
import android.provider.Telephony.Mms;
import android.provider.Telephony.MmsSms;
import android.provider.Telephony.MmsSms.PendingMessages;
import android.provider.Telephony.Sms;
import android.provider.Telephony.Sms.Conversations;
import android.provider.Telephony.Threads;
import android.provider.Telephony.ThreadsColumns;
import android.provider.Telephony.MmsSms.PendingMessages;
import android.provider.Telephony.Sms.Conversations;
import android.text.TextUtils;
import android.util.Log;
import com.google.android.mms.pdu.PduHeaders;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* This class provides the ability to query the MMS and SMS databases
* at the same time, mixing messages from both in a single thread
......@@ -1240,13 +1240,14 @@ public class MmsSmsProvider extends ContentProvider {
@Override
public int update(Uri uri, ContentValues values,
String selection, String[] selectionArgs) {
final int callerUid = Binder.getCallingUid();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int affectedRows = 0;
switch(URI_MATCHER.match(uri)) {
case URI_CONVERSATIONS_MESSAGES:
String threadIdString = uri.getPathSegments().get(1);
affectedRows = updateConversation(threadIdString, values,
selection, selectionArgs);
selection, selectionArgs, callerUid);
break;
case URI_PENDING_MSG:
......@@ -1286,12 +1287,22 @@ public class MmsSmsProvider extends ContentProvider {
private int updateConversation(
String threadIdString, ContentValues values, String selection,
String[] selectionArgs) {
String[] selectionArgs, int callerUid) {
try {
Long.parseLong(threadIdString);
} catch (NumberFormatException exception) {
Log.e(LOG_TAG, "Thread ID must be a Long.");
return 0;
}
if (ProviderUtil.shouldRemoveCreator(values, callerUid)) {
// CREATOR should not be changed by non-SYSTEM/PHONE apps
Log.w(LOG_TAG, ProviderUtil.getPackageNamesByUid(getContext(), callerUid) +
" tries to update CREATOR");
// Sms.CREATOR and Mms.CREATOR are same. But let's do this
// twice in case the names may differ in the future
values.remove(Sms.CREATOR);
values.remove(Mms.CREATOR);
}
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
......
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.providers.telephony;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Process;
import android.provider.Telephony;
import android.text.TextUtils;
/**
* Helpers
*/
public class ProviderUtil {
/**
* Get space separated package names associated with a UID
*
* @param context The context to use
* @param uid The UID to look up
* @return The space separated list of package names for UID
*/
public static String getPackageNamesByUid(Context context, int uid) {
final PackageManager pm = context.getPackageManager();
final String[] packageNames = pm.getPackagesForUid(uid);
if (packageNames != null) {
final StringBuilder sb = new StringBuilder();
for (String name : packageNames) {
if (!TextUtils.isEmpty(name)) {
if (sb.length() > 0) {
sb.append(' ');
}
sb.append(name);
}
}
return sb.toString();
}
return null;
}
/**
* Whether should set CREATOR for an insertion
*
* @param values The content of the message
* @param uid The caller UID of the insertion
* @return true if we should set CREATOR, false otherwise
*/
public static boolean shouldSetCreator(ContentValues values, int uid) {
return (uid != Process.SYSTEM_UID && uid != Process.PHONE_UID) ||
(!values.containsKey(Telephony.Sms.CREATOR) &&
!values.containsKey(Telephony.Mms.CREATOR));
}
/**
* Whether should remove CREATOR for an update
*
* @param values The content of the message
* @param uid The caller UID of the update
* @return true if we should remove CREATOR, false otherwise
*/
public static boolean shouldRemoveCreator(ContentValues values, int uid) {
return (uid != Process.SYSTEM_UID && uid != Process.PHONE_UID) &&
(values.containsKey(Telephony.Sms.CREATOR) ||
values.containsKey(Telephony.Mms.CREATOR));
}
}
......@@ -20,7 +20,6 @@ import android.app.AppOpsManager;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.DatabaseUtils;
......@@ -33,7 +32,6 @@ import android.os.Binder;
import android.os.UserHandle;
import android.provider.Contacts;
import android.provider.Telephony;
import android.provider.Telephony.Mms;
import android.provider.Telephony.MmsSms;
import android.provider.Telephony.Sms;
import android.provider.Telephony.TextBasedSmsColumns;
......@@ -357,15 +355,16 @@ public class SmsProvider extends ContentProvider {
@Override
public Uri insert(Uri url, ContentValues initialValues) {
final int callerUid = Binder.getCallingUid();
long token = Binder.clearCallingIdentity();
try {
return insertInner(url, initialValues);
return insertInner(url, initialValues, callerUid);
} finally {
Binder.restoreCallingIdentity(token);
}
}
private Uri insertInner(Uri url, ContentValues initialValues) {
private Uri insertInner(Uri url, ContentValues initialValues, int callerUid) {
ContentValues values;
long rowID;
int type = Sms.MESSAGE_TYPE_ALL;
......@@ -508,6 +507,13 @@ public class SmsProvider extends ContentProvider {
// Mark all non-inbox messages read.
values.put(Sms.READ, ONE);
}
if (ProviderUtil.shouldSetCreator(values, callerUid)) {
// Only SYSTEM or PHONE can set CREATOR
// If caller is not SYSTEM or PHONE, or SYSTEM or PHONE does not set CREATOR
// set CREATOR using the truth on caller.
// Note: Inferring package name from UID may include unrelated package names
values.put(Sms.CREATOR, ProviderUtil.getPackageNamesByUid(getContext(), callerUid));
}
} else {
if (initialValues == null) {
values = new ContentValues(1);
......@@ -541,7 +547,7 @@ public class SmsProvider extends ContentProvider {
notifyChange(uri);
return uri;
} else {
Log.e(TAG,"insert: failed! " + values.toString());
Log.e(TAG,"insert: failed!");
}
return null;
......@@ -636,6 +642,7 @@ public class SmsProvider extends ContentProvider {
@Override
public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
final int callerUid = Binder.getCallingUid();
int count = 0;
String table = TABLE_SMS;
String extraWhere = null;
......@@ -695,6 +702,13 @@ public class SmsProvider extends ContentProvider {
"URI " + url + " not supported");
}
if (table.equals(TABLE_SMS) && ProviderUtil.shouldRemoveCreator(values, callerUid)) {
// CREATOR should not be changed by non-SYSTEM/PHONE apps
Log.w(TAG, ProviderUtil.getPackageNamesByUid(getContext(), callerUid) +
" tries to update CREATOR");
values.remove(Sms.CREATOR);
}
where = DatabaseUtils.concatenateWhere(where, extraWhere);
count = db.update(table, values, where, whereArgs);
......
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