Fix the remaining holes for access to APN data

Add the following checks for preventing unauthorized access to the APN
username and password fields in the carrier db:
1. Check the query for sensitive fields no matter what URI is being
queried
2. Perform a case-insensitive search for sensitive fields
3. Always check the permission for accessing username/password if any
part of the query contains a subquery (detected via looking for the
"select" token).

Bug: 138802882
Test: CTS
Change-Id: I59b297642d2000dde0a83f77b20112c7382b7ef1
Merged-In: I59b297642d2000dde0a83f77b20112c7382b7ef1
(cherry picked from commit 09a82c2251fe7c79b8e06c470f3f260e3c468ea2)
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index 3f0ea49..0053036 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -110,6 +110,10 @@
     private static final String OTA_UPDATED_APNS_PATH = "misc/apns-conf.xml";
     private static final String OLD_APNS_PATH = "etc/old-apns-conf.xml";
 
+    // Used to check if certain queries contain subqueries that may attempt to access sensitive
+    // fields in the carriers db.
+    private static final String SQL_SELECT_TOKEN = "select";
+
     private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 
     private static final ContentValues s_currentNullMap;
@@ -1841,25 +1845,26 @@
             }
         }
 
-        if (match != URL_SIMINFO) {
-            // Determine if we need to do a check for fields in the selection
-            boolean selectionOrSortContainsSensitiveFields;
-            try {
-                selectionOrSortContainsSensitiveFields = containsSensitiveFields(selection);
-                selectionOrSortContainsSensitiveFields |= containsSensitiveFields(sort);
-            } catch (Exception e) {
-                // Malformed sql, check permission anyway.
-                selectionOrSortContainsSensitiveFields = true;
-            }
+        // Determine if we need to do a check for fields in the selection
+        boolean selectionOrSortContainsSensitiveFields;
+        try {
+            selectionOrSortContainsSensitiveFields = containsSensitiveFields(selection);
+            selectionOrSortContainsSensitiveFields |= containsSensitiveFields(sort);
+        } catch (Exception e) {
+            // Malformed sql, check permission anyway.
+            selectionOrSortContainsSensitiveFields = true;
+        }
 
-            if (selectionOrSortContainsSensitiveFields) {
-                try {
-                    checkPermission();
-                } catch (SecurityException e) {
-                    EventLog.writeEvent(0x534e4554, "124107808", Binder.getCallingUid());
-                    throw e;
-                }
+        if (selectionOrSortContainsSensitiveFields) {
+            try {
+                checkPermission();
+            } catch (SecurityException e) {
+                EventLog.writeEvent(0x534e4554, "124107808", Binder.getCallingUid());
+                throw e;
             }
+        }
+
+        if (match != URL_SIMINFO) {
             if (projectionIn != null) {
                 for (String column : projectionIn) {
                     if (TYPE.equals(column) ||
@@ -1907,9 +1912,10 @@
     private boolean containsSensitiveFields(String sqlStatement) {
         try {
             SqlTokenFinder.findTokens(sqlStatement, s -> {
-                switch (s) {
+                switch (s.toLowerCase()) {
                     case USER:
                     case PASSWORD:
+                    case SQL_SELECT_TOKEN:
                         throw new SecurityException();
                 }
             });