Restricted view of SMS/MMS providers (2/2)
Only expose sent/received SMS/MMS and non-wap push MMS messages for
non-default SMS apps, preventing non-default SMS apps to interfere
internal states of default SMS app, like stealing wap push to download
or sending outbox message.
b/19348537
Change-Id: Icec639a01ab8f5cd2d1346b76418ec487979295a
diff --git a/src/com/android/providers/telephony/MmsProvider.java b/src/com/android/providers/telephony/MmsProvider.java
index 6b5b29e..710fa43 100644
--- a/src/com/android/providers/telephony/MmsProvider.java
+++ b/src/com/android/providers/telephony/MmsProvider.java
@@ -62,6 +62,7 @@
static final String TABLE_RATE = "rate";
static final String TABLE_DRM = "drm";
static final String TABLE_WORDS = "words";
+ static final String VIEW_PDU_RESTRICTED = "pdu_restricted";
// The name of parts directory. The full dir is "app_parts".
private static final String PARTS_DIR_NAME = "parts";
@@ -73,9 +74,27 @@
return true;
}
+ /**
+ * Return the proper view of "pdu" table for the current access status.
+ *
+ * @param accessRestricted If the access is restricted
+ * @return the table/view name of the mms data
+ */
+ public static String getPduTable(boolean accessRestricted) {
+ return accessRestricted ? VIEW_PDU_RESTRICTED : TABLE_PDU;
+ }
+
@Override
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
+ // First check if a restricted view of the "pdu" table should be used based on the
+ // caller's identity. Only system, phone or the default sms app can have full access
+ // of mms data. For other apps, we present a restricted view which only contains sent
+ // or received messages, without wap pushes.
+ final boolean accessRestricted = ProviderUtil.isAccessRestricted(
+ getContext(), getCallingPackage(), Binder.getCallingUid());
+ final String pduTable = getPduTable(accessRestricted);
+
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
// Generate the body of the query.
@@ -86,29 +105,29 @@
switch (match) {
case MMS_ALL:
- constructQueryForBox(qb, Mms.MESSAGE_BOX_ALL);
+ constructQueryForBox(qb, Mms.MESSAGE_BOX_ALL, pduTable);
break;
case MMS_INBOX:
- constructQueryForBox(qb, Mms.MESSAGE_BOX_INBOX);
+ constructQueryForBox(qb, Mms.MESSAGE_BOX_INBOX, pduTable);
break;
case MMS_SENT:
- constructQueryForBox(qb, Mms.MESSAGE_BOX_SENT);
+ constructQueryForBox(qb, Mms.MESSAGE_BOX_SENT, pduTable);
break;
case MMS_DRAFTS:
- constructQueryForBox(qb, Mms.MESSAGE_BOX_DRAFTS);
+ constructQueryForBox(qb, Mms.MESSAGE_BOX_DRAFTS, pduTable);
break;
case MMS_OUTBOX:
- constructQueryForBox(qb, Mms.MESSAGE_BOX_OUTBOX);
+ constructQueryForBox(qb, Mms.MESSAGE_BOX_OUTBOX, pduTable);
break;
case MMS_ALL_ID:
- qb.setTables(TABLE_PDU);
+ qb.setTables(pduTable);
qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(0));
break;
case MMS_INBOX_ID:
case MMS_SENT_ID:
case MMS_DRAFTS_ID:
case MMS_OUTBOX_ID:
- qb.setTables(TABLE_PDU);
+ qb.setTables(pduTable);
qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(1));
qb.appendWhere(" AND " + Mms.MESSAGE_BOX + "="
+ getMessageBoxByMatch(match));
@@ -155,19 +174,23 @@
OR (msg_id = id3 AND type = 137)
WHERE T.id1 = ?;
*/
- qb.setTables("addr INNER JOIN (SELECT P1._id AS id1, P2._id" +
- " AS id2, P3._id AS id3, ifnull(P2.st, 0) AS" +
- " delivery_status, ifnull(P3.read_status, 0) AS" +
- " read_status FROM pdu P1 INNER JOIN pdu P2 ON" +
- " P1.m_id=P2.m_id AND P2.m_type=134 LEFT JOIN" +
- " pdu P3 ON P1.m_id=P3.m_id AND P3.m_type=136" +
- " UNION SELECT P1._id AS id1, P2._id AS id2, P3._id" +
- " AS id3, ifnull(P2.st, 0) AS delivery_status," +
- " ifnull(P3.read_status, 0) AS read_status FROM" +
- " pdu P1 INNER JOIN pdu P3 ON P1.m_id=P3.m_id AND" +
- " P3.m_type=136 LEFT JOIN pdu P2 ON P1.m_id=P2.m_id" +
- " AND P2.m_type=134) T ON (msg_id=id2 AND type=151)" +
- " OR (msg_id=id3 AND type=137)");
+ qb.setTables(TABLE_ADDR + " INNER JOIN "
+ + "(SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3, "
+ + "ifnull(P2.st, 0) AS delivery_status, "
+ + "ifnull(P3.read_status, 0) AS read_status "
+ + "FROM " + pduTable + " P1 INNER JOIN " + pduTable + " P2 "
+ + "ON P1.m_id=P2.m_id AND P2.m_type=134 "
+ + "LEFT JOIN " + pduTable + " P3 "
+ + "ON P1.m_id=P3.m_id AND P3.m_type=136 "
+ + "UNION "
+ + "SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3, "
+ + "ifnull(P2.st, 0) AS delivery_status, "
+ + "ifnull(P3.read_status, 0) AS read_status "
+ + "FROM " + pduTable + " P1 INNER JOIN " + pduTable + " P3 "
+ + "ON P1.m_id=P3.m_id AND P3.m_type=136 "
+ + "LEFT JOIN " + pduTable + " P2 "
+ + "ON P1.m_id=P2.m_id AND P2.m_type=134) T "
+ + "ON (msg_id=id2 AND type=151) OR (msg_id=id3 AND type=137)");
qb.appendWhere("T.id1 = " + uri.getLastPathSegment());
qb.setDistinct(true);
break;
@@ -178,9 +201,9 @@
WHERE pdu._id = messageId AND addr.type = 151
*/
qb.setTables(TABLE_ADDR + " join " +
- TABLE_PDU + " on pdu._id = addr.msg_id");
- qb.appendWhere("pdu._id = " + uri.getLastPathSegment());
- qb.appendWhere(" AND " + "addr.type = " + PduHeaders.TO);
+ pduTable + " on " + pduTable + "._id = addr.msg_id");
+ qb.appendWhere(pduTable + "._id = " + uri.getLastPathSegment());
+ qb.appendWhere(" AND " + TABLE_ADDR + ".type = " + PduHeaders.TO);
break;
case MMS_SENDING_RATE:
qb.setTables(TABLE_RATE);
@@ -190,7 +213,7 @@
qb.appendWhere(BaseColumns._ID + "=" + uri.getLastPathSegment());
break;
case MMS_THREADS:
- qb.setTables("pdu group by thread_id");
+ qb.setTables(pduTable + " group by thread_id");
break;
default:
Log.e(TAG, "query: invalid request: " + uri);
@@ -199,7 +222,7 @@
String finalSortOrder = null;
if (TextUtils.isEmpty(sortOrder)) {
- if (qb.getTables().equals(TABLE_PDU)) {
+ if (qb.getTables().equals(pduTable)) {
finalSortOrder = Mms.DATE + " DESC";
} else if (qb.getTables().equals(TABLE_PART)) {
finalSortOrder = Part.SEQ;
@@ -223,8 +246,8 @@
return ret;
}
- private void constructQueryForBox(SQLiteQueryBuilder qb, int msgBox) {
- qb.setTables(TABLE_PDU);
+ private void constructQueryForBox(SQLiteQueryBuilder qb, int msgBox, String pduTable) {
+ qb.setTables(pduTable);
if (msgBox != Mms.MESSAGE_BOX_ALL) {
qb.appendWhere(Mms.MESSAGE_BOX + "=" + msgBox);
@@ -282,6 +305,7 @@
return null;
}
final int callerUid = Binder.getCallingUid();
+ final String callerPkg = getCallingPackage();
int msgBox = Mms.MESSAGE_BOX_ALL;
boolean notify = true;
@@ -379,8 +403,7 @@
// 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));
+ finalValues.put(Telephony.Mms.CREATOR, callerPkg);
}
if ((rowId = db.insert(table, null, finalValues)) <= 0) {
@@ -709,6 +732,7 @@
return 0;
}
final int callerUid = Binder.getCallingUid();
+ final String callerPkg = getCallingPackage();
int match = sURLMatcher.match(uri);
if (LOCAL_LOGV) {
Log.v(TAG, "Update uri=" + uri + ", match=" + match);
@@ -763,8 +787,7 @@
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");
+ Log.w(TAG, callerPkg + " tries to update CREATOR");
values.remove(Mms.CREATOR);
}
finalValues = new ContentValues(values);