From c0d75ee14d652c9d4406da629f871c068ba25851 Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 26 Jun 2019 16:21:25 -0700 Subject: Handle unrecognized columns and avoid SQL injection Bug:135269669 Test: atest com.android.providers.tv Change-Id: I6445fb22501e8ee2aeb6901b32cb03e971c14211 (cherry picked from commit d817260cae81eee3ea18fe6b8f69c32ba070ea6e) (cherry picked from commit 7b2b1fba39aeb61b67b29cdb8d4780afc817ac2e) --- src/com/android/providers/tv/TvProvider.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/com/android/providers/tv/TvProvider.java b/src/com/android/providers/tv/TvProvider.java index e8543a2..cf16ded 100644 --- a/src/com/android/providers/tv/TvProvider.java +++ b/src/com/android/providers/tv/TvProvider.java @@ -118,7 +118,6 @@ public class TvProvider extends ContentProvider { private static final String OP_UPDATE = "update"; private static final String OP_DELETE = "delete"; - private static final UriMatcher sUriMatcher; private static final int MATCH_CHANNEL = 1; private static final int MATCH_CHANNEL_ID = 2; @@ -1605,9 +1604,15 @@ public class TvProvider extends ContentProvider { } Map columnProjectionMap = new HashMap<>(); for (String columnName : projection) { - // Value NULL will be provided if the requested column does not exist in the database. - columnProjectionMap.put(columnName, - projectionMap.getOrDefault(columnName, "NULL as " + columnName)); + String value = projectionMap.get(columnName); + if (value != null) { + columnProjectionMap.put(columnName, value); + } else { + // Value NULL will be provided if the requested column does not exist in the + // database. + value = "NULL AS " + DatabaseUtils.sqlEscapeString(columnName); + columnProjectionMap.put(columnName, value); + } } return columnProjectionMap; } -- cgit v1.2.3 From b43e5beb795e5f5adf615b1760c75f7d13027d69 Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 26 Jun 2019 16:21:25 -0700 Subject: Handle unrecognized columns and avoid SQL injection Bug:135269669 Test: atest com.android.providers.tv Change-Id: I6445fb22501e8ee2aeb6901b32cb03e971c14211 (cherry picked from commit d817260cae81eee3ea18fe6b8f69c32ba070ea6e) --- src/com/android/providers/tv/TvProvider.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/com/android/providers/tv/TvProvider.java b/src/com/android/providers/tv/TvProvider.java index 01bc833..14d17f6 100644 --- a/src/com/android/providers/tv/TvProvider.java +++ b/src/com/android/providers/tv/TvProvider.java @@ -118,7 +118,6 @@ public class TvProvider extends ContentProvider { private static final String OP_UPDATE = "update"; private static final String OP_DELETE = "delete"; - private static final UriMatcher sUriMatcher; private static final int MATCH_CHANNEL = 1; private static final int MATCH_CHANNEL_ID = 2; @@ -1605,9 +1604,15 @@ public class TvProvider extends ContentProvider { } Map columnProjectionMap = new HashMap<>(); for (String columnName : projection) { - // Value NULL will be provided if the requested column does not exist in the database. - columnProjectionMap.put(columnName, - projectionMap.getOrDefault(columnName, "NULL as " + columnName)); + String value = projectionMap.get(columnName); + if (value != null) { + columnProjectionMap.put(columnName, value); + } else { + // Value NULL will be provided if the requested column does not exist in the + // database. + value = "NULL AS " + DatabaseUtils.sqlEscapeString(columnName); + columnProjectionMap.put(columnName, value); + } } return columnProjectionMap; } -- cgit v1.2.3 From 91fb529f11ccb74cde2460c5d40f03d859e7013d Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 26 Jun 2019 16:21:25 -0700 Subject: Handle unrecognized columns and avoid SQL injection Bug:135269669 Test: atest com.android.providers.tv Change-Id: I6445fb22501e8ee2aeb6901b32cb03e971c14211 (cherry picked from commit d817260cae81eee3ea18fe6b8f69c32ba070ea6e) (cherry picked from commit 7b2b1fba39aeb61b67b29cdb8d4780afc817ac2e) --- src/com/android/providers/tv/TvProvider.java | 13 ++- .../android/providers/tv/TvProviderForTesting.java | 4 + .../providers/tv/UnrecognizedColumnsTest.java | 116 +++++++++++++++++++++ 3 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 tests/src/com/android/providers/tv/UnrecognizedColumnsTest.java diff --git a/src/com/android/providers/tv/TvProvider.java b/src/com/android/providers/tv/TvProvider.java index 76bdf8e..b324ba3 100644 --- a/src/com/android/providers/tv/TvProvider.java +++ b/src/com/android/providers/tv/TvProvider.java @@ -124,7 +124,6 @@ public class TvProvider extends ContentProvider { private static final String OP_UPDATE = "update"; private static final String OP_DELETE = "delete"; - private static final UriMatcher sUriMatcher; private static final int MATCH_CHANNEL = 1; private static final int MATCH_CHANNEL_ID = 2; @@ -1660,9 +1659,15 @@ public class TvProvider extends ContentProvider { } Map columnProjectionMap = new HashMap<>(); for (String columnName : projection) { - // Value NULL will be provided if the requested column does not exist in the database. - columnProjectionMap.put(columnName, - projectionMap.getOrDefault(columnName, "NULL as " + columnName)); + String value = projectionMap.get(columnName); + if (value != null) { + columnProjectionMap.put(columnName, value); + } else { + // Value NULL will be provided if the requested column does not exist in the + // database. + value = "NULL AS " + DatabaseUtils.sqlEscapeString(columnName); + columnProjectionMap.put(columnName, value); + } } return columnProjectionMap; } diff --git a/tests/src/com/android/providers/tv/TvProviderForTesting.java b/tests/src/com/android/providers/tv/TvProviderForTesting.java index 0f9638e..5300756 100644 --- a/tests/src/com/android/providers/tv/TvProviderForTesting.java +++ b/tests/src/com/android/providers/tv/TvProviderForTesting.java @@ -21,6 +21,7 @@ import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.media.tv.TvContract; import android.net.Uri; +import java.io.File; class TvProviderForTesting extends TvProvider { private static final String FAKE_SESSION_TOKEN = "TvProviderForTesting"; @@ -51,7 +52,10 @@ class TvProviderForTesting extends TvProvider { super.shutdown(); if (mDatabaseHelper != null) { + SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); + File databaseFile = new File(db.getPath()); mDatabaseHelper.close(); + SQLiteDatabase.deleteDatabase(databaseFile); } } diff --git a/tests/src/com/android/providers/tv/UnrecognizedColumnsTest.java b/tests/src/com/android/providers/tv/UnrecognizedColumnsTest.java new file mode 100644 index 0000000..f552013 --- /dev/null +++ b/tests/src/com/android/providers/tv/UnrecognizedColumnsTest.java @@ -0,0 +1,116 @@ +package com.android.providers.tv; + +import android.content.pm.ProviderInfo; +import android.database.Cursor; +import android.media.tv.TvContract; +import android.media.tv.TvContract.Programs; +import android.os.Bundle; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.test.mock.MockContentProvider; +import android.test.mock.MockContentResolver; +import com.android.providers.tv.Utils.Program; +import java.util.Arrays; + +import com.google.android.collect.Sets; + +public class UnrecognizedColumnsTest extends AndroidTestCase { + private static final String PERMISSION_ACCESS_ALL_EPG_DATA = + "com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA"; + private static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS"; + + private static final String MY_PACKAGE = "example.my"; + private static final String ANOTHER_PACKAGE = "example.another"; + + private MockContentResolver mResolver; + private TvProviderForTesting mProvider; + private MockTvProviderContext mContext; + private Program mProgram; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mResolver = new MockContentResolver(); + mResolver.addProvider(Settings.AUTHORITY, new MockContentProvider() { + @Override + public Bundle call(String method, String request, Bundle args) { + return new Bundle(); + } + }); + + mProvider = new TvProviderForTesting(); + mResolver.addProvider(TvContract.AUTHORITY, mProvider); + + mContext = new MockTvProviderContext(mResolver, getContext()); + // get data of the calling package only + mContext.grantOrRejectPermission(PERMISSION_ACCESS_ALL_EPG_DATA, false); + mContext.grantOrRejectPermission(PERMISSION_READ_TV_LISTINGS, false); + + setContext(mContext); + + final ProviderInfo info = new ProviderInfo(); + info.authority = TvContract.AUTHORITY; + mProvider.attachInfoForTesting(getContext(), info); + } + + + @Override + protected void tearDown() throws Exception { + Utils.clearTvProvider(mResolver); + mProvider.setOpenHelper(null, true); + mProvider.shutdown(); + super.tearDown(); + } + + public void testUnrecognizedColumns() { + insertPrograms(); + + String[] projection = new String[] { + TvContract.Programs._ID, + "_random_name", + " with spaces ", + "\' in single quotes \'", + "\" in double quotes \"", + "quotes \' inside \' this \" name \"", + }; + + Cursor cursor = + mResolver.query(TvContract.Programs.CONTENT_URI, projection, null, null, null); + assertNotNull(cursor); + cursor.moveToNext(); + assertEquals(1, cursor.getCount()); + + assertEquals( + "Column names don't match.", + Arrays.asList( + Programs._ID, + "_random_name", + " with spaces ", + "\' in single quotes \'", + "\" in double quotes \"", + "quotes \' inside \' this \" name \""), + Arrays.asList(cursor.getColumnNames())); + + assertEquals(mProgram.id, cursor.getLong(0)); + assertNull(cursor.getString(1)); + assertNull(cursor.getString(2)); + assertNull(cursor.getString(3)); + assertNull(cursor.getString(4)); + assertNull(cursor.getString(5)); + } + + private void insertPrograms() { + mProvider.callingPackage = MY_PACKAGE; + long myChannelId = Utils.insertChannel(mResolver); + mProgram = new Program(1, MY_PACKAGE); + Utils.insertPrograms(mResolver, myChannelId, mProgram); + + mProvider.callingPackage = ANOTHER_PACKAGE; + long anotherChannelId = Utils.insertChannel(mResolver); + Program anotherProgram = new Program(2, ANOTHER_PACKAGE); + Utils.insertPrograms(mResolver, anotherChannelId, anotherProgram); + + mProvider.callingPackage = MY_PACKAGE; + } +} -- cgit v1.2.3 From 0f626d4c9a0ff287b091c9c6caf1333b9542e8f5 Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 26 Jun 2019 16:21:25 -0700 Subject: Handle unrecognized columns and avoid SQL injection Bug:135269669 Test: atest com.android.providers.tv Change-Id: I6445fb22501e8ee2aeb6901b32cb03e971c14211 (cherry picked from commit d817260cae81eee3ea18fe6b8f69c32ba070ea6e) (cherry picked from commit 7b2b1fba39aeb61b67b29cdb8d4780afc817ac2e) --- src/com/android/providers/tv/TvProvider.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/com/android/providers/tv/TvProvider.java b/src/com/android/providers/tv/TvProvider.java index 01bc833..14d17f6 100644 --- a/src/com/android/providers/tv/TvProvider.java +++ b/src/com/android/providers/tv/TvProvider.java @@ -118,7 +118,6 @@ public class TvProvider extends ContentProvider { private static final String OP_UPDATE = "update"; private static final String OP_DELETE = "delete"; - private static final UriMatcher sUriMatcher; private static final int MATCH_CHANNEL = 1; private static final int MATCH_CHANNEL_ID = 2; @@ -1605,9 +1604,15 @@ public class TvProvider extends ContentProvider { } Map columnProjectionMap = new HashMap<>(); for (String columnName : projection) { - // Value NULL will be provided if the requested column does not exist in the database. - columnProjectionMap.put(columnName, - projectionMap.getOrDefault(columnName, "NULL as " + columnName)); + String value = projectionMap.get(columnName); + if (value != null) { + columnProjectionMap.put(columnName, value); + } else { + // Value NULL will be provided if the requested column does not exist in the + // database. + value = "NULL AS " + DatabaseUtils.sqlEscapeString(columnName); + columnProjectionMap.put(columnName, value); + } } return columnProjectionMap; } -- cgit v1.2.3 From c302b1da2f41f12f5235a2f53efa754b6937c44a Mon Sep 17 00:00:00 2001 From: shubang Date: Mon, 22 Jul 2019 16:05:36 -0700 Subject: Add SafetyNet logging to Tvprovider see go/safetynet-logging drive/open?id=1TQgBUkUUGYsiujLBn_4uzeUbwYdcguooHSwCzz0beTI Test: N/A Bug: 135269669 Change-Id: I73a62fdd33782de87aaf46e5392d186db296f52c (cherry picked from commit 52ec984f862fcc76ee1a7590b753fb64390f5f3a) (cherry picked from commit 1479ef8f05778813250a79dc8616f5a5c8652735) --- src/com/android/providers/tv/TvProvider.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/com/android/providers/tv/TvProvider.java b/src/com/android/providers/tv/TvProvider.java index cf16ded..4797272 100644 --- a/src/com/android/providers/tv/TvProvider.java +++ b/src/com/android/providers/tv/TvProvider.java @@ -1612,11 +1612,25 @@ public class TvProvider extends ContentProvider { // database. value = "NULL AS " + DatabaseUtils.sqlEscapeString(columnName); columnProjectionMap.put(columnName, value); + + if (needEventLog(columnName)) { + android.util.EventLog.writeEvent(0x534e4554, "135269669", -1, ""); + } } } return columnProjectionMap; } + private boolean needEventLog(String columnName) { + for (int i = 0; i < columnName.length(); i++) { + char c = columnName.charAt(i); + if (!Character.isLetterOrDigit(c) && c != '_') { + return true; + } + } + return false; + } + private void filterContentValues(ContentValues values, Map projectionMap) { Iterator iter = values.keySet().iterator(); while (iter.hasNext()) { -- cgit v1.2.3 From 128954a2836ca4decb962644909a403c54af6078 Mon Sep 17 00:00:00 2001 From: shubang Date: Mon, 22 Jul 2019 16:05:36 -0700 Subject: Add SafetyNet logging to Tvprovider see go/safetynet-logging drive/open?id=1TQgBUkUUGYsiujLBn_4uzeUbwYdcguooHSwCzz0beTI Test: N/A Bug: 135269669 Change-Id: I73a62fdd33782de87aaf46e5392d186db296f52c (cherry picked from commit 52ec984f862fcc76ee1a7590b753fb64390f5f3a) (cherry picked from commit 1479ef8f05778813250a79dc8616f5a5c8652735) --- src/com/android/providers/tv/TvProvider.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/com/android/providers/tv/TvProvider.java b/src/com/android/providers/tv/TvProvider.java index 14d17f6..674bb88 100644 --- a/src/com/android/providers/tv/TvProvider.java +++ b/src/com/android/providers/tv/TvProvider.java @@ -1612,11 +1612,25 @@ public class TvProvider extends ContentProvider { // database. value = "NULL AS " + DatabaseUtils.sqlEscapeString(columnName); columnProjectionMap.put(columnName, value); + + if (needEventLog(columnName)) { + android.util.EventLog.writeEvent(0x534e4554, "135269669", -1, ""); + } } } return columnProjectionMap; } + private boolean needEventLog(String columnName) { + for (int i = 0; i < columnName.length(); i++) { + char c = columnName.charAt(i); + if (!Character.isLetterOrDigit(c) && c != '_') { + return true; + } + } + return false; + } + private void filterContentValues(ContentValues values, Map projectionMap) { Iterator iter = values.keySet().iterator(); while (iter.hasNext()) { -- cgit v1.2.3 From a2f943651a5d5b8b12e8993d0ecfaf4667ad9699 Mon Sep 17 00:00:00 2001 From: shubang Date: Mon, 22 Jul 2019 16:05:36 -0700 Subject: Add SafetyNet logging to Tvprovider see go/safetynet-logging drive/open?id=1TQgBUkUUGYsiujLBn_4uzeUbwYdcguooHSwCzz0beTI Test: N/A Bug: 135269669 Change-Id: I73a62fdd33782de87aaf46e5392d186db296f52c (cherry picked from commit 52ec984f862fcc76ee1a7590b753fb64390f5f3a) (cherry picked from commit 1479ef8f05778813250a79dc8616f5a5c8652735) --- src/com/android/providers/tv/TvProvider.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/com/android/providers/tv/TvProvider.java b/src/com/android/providers/tv/TvProvider.java index 14d17f6..674bb88 100644 --- a/src/com/android/providers/tv/TvProvider.java +++ b/src/com/android/providers/tv/TvProvider.java @@ -1612,11 +1612,25 @@ public class TvProvider extends ContentProvider { // database. value = "NULL AS " + DatabaseUtils.sqlEscapeString(columnName); columnProjectionMap.put(columnName, value); + + if (needEventLog(columnName)) { + android.util.EventLog.writeEvent(0x534e4554, "135269669", -1, ""); + } } } return columnProjectionMap; } + private boolean needEventLog(String columnName) { + for (int i = 0; i < columnName.length(); i++) { + char c = columnName.charAt(i); + if (!Character.isLetterOrDigit(c) && c != '_') { + return true; + } + } + return false; + } + private void filterContentValues(ContentValues values, Map projectionMap) { Iterator iter = values.keySet().iterator(); while (iter.hasNext()) { -- cgit v1.2.3 From 929b2a554a61c06bc26c4736a95859d21b0062d7 Mon Sep 17 00:00:00 2001 From: shubang Date: Mon, 22 Jul 2019 16:05:36 -0700 Subject: Add SafetyNet logging to Tvprovider see go/safetynet-logging drive/open?id=1TQgBUkUUGYsiujLBn_4uzeUbwYdcguooHSwCzz0beTI Test: N/A Bug: 135269669 Change-Id: I73a62fdd33782de87aaf46e5392d186db296f52c (cherry picked from commit 52ec984f862fcc76ee1a7590b753fb64390f5f3a) (cherry picked from commit 1479ef8f05778813250a79dc8616f5a5c8652735) --- src/com/android/providers/tv/TvProvider.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/com/android/providers/tv/TvProvider.java b/src/com/android/providers/tv/TvProvider.java index b324ba3..d57eb8b 100644 --- a/src/com/android/providers/tv/TvProvider.java +++ b/src/com/android/providers/tv/TvProvider.java @@ -1667,11 +1667,25 @@ public class TvProvider extends ContentProvider { // database. value = "NULL AS " + DatabaseUtils.sqlEscapeString(columnName); columnProjectionMap.put(columnName, value); + + if (needEventLog(columnName)) { + android.util.EventLog.writeEvent(0x534e4554, "135269669", -1, ""); + } } } return columnProjectionMap; } + private boolean needEventLog(String columnName) { + for (int i = 0; i < columnName.length(); i++) { + char c = columnName.charAt(i); + if (!Character.isLetterOrDigit(c) && c != '_') { + return true; + } + } + return false; + } + private void filterContentValues(ContentValues values, Map projectionMap) { Iterator iter = values.keySet().iterator(); while (iter.hasNext()) { -- cgit v1.2.3 From 66df06a08d96984fcb6fcca0db6820b1ce6d892b Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Tue, 24 Sep 2019 22:16:15 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Iae07c681e743644f8d50a593029117e4d62d5009 Auto-generated-cl: translation import --- res/values-ja/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index a85e674..acaedf4 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -18,5 +18,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "TV Storage" "すべてのテレビ番組表の読み取り" - "端末で利用できるすべてのテレビ番組表の読み取り" + "デバイスで利用できるすべてのテレビ番組表の読み取り" -- cgit v1.2.3