From d6593e996b5daaebeb86b8ca37aa7fdd2e8fffc0 Mon Sep 17 00:00:00 2001 From: Rhed Jao Date: Thu, 17 Jun 2021 17:58:45 +0800 Subject: [PATCH] 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 --- .../server/pm/PackageManagerService.java | 25 ++++- .../java/com/android/server/pm/TEST_MAPPING | 3 + .../appenumeration/Android.bp | 36 +++++++ .../appenumeration/AndroidManifest.xml | 27 +++++ .../appenumeration/AndroidTest.xml | 43 ++++++++ .../AppEnumerationInternalTests.java | 98 +++++++++++++++++++ .../test-apps/target/Android.bp | 36 +++++++ .../target/AndroidManifest-syncprovider.xml | 29 ++++++ .../appenumeration/testapp/DummyProvider.java | 55 +++++++++++ 9 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 services/tests/PackageManagerServiceTests/appenumeration/Android.bp create mode 100644 services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml create mode 100644 services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml create mode 100644 services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java create mode 100644 services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp create mode 100644 services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-syncprovider.xml create mode 100644 services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/src/com/android/appenumeration/testapp/DummyProvider.java diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a8cc5fdf884d5..17ec51181a891 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -11524,8 +11524,31 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } + final List names = new ArrayList<>(); + final List 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 diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING index b7a069e10b676..2b62255adbaa7 100644 --- a/services/core/java/com/android/server/pm/TEST_MAPPING +++ b/services/core/java/com/android/server/pm/TEST_MAPPING @@ -12,6 +12,9 @@ { "name": "CtsAppEnumerationTestCases" }, + { + "name": "AppEnumerationInternalTests" + }, { "name": "CtsMatchFlagTestCases" }, diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp new file mode 100644 index 0000000000000..479ef8e5f1880 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp @@ -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"], +} diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml new file mode 100644 index 0000000000000..2039aaa20945c --- /dev/null +++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml new file mode 100644 index 0000000000000..6f168a3888b33 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml @@ -0,0 +1,43 @@ + + + + + diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java new file mode 100644 index 0000000000000..9337845604105 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java @@ -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 names = new ArrayList<>(); + final List 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 names = new ArrayList<>(); + final List 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); + } +} diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp new file mode 100644 index 0000000000000..64239b4c6b2d0 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp @@ -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, +} diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-syncprovider.xml b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-syncprovider.xml new file mode 100644 index 0000000000000..de8439384b54e --- /dev/null +++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-syncprovider.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/src/com/android/appenumeration/testapp/DummyProvider.java b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/src/com/android/appenumeration/testapp/DummyProvider.java new file mode 100644 index 0000000000000..e8b610969c2f7 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/src/com/android/appenumeration/testapp/DummyProvider.java @@ -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"; + } +}