1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.providers.contacts; 18 19 import static com.android.providers.contacts.EvenMoreAsserts.assertThrows; 20 21 import android.database.Cursor; 22 import android.database.sqlite.SQLiteException; 23 import android.net.Uri; 24 import android.net.Uri.Builder; 25 import android.provider.ContactsContract; 26 import android.provider.ContactsContract.CommonDataKinds.Phone; 27 import android.provider.ContactsContract.Contacts; 28 import android.test.suitebuilder.annotation.MediumTest; 29 30 import com.android.providers.contacts.testutil.RawContactUtil; 31 32 /** 33 * Unit tests for {@link ContactsProvider2}, to make sure the queries don't allow sql injection. 34 * 35 * Run the test like this: 36 * <code> 37 * adb shell am instrument -e class com.android.providers.contacts.SqlInjectionDetectionTest -w \ 38 * com.android.providers.contacts.tests/android.test.InstrumentationTestRunner 39 * </code> 40 */ 41 @MediumTest 42 public class SqlInjectionDetectionTest extends BaseContactsProvider2Test { 43 private static final String[] PHONE_ID_PROJECTION = new String[] { Phone._ID }; 44 testPhoneQueryValid()45 public void testPhoneQueryValid() { 46 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale"); 47 insertPhoneNumber(rawContactId, "555-123-4567"); 48 49 assertQueryValid(Phone.CONTENT_URI, PHONE_ID_PROJECTION, 50 Phone.NUMBER + "='555-123-4567'", null); 51 } 52 testPhoneQueryBadProjection()53 public void testPhoneQueryBadProjection() { 54 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale"); 55 insertPhoneNumber(rawContactId, "555-123-4567"); 56 57 assertQueryThrows(IllegalArgumentException.class, Phone.CONTENT_URI, 58 new String[] { "0 UNION SELECT _id FROM view_data--" }, null, null); 59 } 60 testPhoneQueryBadSelection()61 public void testPhoneQueryBadSelection() { 62 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale"); 63 insertPhoneNumber(rawContactId, "555-123-4567"); 64 65 assertQueryThrows(SQLiteException.class, Phone.CONTENT_URI, PHONE_ID_PROJECTION, 66 "0=1) UNION SELECT _id FROM view_data--", null); 67 } 68 testPhoneQueryBadSortOrder()69 public void testPhoneQueryBadSortOrder() { 70 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale"); 71 insertPhoneNumber(rawContactId, "555-123-4567"); 72 73 assertQueryThrows(SQLiteException.class, Phone.CONTENT_URI, 74 PHONE_ID_PROJECTION, null, "_id UNION SELECT _id FROM view_data--"); 75 } 76 testPhoneQueryBadLimit()77 public void testPhoneQueryBadLimit() { 78 // Non-numeric query parameters are ignored by the provider 79 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale"); 80 insertPhoneNumber(rawContactId, "555-123-4567"); 81 82 Builder builder = Contacts.CONTENT_FILTER_URI.buildUpon(); 83 builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, 84 "0 UNION SELECT -50"); 85 assertQueryValid(Phone.CONTENT_URI, 86 PHONE_ID_PROJECTION, null, null); 87 88 final Cursor c = mResolver.query(Phone.CONTENT_URI, PHONE_ID_PROJECTION, null, null, null); 89 // the current implementation ignores every non-numeric limit. so we should see the 90 // contact as the only result 91 assertEquals(1, c.getCount()); 92 c.moveToFirst(); 93 assertNotSame(-50, c.getLong(0)); 94 c.close(); 95 } 96 assertQueryValid(final Uri uri, final String[] projection, final String selection, final String sortOrder)97 private void assertQueryValid(final Uri uri, final String[] projection, 98 final String selection, final String sortOrder) { 99 final Cursor c = mResolver.query(uri, projection, selection, null, sortOrder); 100 c.close(); 101 } 102 assertQueryThrows(Class<T> exception, final Uri uri, final String[] projection, final String selection, final String sortOrder)103 private <T extends Exception> void assertQueryThrows(Class<T> exception, final Uri uri, 104 final String[] projection, final String selection, final String sortOrder) { 105 assertThrows(exception, new Runnable() { 106 @Override 107 public void run() { 108 final Cursor c = mResolver.query(uri, projection, selection, null, sortOrder); 109 c.close(); 110 } 111 }); 112 } 113 } 114