aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-11 02:16:53 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-11 02:16:53 +0000
commit00d87c8b43518e63bb7e96e200de483f5adfc239 (patch)
treec70d383e0550ea0fcc745fb9110c9edb6aa3b438
parent3bce5a58d0b9697a4a0242cccd5ceccbf3279b25 (diff)
parentd2d03abc6da38a32a45ed3582ba61195db0840cf (diff)
downloadContactsProvider-android12-platform-release.tar.gz
Change-Id: I947f89e6736ae39f921a6a5e9c74a39e57584c48
-rw-r--r--src/com/android/providers/contacts/CallLogProvider.java65
1 files changed, 63 insertions, 2 deletions
diff --git a/src/com/android/providers/contacts/CallLogProvider.java b/src/com/android/providers/contacts/CallLogProvider.java
index 991413eb..589bd041 100644
--- a/src/com/android/providers/contacts/CallLogProvider.java
+++ b/src/com/android/providers/contacts/CallLogProvider.java
@@ -36,6 +36,7 @@ import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
+import android.database.sqlite.SQLiteTokenizer;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -54,6 +55,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
+import android.util.EventLog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ProviderAccessStats;
@@ -81,6 +83,8 @@ import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Locale;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
@@ -432,10 +436,11 @@ public class CallLogProvider extends ContentProvider {
List<String> pathSegments = uri.getPathSegments();
String phoneNumber = pathSegments.size() >= 2 ? pathSegments.get(2) : null;
if (!TextUtils.isEmpty(phoneNumber)) {
- qb.appendWhere("PHONE_NUMBERS_EQUAL(number, ");
- qb.appendWhereEscapeString(phoneNumber);
+ qb.appendWhere("PHONE_NUMBERS_EQUAL(number, ?");
qb.appendWhere(mUseStrictPhoneNumberComparation ? ", 1)"
: ", 0, " + mMinMatch + ")");
+ selectionArgs = copyArrayAndAppendElement(selectionArgs,
+ "'" + phoneNumber + "'");
} else {
qb.appendWhere(Calls.NUMBER_PRESENTATION + "!="
+ Calls.PRESENTATION_ALLOWED);
@@ -457,12 +462,68 @@ public class CallLogProvider extends ContentProvider {
final SQLiteDatabase db = mDbHelper.getReadableDatabase();
final Cursor c = qb.query(db, projection, selectionBuilder.build(), selectionArgs, null,
null, sortOrder, limitClause);
+
+ if (match == CALLS_FILTER && selectionArgs.length > 0) {
+ // throw SE if the user is sending requests that try to bypass voicemail permissions
+ examineEmptyCursorCause(c, selectionArgs[selectionArgs.length - 1]);
+ }
+
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), CallLog.CONTENT_URI);
}
return c;
}
+ /**
+ * Helper method for queryInternal that appends an extra argument to the existing selection
+ * arguments array.
+ *
+ * @param oldSelectionArguments the existing selection argument array in queryInternal
+ * @param phoneNumber the phoneNumber that was passed into queryInternal
+ * @return the new selection argument array with the phoneNumber as the last argument
+ */
+ private String[] copyArrayAndAppendElement(String[] oldSelectionArguments, String phoneNumber) {
+ if (oldSelectionArguments == null) {
+ return new String[]{phoneNumber};
+ }
+ String[] newSelectionArguments = new String[oldSelectionArguments.length + 1];
+ System.arraycopy(oldSelectionArguments, 0, newSelectionArguments, 0,
+ oldSelectionArguments.length);
+ newSelectionArguments[oldSelectionArguments.length] = phoneNumber;
+ return newSelectionArguments;
+ }
+
+ /**
+ * Helper that throws a Security Exception if the Cursor object is empty && the phoneNumber
+ * appears to have SQL.
+ *
+ * @param cursor returned from the query.
+ * @param phoneNumber string to check for SQL.
+ */
+ private void examineEmptyCursorCause(Cursor cursor, String phoneNumber) {
+ // checks if the cursor is empty
+ if ((cursor == null) || !cursor.moveToFirst()) {
+ try {
+ // tokenize the phoneNumber and run each token through a checker
+ SQLiteTokenizer.tokenize(phoneNumber, SQLiteTokenizer.OPTION_NONE,
+ this::enforceStrictPhoneNumber);
+ } catch (IllegalArgumentException e) {
+ EventLog.writeEvent(0x534e4554, "224771921", Binder.getCallingUid(),
+ ("invalid phoneNumber passed to queryInternal"));
+ throw new SecurityException("invalid phoneNumber passed to queryInternal");
+ }
+ }
+ }
+
+ private void enforceStrictPhoneNumber(String token) {
+ boolean isAllowedKeyword = SQLiteTokenizer.isKeyword(token);
+ Set<String> lookupTable = Set.of("UNION", "SELECT", "FROM", "WHERE",
+ "GROUP", "HAVING", "WINDOW", "VALUES", "ORDER", "LIMIT");
+ if (!isAllowedKeyword || lookupTable.contains(token.toUpperCase(Locale.US))) {
+ throw new IllegalArgumentException("Invalid token " + token);
+ }
+ }
+
private void queryForTesting(Uri uri) {
if (!uri.getBooleanQueryParameter(PARAM_KEY_QUERY_FOR_TESTING, false)) {
return;