| /* |
| * Copyright (C) 2018 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.appsecurity.cts; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import android.platform.test.annotations.AppModeFull; |
| import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; |
| import com.android.tradefed.build.IBuildInfo; |
| import com.android.tradefed.device.ITestDevice; |
| import com.android.tradefed.result.InputStreamSource; |
| import com.android.tradefed.testtype.DeviceTestCase; |
| import com.android.tradefed.testtype.IBuildReceiver; |
| import com.android.tradefed.util.FileUtil; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| |
| import java.io.File; |
| |
| /** |
| * Set of tests that verify that corrupt APKs are properly rejected by PackageManager and |
| * do not cause the system to crash. |
| */ |
| @AppModeFull // TODO: Needs porting to instant |
| public class CorruptApkTests extends DeviceTestCase implements IBuildReceiver { |
| private final String B71360999_PKG = "com.android.appsecurity.b71360999"; |
| private final String B71361168_PKG = "com.android.appsecurity.b71361168"; |
| private final String B79488511_PKG = "com.android.appsecurity.b79488511"; |
| |
| private IBuildInfo mBuildInfo; |
| |
| @Override |
| public void setBuild(IBuildInfo buildInfo) { |
| mBuildInfo = buildInfo; |
| } |
| |
| @Before |
| @Override |
| public void setUp() throws Exception { |
| super.setUp(); |
| uninstall(B71360999_PKG); |
| uninstall(B71361168_PKG); |
| uninstall(B79488511_PKG); |
| } |
| |
| @After |
| @Override |
| public void tearDown() throws Exception { |
| super.tearDown(); |
| uninstall(B71360999_PKG); |
| uninstall(B71361168_PKG); |
| uninstall(B79488511_PKG); |
| } |
| |
| /** Uninstall the apk if the test failed previously. */ |
| public void uninstall(String pkg) throws Exception { |
| ITestDevice device = getDevice(); |
| if (device.getInstalledPackageNames().contains(pkg)) { |
| device.uninstallPackage(pkg); |
| } |
| } |
| |
| /** |
| * Tests that apks described in b/71360999 do not install successfully. |
| */ |
| public void testFailToInstallCorruptStringPoolHeader_b71360999() throws Exception { |
| final String APK_PATH = "CtsCorruptApkTests_b71360999.apk"; |
| assertInstallNoFatalError(APK_PATH, B71360999_PKG); |
| } |
| |
| /** |
| * Tests that apks described in b/71361168 do not install successfully. |
| */ |
| public void testFailToInstallCorruptStringPoolHeader_b71361168() throws Exception { |
| final String APK_PATH = "CtsCorruptApkTests_b71361168.apk"; |
| assertInstallNoFatalError(APK_PATH, B71361168_PKG); |
| } |
| |
| /** |
| * Tests that apks described in b/79488511 do not install successfully. |
| */ |
| public void testFailToInstallCorruptStringPoolHeader_b79488511() throws Exception { |
| final String APK_PATH = "CtsCorruptApkTests_b79488511.apk"; |
| assertInstallNoFatalError(APK_PATH, B79488511_PKG); |
| } |
| |
| /** |
| * Assert that installing the app does not cause a native error caused by a buffer overflow |
| * or an out-of-bounds read. |
| **/ |
| private void assertInstallNoFatalError(String filename, String pkg) throws Exception { |
| ITestDevice device = getDevice(); |
| device.clearLogcat(); |
| |
| final String result = device.installPackage( |
| new CompatibilityBuildHelper(mBuildInfo).getTestFile(filename), |
| true /*reinstall*/); |
| |
| // Starting from P, corrupt apks should always fail to install |
| if (device.getApiLevel() >= 28) { |
| assertThat(result).isNotNull(); |
| assertThat(result).isNotEmpty(); |
| assertThat(device.getInstalledPackageNames()).doesNotContain(pkg); |
| } |
| |
| // This catches if the device fails to install the app because a segmentation fault |
| // or out of bounds read created by the bug occurs |
| File tmpTxtFile = null; |
| InputStreamSource source = device.getLogcat(200 * 1024); |
| try { |
| assertNotNull(source); |
| tmpTxtFile = FileUtil.createTempFile("logcat", ".txt"); |
| FileUtil.writeToFile(source.createInputStream(), tmpTxtFile); |
| String s = FileUtil.readStringFromFile(tmpTxtFile); |
| assertFalse(s.contains("SIGSEGV")); |
| assertFalse(s.contains("==ERROR")); |
| } finally { |
| source.close(); |
| if (tmpTxtFile != null) { |
| FileUtil.deleteFile(tmpTxtFile); |
| } |
| } |
| } |
| } |