Enforce package visibility to the api querySyncProviders

A security fix to enforce package visibility filter to the
api IPackageManager#querySyncProviders.

Bug: 188802680
Test: atest AppEnumerationInternalTests
Change-Id: Idca4b1bf739b6113ac3922af63ebc9d15fd5fe69
This commit is contained in:
Rhed Jao
2021-06-17 17:58:45 +08:00
parent 4a762bc62b
commit d6593e996b
9 changed files with 351 additions and 1 deletions

View File

@@ -11524,8 +11524,31 @@ public class PackageManagerService extends IPackageManager.Stub
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return;
}
final List<String> names = new ArrayList<>();
final List<ProviderInfo> infos = new ArrayList<>();
final int callingUserId = UserHandle.getCallingUserId();
mComponentResolver.querySyncProviders(
outNames, outInfo, mSafeMode, UserHandle.getCallingUserId());
names, infos, mSafeMode, callingUserId);
synchronized (mLock) {
for (int i = infos.size() - 1; i >= 0; i--) {
final ProviderInfo providerInfo = infos.get(i);
final PackageSetting ps = mSettings.getPackageLPr(providerInfo.packageName);
final ComponentName component =
new ComponentName(providerInfo.packageName, providerInfo.name);
if (!shouldFilterApplicationLocked(ps, Binder.getCallingUid(), component,
TYPE_PROVIDER, callingUserId)) {
continue;
}
infos.remove(i);
names.remove(i);
}
}
if (!names.isEmpty()) {
outNames.addAll(names);
}
if (!infos.isEmpty()) {
outInfo.addAll(infos);
}
}
@Override

View File

@@ -12,6 +12,9 @@
{
"name": "CtsAppEnumerationTestCases"
},
{
"name": "AppEnumerationInternalTests"
},
{
"name": "CtsMatchFlagTestCases"
},

View File

@@ -0,0 +1,36 @@
// Copyright (C) 2021 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 {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
android_test {
name: "AppEnumerationInternalTests",
srcs: [
"src/**/*.java",
],
static_libs: [
"compatibility-device-util-axt",
"androidx.test.runner",
"truth-prebuilt",
],
platform_apis: true,
test_suites: ["device-tests"],
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.pm.test.appenumeration">
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.server.pm.test.appenumeration"
android:label="Package Manager Service Tests for app enumeration">
</instrumentation>
</manifest>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<configuration description="Runs Package Manager Service App Enumeration Tests.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-instrumentation" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="AppEnumerationInternalTests.apk" />
</target_preparer>
<!-- Create place to store apks -->
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="mkdir -p /data/local/tmp/appenumerationtests" />
<option name="teardown-command" value="rm -rf /data/local/tmp/appenumerationtests"/>
</target_preparer>
<!-- Load additional APKs onto device -->
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="push" value="AppEnumerationSyncProviderTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationSyncProviderTestApp.apk" />
</target_preparer>
<option name="test-tag" value="AppEnumerationInternalTest" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.server.pm.test.appenumeration" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false" />
</test>
</configuration>

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2021 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 com.android.server.pm.test.appenumeration;
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import static com.google.common.truth.Truth.assertThat;
import android.app.AppGlobals;
import android.content.pm.IPackageManager;
import android.content.pm.ProviderInfo;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Application enumeration tests for the internal apis of package manager service.
*/
@RunWith(AndroidJUnit4.class)
public class AppEnumerationInternalTests {
private static final String TEST_DATA_PATH = "/data/local/tmp/appenumerationtests/";
private static final String SYNC_PROVIDER_APK_PATH =
TEST_DATA_PATH + "AppEnumerationSyncProviderTestApp.apk";
private static final String SYNC_PROVIDER_PKG_NAME = "com.android.appenumeration.syncprovider";
private static final String SYNC_PROVIDER_AUTHORITY = SYNC_PROVIDER_PKG_NAME;
private IPackageManager mIPackageManager;
@Before
public void setup() {
mIPackageManager = AppGlobals.getPackageManager();
}
@After
public void tearDown() throws Exception {
uninstallPackage(SYNC_PROVIDER_PKG_NAME);
}
@Test
public void querySyncProviders_canSeeForceQueryable() throws Exception {
final List<String> names = new ArrayList<>();
final List<ProviderInfo> infos = new ArrayList<>();
installPackage(SYNC_PROVIDER_APK_PATH, true /* forceQueryable */);
mIPackageManager.querySyncProviders(names, infos);
assertThat(names).contains(SYNC_PROVIDER_AUTHORITY);
assertThat(infos.stream().map(info -> info.packageName).collect(Collectors.toList()))
.contains(SYNC_PROVIDER_PKG_NAME);
}
@Test
public void querySyncProviders_cannotSeeSyncProvider() throws Exception {
final List<String> names = new ArrayList<>();
final List<ProviderInfo> infos = new ArrayList<>();
installPackage(SYNC_PROVIDER_APK_PATH, false /* forceQueryable */);
mIPackageManager.querySyncProviders(names, infos);
assertThat(names).doesNotContain(SYNC_PROVIDER_AUTHORITY);
assertThat(infos.stream().map(info -> info.packageName).collect(Collectors.toList()))
.doesNotContain(SYNC_PROVIDER_PKG_NAME);
}
private static void installPackage(String apkPath, boolean forceQueryable) {
final StringBuilder cmd = new StringBuilder("pm install ");
if (forceQueryable) {
cmd.append("--force-queryable ");
}
cmd.append(apkPath);
final String result = runShellCommand(cmd.toString());
assertThat(result.trim()).contains("Success");
}
private static void uninstallPackage(String packageName) {
runShellCommand("pm uninstall " + packageName);
}
}

View File

@@ -0,0 +1,36 @@
// Copyright (C) 2021 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 {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
android_test_helper_app {
name: "AppEnumerationSyncProviderTestApp",
srcs: ["src/**/*.java"],
manifest: "AndroidManifest-syncprovider.xml",
dex_preopt: {
enabled: false,
},
optimize: {
enabled: false,
},
test_suites: ["device-tests"],
platform_apis: true,
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.appenumeration.syncprovider">
<application>
<provider android:name="com.android.appenumeration.testapp.DummyProvider"
android:authorities="com.android.appenumeration.syncprovider"
android:syncable="true" android:exported="true">
<intent-filter>
<action android:name="com.android.appenumeration.action.PROVIDER"/>
</intent-filter>
</provider>
</application>
</manifest>

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2021 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 com.android.appenumeration.testapp;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
public class DummyProvider extends ContentProvider {
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
@Override
public String getType(Uri uri) {
return "text/plain";
}
}