summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2019-12-23 21:03:17 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2019-12-23 21:03:17 +0000
commit70030aaec339f7c331f80b907a2d147591840d6f (patch)
treee8366071f295dd1e40522931118cb82ea23e5910
parent49583e3d84ad6904b09ea42b76fdcf891c31c79b (diff)
parentd4d523686429f0bbe2484d8d24652f671c53f310 (diff)
downloadcts-70030aaec339f7c331f80b907a2d147591840d6f.tar.gz
Merge changes I6b247672,Ie8ea452b,I9ef52453 into pie-cts-dev
* changes: RESTRICT AUTOMERGE Strict SQLiteQueryBuilder needs to be stricter. DO NOT MERGE fixes a security vulnerability in slice provider DO NOT MERGE CTS: Test column name with spaces
-rw-r--r--tests/tests/database/src/android/database/sqlite/cts/SQLiteQueryBuilderTest.java176
-rw-r--r--tests/tests/slice/src/android/slice/cts/SliceProviderTest.java89
-rw-r--r--tests/tests/tv/src/android/media/tv/cts/TvContractTest.java13
3 files changed, 265 insertions, 13 deletions
diff --git a/tests/tests/database/src/android/database/sqlite/cts/SQLiteQueryBuilderTest.java b/tests/tests/database/src/android/database/sqlite/cts/SQLiteQueryBuilderTest.java
index 97b0b8f5475..4479a5d393c 100644
--- a/tests/tests/database/src/android/database/sqlite/cts/SQLiteQueryBuilderTest.java
+++ b/tests/tests/database/src/android/database/sqlite/cts/SQLiteQueryBuilderTest.java
@@ -18,6 +18,7 @@ package android.database.sqlite.cts;
import android.content.Context;
+import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteCursor;
import android.database.sqlite.SQLiteCursorDriver;
@@ -28,12 +29,15 @@ import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.test.AndroidTestCase;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
public class SQLiteQueryBuilderTest extends AndroidTestCase {
private SQLiteDatabase mDatabase;
+ private SQLiteQueryBuilder mStrictBuilder;
+
private final String TEST_TABLE_NAME = "test";
private final String EMPLOYEE_TABLE_NAME = "employee";
private static final String DATABASE_FILE = "database_test.db";
@@ -45,6 +49,9 @@ public class SQLiteQueryBuilderTest extends AndroidTestCase {
getContext().deleteDatabase(DATABASE_FILE);
mDatabase = getContext().openOrCreateDatabase(DATABASE_FILE, Context.MODE_PRIVATE, null);
assertNotNull(mDatabase);
+
+ createEmployeeTable();
+ createStrictQueryBuilder();
}
@Override
@@ -202,8 +209,6 @@ public class SQLiteQueryBuilderTest extends AndroidTestCase {
}
public void testQuery() {
- createEmployeeTable();
-
SQLiteQueryBuilder sqliteQueryBuilder = new SQLiteQueryBuilder();
sqliteQueryBuilder.setTables("Employee");
Cursor cursor = sqliteQueryBuilder.query(mDatabase,
@@ -276,8 +281,6 @@ public class SQLiteQueryBuilderTest extends AndroidTestCase {
}
public void testCancelableQuery_WhenNotCanceled_ReturnsResultSet() {
- createEmployeeTable();
-
CancellationSignal cancellationSignal = new CancellationSignal();
SQLiteQueryBuilder sqliteQueryBuilder = new SQLiteQueryBuilder();
sqliteQueryBuilder.setTables("Employee");
@@ -289,8 +292,6 @@ public class SQLiteQueryBuilderTest extends AndroidTestCase {
}
public void testCancelableQuery_WhenCanceledBeforeQuery_ThrowsImmediately() {
- createEmployeeTable();
-
CancellationSignal cancellationSignal = new CancellationSignal();
SQLiteQueryBuilder sqliteQueryBuilder = new SQLiteQueryBuilder();
sqliteQueryBuilder.setTables("Employee");
@@ -307,8 +308,6 @@ public class SQLiteQueryBuilderTest extends AndroidTestCase {
}
public void testCancelableQuery_WhenCanceledAfterQuery_ThrowsWhenExecuted() {
- createEmployeeTable();
-
CancellationSignal cancellationSignal = new CancellationSignal();
SQLiteQueryBuilder sqliteQueryBuilder = new SQLiteQueryBuilder();
sqliteQueryBuilder.setTables("Employee");
@@ -327,8 +326,6 @@ public class SQLiteQueryBuilderTest extends AndroidTestCase {
}
public void testCancelableQuery_WhenCanceledDueToContention_StopsWaitingAndThrows() {
- createEmployeeTable();
-
for (int i = 0; i < 5; i++) {
final CancellationSignal cancellationSignal = new CancellationSignal();
final Semaphore barrier1 = new Semaphore(0);
@@ -460,6 +457,152 @@ public class SQLiteQueryBuilderTest extends AndroidTestCase {
fail("Could not prove that the query actually canceled midway during execution.");
}
+ public void testStrictQuery() throws Exception {
+ final SQLiteQueryBuilder qb = mStrictBuilder;
+
+ // Should normally only be able to see one row
+ try (Cursor c = qb.query(mDatabase, null, null, null, null, null, null)) {
+ assertEquals(1, c.getCount());
+ }
+
+ // Trying sneaky queries should fail; even if they somehow succeed, we
+ // shouldn't get to see any other data.
+ try (Cursor c = qb.query(mDatabase, null, "1=1", null, null, null, null)) {
+ assertEquals(1, c.getCount());
+ } catch (Exception tolerated) {
+ }
+ try (Cursor c = qb.query(mDatabase, null, "1=1 --", null, null, null, null)) {
+ assertEquals(1, c.getCount());
+ } catch (Exception tolerated) {
+ }
+ try (Cursor c = qb.query(mDatabase, null, "1=1) OR (1=1", null, null, null, null)) {
+ assertEquals(1, c.getCount());
+ } catch (Exception tolerated) {
+ }
+ try (Cursor c = qb.query(mDatabase, null, "1=1)) OR ((1=1", null, null, null, null)) {
+ assertEquals(1, c.getCount());
+ } catch (Exception tolerated) {
+ }
+ }
+
+ private static final String[] COLUMNS_VALID = new String[] {
+ "_id",
+ };
+
+ private static final String[] COLUMNS_INVALID = new String[] {
+ "salary",
+ "MAX(salary)",
+ "undefined",
+ "(secret_column IN secret_table)",
+ "(SELECT secret_column FROM secret_table)",
+ };
+
+ public void testStrictQueryProjection() throws Exception {
+ for (String column : COLUMNS_VALID) {
+ assertStrictQueryValid(
+ new String[] { column }, null, null, null, null, null, null);
+ }
+ for (String column : COLUMNS_INVALID) {
+ assertStrictQueryInvalid(
+ new String[] { column }, null, null, null, null, null, null);
+ }
+ }
+
+ public void testStrictQueryWhere() throws Exception {
+ for (String column : COLUMNS_VALID) {
+ assertStrictQueryValid(
+ null, column + ">0", null, null, null, null, null);
+ assertStrictQueryValid(
+ null, "_id>" + column, null, null, null, null, null);
+ }
+ for (String column : COLUMNS_INVALID) {
+ assertStrictQueryInvalid(
+ null, column + ">0", null, null, null, null, null);
+ assertStrictQueryInvalid(
+ null, "_id>" + column, null, null, null, null, null);
+ }
+ }
+
+ public void testStrictQueryGroupBy() {
+ for (String column : COLUMNS_VALID) {
+ assertStrictQueryValid(
+ null, null, null, column, null, null, null);
+ assertStrictQueryValid(
+ null, null, null, "_id," + column, null, null, null);
+ }
+ for (String column : COLUMNS_INVALID) {
+ assertStrictQueryInvalid(
+ null, null, null, column, null, null, null);
+ assertStrictQueryInvalid(
+ null, null, null, "_id," + column, null, null, null);
+ }
+ }
+
+ public void testStrictQueryHaving() {
+ for (String column : COLUMNS_VALID) {
+ assertStrictQueryValid(
+ null, null, null, "_id", column, null, null);
+ }
+ for (String column : COLUMNS_INVALID) {
+ assertStrictQueryInvalid(
+ null, null, null, "_id", column, null, null);
+ }
+ }
+
+ public void testStrictQueryOrderBy() {
+ for (String column : COLUMNS_VALID) {
+ assertStrictQueryValid(
+ null, null, null, null, null, column, null);
+ assertStrictQueryValid(
+ null, null, null, null, null, column + " ASC", null);
+ assertStrictQueryValid(
+ null, null, null, null, null, "_id COLLATE NOCASE ASC," + column, null);
+ }
+ for (String column : COLUMNS_INVALID) {
+ assertStrictQueryInvalid(
+ null, null, null, null, null, column, null);
+ assertStrictQueryInvalid(
+ null, null, null, null, null, column + " ASC", null);
+ assertStrictQueryInvalid(
+ null, null, null, null, null, "_id COLLATE NOCASE ASC," + column, null);
+ }
+ }
+
+ public void testStrictQueryLimit() {
+ assertStrictQueryValid(
+ null, null, null, null, null, null, "32");
+ assertStrictQueryValid(
+ null, null, null, null, null, null, "0,32");
+ assertStrictQueryValid(
+ null, null, null, null, null, null, "32 OFFSET 0");
+
+ for (String column : COLUMNS_VALID) {
+ assertStrictQueryInvalid(
+ null, null, null, null, null, null, column);
+ }
+ for (String column : COLUMNS_INVALID) {
+ assertStrictQueryInvalid(
+ null, null, null, null, null, null, column);
+ }
+ }
+
+ private void assertStrictQueryValid(String[] projectionIn, String selection,
+ String[] selectionArgs, String groupBy, String having, String sortOrder, String limit) {
+ try (Cursor c = mStrictBuilder.query(mDatabase, projectionIn, selection, selectionArgs,
+ groupBy, having, sortOrder, limit, null)) {
+ }
+ }
+
+ private void assertStrictQueryInvalid(String[] projectionIn, String selection,
+ String[] selectionArgs, String groupBy, String having, String sortOrder, String limit) {
+ try (Cursor c = mStrictBuilder.query(mDatabase, projectionIn, selection, selectionArgs,
+ groupBy, having, sortOrder, limit, null)) {
+ fail(Arrays.asList(projectionIn, selection, selectionArgs,
+ groupBy, having, sortOrder, limit).toString());
+ } catch (Exception expected) {
+ }
+ }
+
private void createEmployeeTable() {
mDatabase.execSQL("CREATE TABLE employee (_id INTEGER PRIMARY KEY, " +
"name TEXT, month INTEGER, salary INTEGER);");
@@ -476,4 +619,17 @@ public class SQLiteQueryBuilderTest extends AndroidTestCase {
mDatabase.execSQL("INSERT INTO employee (name, month, salary) " +
"VALUES ('Jim', '3', '3500');");
}
+
+ private void createStrictQueryBuilder() {
+ mStrictBuilder = new SQLiteQueryBuilder();
+ mStrictBuilder.setTables("employee");
+ mStrictBuilder.setStrict(true);
+ mStrictBuilder.appendWhere("month=2");
+
+ final Map<String, String> projectionMap = new HashMap<>();
+ projectionMap.put("_id", "_id");
+ projectionMap.put("name", "name");
+ projectionMap.put("month", "month");
+ mStrictBuilder.setProjectionMap(projectionMap);
+ }
}
diff --git a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java
new file mode 100644
index 00000000000..2a2e8e46b1a
--- /dev/null
+++ b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 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 android.slice.cts;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceSpec;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.Bundle;
+
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.android.collect.Lists;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SliceProviderTest {
+
+ private static final String VALID_AUTHORITY = "android.slice.cts";
+ private static final String SUSPICIOUS_AUTHORITY = "com.suspicious.www";
+ private static final String ACTION_BLUETOOTH = "/action/bluetooth";
+ private static final String VALID_BASE_URI_STRING = "content://" + VALID_AUTHORITY;
+ private static final String VALID_ACTION_URI_STRING =
+ "content://" + VALID_AUTHORITY + ACTION_BLUETOOTH;
+ private static final String SHADY_ACTION_URI_STRING =
+ "content://" + SUSPICIOUS_AUTHORITY + ACTION_BLUETOOTH;
+
+ @Rule
+ public ActivityTestRule<Launcher> mLauncherActivityTestRule = new ActivityTestRule<>(Launcher.class);
+
+ private Uri validBaseUri = Uri.parse(VALID_BASE_URI_STRING);
+ private Uri validActionUri = Uri.parse(VALID_ACTION_URI_STRING);
+ private Uri shadyActionUri = Uri.parse(SHADY_ACTION_URI_STRING);
+
+ private ContentResolver mContentResolver;
+
+ @Before
+ public void setUp() {
+ mContentResolver = mLauncherActivityTestRule.getActivity().getContentResolver();
+ }
+
+ @Test
+ public void testCallSliceUri_ValidAuthority() {
+ doQuery(validActionUri);
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testCallSliceUri_ShadyAuthority() {
+ doQuery(shadyActionUri);
+ }
+
+ private Slice doQuery(Uri actionUri) {
+ Bundle extras = new Bundle();
+ extras.putParcelable("slice_uri", actionUri);
+ extras.putParcelableArrayList("supported_specs", Lists.newArrayList(
+ new SliceSpec("androidx.slice.LIST", 1),
+ new SliceSpec("androidx.app.slice.BASIC", 1),
+ new SliceSpec("androidx.slice.BASIC", 1),
+ new SliceSpec("androidx.app.slice.LIST", 1)
+ ));
+ Bundle result = mContentResolver.call(
+ validBaseUri,
+ SliceProvider.METHOD_SLICE,
+ null,
+ extras
+ );
+ return result.getParcelable(SliceProvider.EXTRA_SLICE);
+ }
+
+}
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
index 27c388a9153..6314ec59209 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
@@ -105,7 +105,8 @@ public class TvContractTest extends AndroidTestCase {
private static final String WHITE_SPACES = " \r \n \t \f ";
private static final String PARAM_CANONICAL_GENRE = "canonical_genre";
- private static final String NON_EXISTING_COLUMN_NAME = "non_existing_column";
+ private static final String[] NON_EXISTING_COLUMN_NAMES =
+ {"non_existing_column", "another non-existing column --"};
private String mInputId;
private ContentResolver mContentResolver;
@@ -336,15 +337,20 @@ public class TvContractTest extends AndroidTestCase {
private void verifyNonExistingColumn(Uri channelUri, long channelId) {
String[] projection = {
Channels._ID,
- NON_EXISTING_COLUMN_NAME
+ NON_EXISTING_COLUMN_NAMES[0],
+ NON_EXISTING_COLUMN_NAMES[1]
};
try (Cursor cursor = mContentResolver.query(channelUri, projection, null, null, null)) {
assertNotNull(cursor);
assertEquals(cursor.getCount(), 1);
assertTrue(cursor.moveToNext());
assertEquals(channelId, cursor.getLong(0));
+ assertEquals(NON_EXISTING_COLUMN_NAMES[0], cursor.getColumnName(1));
assertNull(cursor.getString(1));
assertEquals(0, cursor.getInt(1));
+ assertEquals(NON_EXISTING_COLUMN_NAMES[1], cursor.getColumnName(2));
+ assertNull(cursor.getString(2));
+ assertEquals(0, cursor.getInt(2));
}
}
@@ -533,7 +539,8 @@ public class TvContractTest extends AndroidTestCase {
return;
}
ContentValues values = createDummyChannelValues(mInputId, false);
- values.put(NON_EXISTING_COLUMN_NAME, "dummy value");
+ values.put(NON_EXISTING_COLUMN_NAMES[0], "dummy value 0");
+ values.put(NON_EXISTING_COLUMN_NAMES[1], "dummy value 1");
Uri rowUri = mContentResolver.insert(mChannelsUri, values);
long channelId = ContentUris.parseId(rowUri);
Uri channelUri = TvContract.buildChannelUri(channelId);