• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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