From 8d3b7a4d45992c7af409c0dbcfc1d29ece1ce44e Mon Sep 17 00:00:00 2001 From: Alan Stokes Date: Tue, 19 Feb 2019 17:14:42 +0000 Subject: Rename test class to match code. Renaming DexLoggerIntegrationTests to DynamicCodeLoggerIntegrationTests, to match the rename and changed scope of the code it is testing. Test: atest -p services/core/java/com/android/server/pm/dex Bug: 122946463 Change-Id: I66abd6b173f148279085dee7a714aa64df7a941b --- tests/DynamicCodeLoggerIntegrationTests/Android.mk | 84 ++++ .../AndroidManifest.xml | 35 ++ .../AndroidTest.xml | 30 ++ .../src/com/android/dcl/Simple.java | 22 + .../pm/dex/DynamicCodeLoggerIntegrationTests.java | 497 +++++++++++++++++++++ .../src/cpp/com_android_dcl_Jni.cpp | 22 + .../src/cpp/test_executable.cpp | 20 + 7 files changed, 710 insertions(+) create mode 100644 tests/DynamicCodeLoggerIntegrationTests/Android.mk create mode 100644 tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml create mode 100644 tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml create mode 100644 tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java create mode 100644 tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java create mode 100644 tests/DynamicCodeLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp create mode 100644 tests/DynamicCodeLoggerIntegrationTests/src/cpp/test_executable.cpp (limited to 'tests/DynamicCodeLoggerIntegrationTests') diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk new file mode 100644 index 000000000000..f324eb10a7b0 --- /dev/null +++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk @@ -0,0 +1,84 @@ +# +# Copyright 2017 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. +# + +LOCAL_PATH:= $(call my-dir) + +# Build a tiny library that the test app can dynamically load + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE := DynamicCodeLoggerTestLibrary +LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/dcl) + +include $(BUILD_JAVA_LIBRARY) + +dynamiccodeloggertest_jar := $(LOCAL_BUILT_MODULE) + + +# Also build a native library that the test app can dynamically load + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE := DynamicCodeLoggerNativeTestLibrary +LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) +LOCAL_SDK_VERSION := 28 +LOCAL_NDK_STL_VARIANT := c++_static + +include $(BUILD_SHARED_LIBRARY) + +# And a standalone native executable that we can exec. + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE := DynamicCodeLoggerNativeExecutable +LOCAL_SRC_FILES := src/cpp/test_executable.cpp + +include $(BUILD_EXECUTABLE) + +dynamiccodeloggertest_executable := $(LOCAL_BUILT_MODULE) + +# Build the test app itself + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_PACKAGE_NAME := DynamicCodeLoggerIntegrationTests +LOCAL_SDK_VERSION := current +LOCAL_COMPATIBILITY_SUITE := device-tests +LOCAL_CERTIFICATE := shared +LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/server/pm) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ + truth-prebuilt \ + +# Include both versions of the .so if we have 2 arch +LOCAL_MULTILIB := both +LOCAL_JNI_SHARED_LIBRARIES := \ + DynamicCodeLoggerNativeTestLibrary \ + +# This gets us the javalib.jar built by DynamicCodeLoggerTestLibrary above as well as the various +# native binaries. +LOCAL_JAVA_RESOURCE_FILES := \ + $(dynamiccodeloggertest_jar) \ + $(dynamiccodeloggertest_executable) \ + +include $(BUILD_PACKAGE) diff --git a/tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml b/tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml new file mode 100644 index 000000000000..4327da2db3dd --- /dev/null +++ b/tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + diff --git a/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml b/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml new file mode 100644 index 000000000000..f70b9c8cb357 --- /dev/null +++ b/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml @@ -0,0 +1,30 @@ + + + + + + + diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java new file mode 100644 index 000000000000..e995a26ea5c9 --- /dev/null +++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java @@ -0,0 +1,22 @@ +/* + * Copyright 2017 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.dcl; + +/** Dummy class which is built into a jar purely so we can pass it to DexClassLoader. */ +public final class Simple { + public Simple() {} +} diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java new file mode 100644 index 000000000000..8ef15d869a0b --- /dev/null +++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java @@ -0,0 +1,497 @@ +/* + * Copyright 2017 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.dex; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import android.app.UiAutomation; +import android.content.Context; +import android.os.Build; +import android.os.ParcelFileDescriptor; +import android.os.SystemClock; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.LargeTest; +import android.util.EventLog; +import android.util.EventLog.Event; + +import dalvik.system.DexClassLoader; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Formatter; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * Integration tests for {@link DynamicCodeLogger}. + * + * The setup for the test dynamically loads code in a jar extracted + * from our assets (a secondary dex file). + * + * We then use shell commands to trigger dynamic code logging (and wait + * for it to complete). This causes DynamicCodeLogger to log the hash of the + * file's name and content. We verify that this message appears in + * the event log. + * + * Run with "atest DynamicCodeLoggerIntegrationTests". + */ +@LargeTest +@RunWith(JUnit4.class) +public final class DynamicCodeLoggerIntegrationTests { + + private static final String SHA_256 = "SHA-256"; + + // Event log tag used for SNET related events + private static final int SNET_TAG = 0x534e4554; + + // Subtags used to distinguish dynamic code loading events + private static final String DCL_DEX_SUBTAG = "dcl"; + private static final String DCL_NATIVE_SUBTAG = "dcln"; + + // These are job IDs from DynamicCodeLoggingService + private static final int IDLE_LOGGING_JOB_ID = 2030028; + private static final int AUDIT_WATCHING_JOB_ID = 203142925; + + // For tests that rely on parsing audit logs, how often to retry. (There are many reasons why + // we might not see the audit logs, including throttling and delays in log generation, so to + // avoid flakiness we run these tests multiple times, allowing progressively longer between + // code loading and checking the logs on each try.) + private static final int AUDIT_LOG_RETRIES = 10; + private static final int RETRY_DELAY_MS = 2_000; + + private static Context sContext; + private static int sMyUid; + + @BeforeClass + public static void setUpAll() { + sContext = InstrumentationRegistry.getTargetContext(); + sMyUid = android.os.Process.myUid(); + } + + @Before + public void primeEventLog() { + // Force a round trip to logd to make sure everything is up to date. + // Without this the first test passes and others don't - we don't see new events in the + // log. The exact reason is unclear. + EventLog.writeEvent(SNET_TAG, "Dummy event"); + + // Audit log messages are throttled by the kernel (at the request of logd) to 5 per + // second, so running the tests too quickly in sequence means we lose some and get + // spurious failures. Sigh. + SystemClock.sleep(1000); + } + + @Test + public void testGeneratesEvents_standardClassLoader() throws Exception { + File privateCopyFile = privateFile("copied.jar"); + // Obtained via "echo -n copied.jar | sha256sum" + String expectedNameHash = + "1B6C71DB26F36582867432CCA12FB6A517470C9F9AABE9198DD4C5C030D6DC0C"; + String expectedContentHash = copyAndHashResource("/javalib.jar", privateCopyFile); + + // Feed the jar to a class loader and make sure it contains what we expect. + ClassLoader parentClassLoader = sContext.getClass().getClassLoader(); + ClassLoader loader = + new DexClassLoader(privateCopyFile.toString(), null, null, parentClassLoader); + loader.loadClass("com.android.dcl.Simple"); + + // And make sure we log events about it + long previousEventNanos = mostRecentEventTimeNanos(); + runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID); + + assertDclLoggedSince(previousEventNanos, DCL_DEX_SUBTAG, + expectedNameHash, expectedContentHash); + } + + @Test + public void testGeneratesEvents_unknownClassLoader() throws Exception { + File privateCopyFile = privateFile("copied2.jar"); + String expectedNameHash = + "202158B6A3169D78F1722487205A6B036B3F2F5653FDCFB4E74710611AC7EB93"; + String expectedContentHash = copyAndHashResource("/javalib.jar", privateCopyFile); + + // This time make sure an unknown class loader is an ancestor of the class loader we use. + ClassLoader knownClassLoader = sContext.getClass().getClassLoader(); + ClassLoader unknownClassLoader = new UnknownClassLoader(knownClassLoader); + ClassLoader loader = + new DexClassLoader(privateCopyFile.toString(), null, null, unknownClassLoader); + loader.loadClass("com.android.dcl.Simple"); + + // And make sure we log events about it + long previousEventNanos = mostRecentEventTimeNanos(); + runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID); + + assertDclLoggedSince(previousEventNanos, DCL_DEX_SUBTAG, + expectedNameHash, expectedContentHash); + } + + @Test + public void testGeneratesEvents_nativeLibrary() throws Exception { + new TestNativeCodeWithRetries() { + @Override + protected void loadNativeCode(int tryNumber) throws Exception { + // We need to use a different file name for each retry, because once a file is + // loaded, re-loading it has no effect. + String privateCopyName = "copied" + tryNumber + ".so"; + File privateCopyFile = privateFile(privateCopyName); + mExpectedNameHash = hashOf(privateCopyName); + mExpectedContentHash = copyAndHashResource( + libraryPath("DynamicCodeLoggerNativeTestLibrary.so"), privateCopyFile); + + System.load(privateCopyFile.toString()); + } + }.runTest(); + } + + @Test + public void testGeneratesEvents_nativeLibrary_escapedName() throws Exception { + new TestNativeCodeWithRetries() { + @Override + protected void loadNativeCode(int tryNumber) throws Exception { + // A file name with a space will be escaped in the audit log; verify we un-escape it + // correctly. + String privateCopyName = "second copy " + tryNumber + ".so"; + File privateCopyFile = privateFile(privateCopyName); + mExpectedNameHash = hashOf(privateCopyName); + mExpectedContentHash = copyAndHashResource( + libraryPath("DynamicCodeLoggerNativeTestLibrary.so"), privateCopyFile); + + System.load(privateCopyFile.toString()); + } + }.runTest(); + } + + @Test + public void testGeneratesEvents_nativeExecutable() throws Exception { + new TestNativeCodeWithRetries() { + @Override + protected void loadNativeCode(int tryNumber) throws Exception { + String privateCopyName = "test_executable" + tryNumber; + File privateCopyFile = privateFile(privateCopyName); + mExpectedNameHash = hashOf(privateCopyName); + mExpectedContentHash = copyAndHashResource( + "/DynamicCodeLoggerNativeExecutable", privateCopyFile); + assertThat(privateCopyFile.setExecutable(true)).isTrue(); + + Process process = Runtime.getRuntime().exec(privateCopyFile.toString()); + int exitCode = process.waitFor(); + assertThat(exitCode).isEqualTo(0); + } + }.runTest(); + } + + @Test + public void testGeneratesEvents_spoofed_validFile() throws Exception { + File privateCopyFile = privateFile("spoofed"); + + String expectedContentHash = copyAndHashResource( + "/DynamicCodeLoggerNativeExecutable", privateCopyFile); + + EventLog.writeEvent(EventLog.getTagCode("auditd"), + "type=1400 avc: granted { execute_no_trans } " + + "path=\"" + privateCopyFile + "\" " + + "scontext=u:r:untrusted_app_27: " + + "tcontext=u:object_r:app_data_file: " + + "tclass=file "); + + String expectedNameHash = + "1CF36F503A02877BB775DC23C1C5A47A95F2684B6A1A83B11795B856D88861E3"; + + // Run the job to scan generated audit log entries + runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID); + + // And then make sure we log events about it + long previousEventNanos = mostRecentEventTimeNanos(); + runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID); + + assertDclLoggedSince(previousEventNanos, DCL_NATIVE_SUBTAG, + expectedNameHash, expectedContentHash); + } + + @Test + public void testGeneratesEvents_spoofed_pathTraversal() throws Exception { + File privateDir = privateFile("x").getParentFile(); + + // Transform /a/b/c -> /a/b/c/../../.. so we get back to the root + File pathTraversalToRoot = privateDir; + File root = new File("/"); + while (!privateDir.equals(root)) { + pathTraversalToRoot = new File(pathTraversalToRoot, ".."); + privateDir = privateDir.getParentFile(); + } + + File spoofedFile = new File(pathTraversalToRoot, "dev/urandom"); + + assertWithMessage("Expected " + spoofedFile + " to be readable") + .that(spoofedFile.canRead()).isTrue(); + + EventLog.writeEvent(EventLog.getTagCode("auditd"), + "type=1400 avc: granted { execute_no_trans } " + + "path=\"" + spoofedFile + "\" " + + "scontext=u:r:untrusted_app_27: " + + "tcontext=u:object_r:app_data_file: " + + "tclass=file "); + + String expectedNameHash = + "65528FE876BD676B0DFCC9A8ACA8988E026766F99EEC1E1FB48F46B2F635E225"; + + // Run the job to scan generated audit log entries + runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID); + + // And then trigger generating DCL events + long previousEventNanos = mostRecentEventTimeNanos(); + runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID); + + assertNoDclLoggedSince(previousEventNanos, DCL_NATIVE_SUBTAG, expectedNameHash); + } + + @Test + public void testGeneratesEvents_spoofed_otherAppFile() throws Exception { + File ourPath = sContext.getDatabasePath("android_pay"); + File targetPath = new File(ourPath.toString() + .replace("com.android.frameworks.dynamiccodeloggertest", "com.google.android.gms")); + + assertWithMessage("Expected " + targetPath + " to not be readable") + .that(targetPath.canRead()).isFalse(); + + EventLog.writeEvent(EventLog.getTagCode("auditd"), + "type=1400 avc: granted { execute_no_trans } " + + "path=\"" + targetPath + "\" " + + "scontext=u:r:untrusted_app_27: " + + "tcontext=u:object_r:app_data_file: " + + "tclass=file "); + + String expectedNameHash = + "CBE04E8AB9E7199FC19CBAAF9C774B88E56B3B19E823F2251693380AD6F515E6"; + + // Run the job to scan generated audit log entries + runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID); + + // And then trigger generating DCL events + long previousEventNanos = mostRecentEventTimeNanos(); + runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID); + + assertNoDclLoggedSince(previousEventNanos, DCL_NATIVE_SUBTAG, expectedNameHash); + } + + // Abstract out the logic for running a native code loading test multiple times if needed and + // leaving time for audit messages to reach the log. + private abstract class TestNativeCodeWithRetries { + String mExpectedContentHash; + String mExpectedNameHash; + + abstract void loadNativeCode(int tryNumber) throws Exception; + + final void runTest() throws Exception { + List messages = null; + + for (int i = 0; i < AUDIT_LOG_RETRIES; i++) { + loadNativeCode(i); + + SystemClock.sleep(i * RETRY_DELAY_MS); + + // Run the job to scan generated audit log entries + runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID); + + // And then make sure we log events about it + long previousEventNanos = mostRecentEventTimeNanos(); + runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID); + + messages = findMatchingEvents( + previousEventNanos, DCL_NATIVE_SUBTAG, mExpectedNameHash); + if (!messages.isEmpty()) { + break; + } + } + + assertHasDclLog(messages, mExpectedContentHash); + } + } + + private static File privateFile(String name) { + return new File(sContext.getDir("dcl", Context.MODE_PRIVATE), name); + } + + private String libraryPath(final String libraryName) { + // This may be deprecated. but it tells us the ABI of this process which is exactly what we + // want. + return "/lib/" + Build.CPU_ABI + "/" + libraryName; + } + + private static String copyAndHashResource(String resourcePath, File copyTo) throws Exception { + MessageDigest hasher = MessageDigest.getInstance(SHA_256); + + // Copy the jar from our Java resources to a private data directory + Class thisClass = DynamicCodeLoggerIntegrationTests.class; + try (InputStream input = thisClass.getResourceAsStream(resourcePath); + OutputStream output = new FileOutputStream(copyTo)) { + byte[] buffer = new byte[1024]; + while (true) { + int numRead = input.read(buffer); + if (numRead < 0) { + break; + } + output.write(buffer, 0, numRead); + hasher.update(buffer, 0, numRead); + } + } + + // Compute the SHA-256 of the file content so we can check that it is the same as the value + // we see logged. + return toHexString(hasher); + } + + private String hashOf(String input) throws Exception { + MessageDigest hasher = MessageDigest.getInstance(SHA_256); + hasher.update(input.getBytes()); + return toHexString(hasher); + } + + private static String toHexString(MessageDigest hasher) { + Formatter formatter = new Formatter(); + for (byte b : hasher.digest()) { + formatter.format("%02X", b); + } + + return formatter.toString(); + } + + private static void runDynamicCodeLoggingJob(int jobId) throws Exception { + // This forces the DynamicCodeLoggingService job to start now. + runCommand("cmd jobscheduler run -f android " + jobId); + // Wait for the job to have run. + long startTime = SystemClock.elapsedRealtime(); + while (true) { + String response = runCommand( + "cmd jobscheduler get-job-state android " + jobId); + if (!response.contains("pending") && !response.contains("active")) { + break; + } + // Don't wait forever - if it's taken > 10s then something is very wrong. + if (SystemClock.elapsedRealtime() - startTime > TimeUnit.SECONDS.toMillis(10)) { + throw new AssertionError("Job has not completed: " + response); + } + SystemClock.sleep(100); + } + } + + private static String runCommand(String command) throws Exception { + ByteArrayOutputStream response = new ByteArrayOutputStream(); + byte[] buffer = new byte[1000]; + UiAutomation ui = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + ParcelFileDescriptor fd = ui.executeShellCommand(command); + try (InputStream input = new ParcelFileDescriptor.AutoCloseInputStream(fd)) { + while (true) { + int count = input.read(buffer); + if (count == -1) { + break; + } + response.write(buffer, 0, count); + } + } + return response.toString("UTF-8"); + } + + private static long mostRecentEventTimeNanos() throws Exception { + List events = readSnetEvents(); + return events.isEmpty() ? 0 : events.get(events.size() - 1).getTimeNanos(); + } + + private static void assertDclLoggedSince(long previousEventNanos, String expectedSubTag, + String expectedNameHash, String expectedContentHash) throws Exception { + List messages = + findMatchingEvents(previousEventNanos, expectedSubTag, expectedNameHash); + + assertHasDclLog(messages, expectedContentHash); + } + + private static void assertHasDclLog(List messages, String expectedContentHash) { + assertWithMessage("Expected exactly one matching log entry").that(messages).hasSize(1); + assertThat(messages.get(0)).endsWith(expectedContentHash); + } + + private static void assertNoDclLoggedSince(long previousEventNanos, String expectedSubTag, + String expectedNameHash) throws Exception { + List messages = + findMatchingEvents(previousEventNanos, expectedSubTag, expectedNameHash); + + assertWithMessage("Expected no matching log entries").that(messages).isEmpty(); + } + + private static List findMatchingEvents(long previousEventNanos, String expectedSubTag, + String expectedNameHash) throws Exception { + List messages = new ArrayList<>(); + + for (Event event : readSnetEvents()) { + if (event.getTimeNanos() <= previousEventNanos) { + continue; + } + + Object data = event.getData(); + if (!(data instanceof Object[])) { + continue; + } + Object[] fields = (Object[]) data; + + // We only care about DCL events that we generated. + String subTag = (String) fields[0]; + if (!expectedSubTag.equals(subTag)) { + continue; + } + int uid = (int) fields[1]; + if (uid != sMyUid) { + continue; + } + + String message = (String) fields[2]; + if (!message.startsWith(expectedNameHash)) { + continue; + } + + messages.add(message); + //assertThat(message).endsWith(expectedContentHash); + } + return messages; + } + + private static List readSnetEvents() throws Exception { + List events = new ArrayList<>(); + EventLog.readEvents(new int[] { SNET_TAG }, events); + return events; + } + + /** + * A class loader that does nothing useful, but importantly doesn't extend BaseDexClassLoader. + */ + private static class UnknownClassLoader extends ClassLoader { + UnknownClassLoader(ClassLoader parent) { + super(parent); + } + } +} diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp b/tests/DynamicCodeLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp new file mode 100644 index 000000000000..060888310b51 --- /dev/null +++ b/tests/DynamicCodeLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp @@ -0,0 +1,22 @@ +/* + * Copyright 2019 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. + */ + +#include "jni.h" + +extern "C" jint JNI_OnLoad(JavaVM* /* vm */, void* /* reserved */) +{ + return JNI_VERSION_1_6; +} diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/cpp/test_executable.cpp b/tests/DynamicCodeLoggerIntegrationTests/src/cpp/test_executable.cpp new file mode 100644 index 000000000000..ad025e696dec --- /dev/null +++ b/tests/DynamicCodeLoggerIntegrationTests/src/cpp/test_executable.cpp @@ -0,0 +1,20 @@ +/* + * Copyright 2019 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. + */ + +int main() { + // This program just has to run, it doesn't need to do anything. So we don't. + return 0; +} -- cgit v1.2.3-59-g8ed1b From fc9a21de684f24f0005be43d0113b504bd5990fc Mon Sep 17 00:00:00 2001 From: Alan Stokes Date: Wed, 27 Feb 2019 21:30:59 +0000 Subject: Detect native code loading by untrusted_app. Modify the regex to cover untrusted_app as well as untrusted_app_25 and untrusted_app_27. Add a test to verify. Bug: 126536482 Test: atest DynamicCodeLoggerIntegrationsTests Change-Id: Ie4cbabfb55a5e78868cc6ee8ec46270ab3bf75d1 --- .../server/pm/DynamicCodeLoggingService.java | 2 +- .../pm/dex/DynamicCodeLoggerIntegrationTests.java | 28 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'tests/DynamicCodeLoggerIntegrationTests') diff --git a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java index d53d81cf0860..a1ff76fc8c09 100644 --- a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java +++ b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java @@ -61,7 +61,7 @@ public class DynamicCodeLoggingService extends JobService { private static final Pattern EXECUTE_NATIVE_AUDIT_PATTERN = Pattern.compile(".*\\bavc: granted \\{ execute(?:_no_trans|) \\} .*" + "\\bpath=(?:\"([^\" ]*)\"|([0-9A-F]+)) .*" - + "\\bscontext=u:r:untrusted_app_2(?:5|7):.*" + + "\\bscontext=u:r:untrusted_app(?:_25|_27)?:.*" + "\\btcontext=u:object_r:app_data_file:.*" + "\\btclass=file\\b.*"); diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java index 8ef15d869a0b..4f9aeea5bdb4 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java +++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java @@ -234,6 +234,34 @@ public final class DynamicCodeLoggerIntegrationTests { expectedNameHash, expectedContentHash); } + @Test + public void testGeneratesEvents_spoofed_validFile_untrustedApp() throws Exception { + File privateCopyFile = privateFile("spoofed2"); + + String expectedContentHash = copyAndHashResource( + "/DynamicCodeLoggerNativeExecutable", privateCopyFile); + + EventLog.writeEvent(EventLog.getTagCode("auditd"), + "type=1400 avc: granted { execute_no_trans } " + + "path=\"" + privateCopyFile + "\" " + + "scontext=u:r:untrusted_app: " + + "tcontext=u:object_r:app_data_file: " + + "tclass=file "); + + String expectedNameHash = + "3E57AA59249154C391316FDCF07C1D499C26A564E4D305833CCD9A98ED895AC9"; + + // Run the job to scan generated audit log entries + runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID); + + // And then make sure we log events about it + long previousEventNanos = mostRecentEventTimeNanos(); + runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID); + + assertDclLoggedSince(previousEventNanos, DCL_NATIVE_SUBTAG, + expectedNameHash, expectedContentHash); + } + @Test public void testGeneratesEvents_spoofed_pathTraversal() throws Exception { File privateDir = privateFile("x").getParentFile(); -- cgit v1.2.3-59-g8ed1b From 502ec7ae4bf0aa26e34a01efdf81116de6907809 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Fri, 1 Mar 2019 14:43:20 -0800 Subject: Migrate remainder of frameworks/base to androidx.test See go/jetpack-test-android-migration Exempt-From-Owner-Approval: automated package name refactoring Test: m m -j BroadcastRadioTests KeystoreTests mediaframeworktest ActivityManagerPerfTests AppLaunch AppLaunchWear BackgroundDexOptServiceIntegrationTests AppCompatibilityTest DynamicCodeLoggerIntegrationTests FlickerLibTest InternalTests PackageWatchdogTest RcsTests RollbackTestAppAv1 RollbackTestAppAv2 RollbackTestAppACrashingV2 RollbackTestAppBv1 RollbackTestAppBv2 RollbackTestAppASplitV1 RollbackTestAppASplitV2 RollbackTest ServiceCrashTest UsageStatsPerfTests UsbTests WindowAnimationJank Change-Id: I32fe3297656eec6060da6c7e24582bcd5315fb16 --- core/tests/BroadcastRadioTests/Android.mk | 2 +- keystore/tests/Android.mk | 2 +- keystore/tests/AndroidManifest.xml | 2 +- .../ParcelableKeyGenParameterSpecTest.java | 12 ++++--- .../security/keystore/KeyGenParameterSpecTest.java | 6 ++-- media/tests/MediaFrameworkTest/Android.mk | 2 +- media/tests/MediaFrameworkTest/AndroidManifest.xml | 2 +- media/tests/MediaFrameworkTest/AndroidTest.xml | 2 +- .../mediaframeworktest/unit/MediaFileTest.java | 3 +- services/tests/runtests.py | 2 +- startop/iorap/tests/Android.bp | 2 +- startop/iorap/tests/AndroidManifest.xml | 2 +- startop/iorap/tests/AndroidTest.xml | 2 +- .../android/startop/iorap/IIorapIntegrationTest.kt | 37 +++++++++++----------- .../android/startop/iorap/ParcelablesTest.kt | 20 ++++++------ startop/view_compiler/dex_builder_test/Android.bp | 2 +- .../dex_builder_test/AndroidManifest.xml | 2 +- .../view_compiler/dex_builder_test/AndroidTest.xml | 2 +- .../src/android/startop/test/DexBuilderTest.java | 12 +++---- .../android/startop/test/LayoutCompilerTest.java | 15 ++++----- tests/ActivityManagerPerfTests/tests/Android.mk | 2 +- .../tests/AndroidManifest.xml | 2 +- .../ActivityManagerPerfTests/tests/AndroidTest.xml | 2 +- .../perftests/am/tests/BasePerfTest.java | 3 +- .../perftests/am/tests/BroadcastPerfTest.java | 5 +-- .../am/tests/ContentProviderPerfTest.java | 5 +-- .../perftests/am/tests/ServiceBindPerfTest.java | 5 +-- .../perftests/am/tests/ServiceStartPerfTest.java | 5 +-- tests/ActivityManagerPerfTests/utils/Android.mk | 2 +- .../frameworks/perftests/am/util/Utils.java | 3 +- tests/AppLaunch/Android.mk | 2 +- .../src/com/android/tests/applaunch/AppLaunch.java | 4 ++- tests/AppLaunchWear/Android.mk | 2 +- .../src/com/android/tests/applaunch/AppLaunch.java | 5 +-- .../Android.mk | 2 +- .../AndroidManifest.xml | 2 +- .../AndroidTest.xml | 2 +- .../BackgroundDexOptServiceIntegrationTests.java | 5 ++- tests/Camera2Tests/CameraToo/tests/Android.mk | 2 +- .../CameraToo/tests/AndroidManifest.xml | 2 +- tests/Compatibility/Android.mk | 2 +- .../compatibilitytest/AppCompatibility.java | 5 +-- .../compatibilitytest/AppCompatibilityRunner.java | 2 +- tests/DynamicCodeLoggerIntegrationTests/Android.mk | 2 +- .../AndroidManifest.xml | 2 +- .../AndroidTest.xml | 2 +- .../pm/dex/DynamicCodeLoggerIntegrationTests.java | 5 +-- tests/FlickerTests/AndroidManifest.xml | 2 +- tests/FlickerTests/lib/Android.mk | 4 +-- .../android/server/wm/flicker/AutomationUtils.java | 3 +- .../server/wm/flicker/TransitionRunner.java | 3 +- .../com/android/server/wm/flicker/WindowUtils.java | 3 +- .../monitor/WindowAnimationFrameStatsMonitor.java | 2 +- tests/FlickerTests/lib/test/Android.mk | 2 +- tests/FlickerTests/lib/test/AndroidManifest.xml | 2 +- .../android/server/wm/flicker/LayersTraceTest.java | 3 +- .../android/server/wm/flicker/TestFileUtils.java | 3 +- .../WindowAnimationFrameStatsMonitorTest.java | 4 +-- .../server/wm/flicker/ChangeAppRotationTest.java | 5 +-- .../server/wm/flicker/CloseImeWindowToAppTest.java | 7 ++-- .../wm/flicker/CloseImeWindowToHomeTest.java | 7 ++-- .../server/wm/flicker/CommonTransitions.java | 3 +- .../com/android/server/wm/flicker/DebugTest.java | 5 +-- .../android/server/wm/flicker/FlickerTestBase.java | 3 +- .../android/server/wm/flicker/OpenAppColdTest.java | 6 ++-- .../wm/flicker/OpenAppToSplitScreenTest.java | 6 ++-- .../android/server/wm/flicker/OpenAppWarmTest.java | 6 ++-- .../server/wm/flicker/OpenImeWindowTest.java | 4 +-- .../server/wm/flicker/ResizeSplitScreenTest.java | 7 ++-- .../server/wm/flicker/SeamlessAppRotationTest.java | 5 +-- .../wm/flicker/SplitScreenToLauncherTest.java | 8 ++--- tests/Internal/Android.mk | 2 +- tests/Internal/AndroidManifest.xml | 2 +- tests/Internal/AndroidTest.xml | 2 +- .../src/android/app/WallpaperColorsTest.java | 5 +-- .../src/android/app/WallpaperInfoTest.java | 7 ++-- .../service/wallpaper/WallpaperServiceTest.java | 2 +- .../colorextraction/ColorExtractorTest.java | 7 ++-- .../internal/colorextraction/types/TonalTest.java | 7 ++-- .../android/internal/graphics/ColorUtilsTest.java | 7 ++-- .../android/internal/ml/clustering/KMeansTest.java | 5 +-- tests/PackageWatchdog/Android.mk | 2 +- tests/PackageWatchdog/AndroidManifest.xml | 2 +- .../com/android/server/PackageWatchdogTest.java | 3 +- tests/RcsTests/Android.mk | 2 +- tests/RcsTests/AndroidManifest.xml | 2 +- .../ims/RcsGroupThreadIconChangedEventTest.java | 3 +- .../ims/RcsGroupThreadNameChangedEventTest.java | 3 +- .../RcsGroupThreadParticipantJoinedEventTest.java | 3 +- .../RcsGroupThreadParticipantLeftEventTest.java | 3 +- .../ims/RcsParticipantAliasChangedEventTest.java | 3 +- .../tests/ims/RcsParticipantQueryParamsTest.java | 3 +- .../tests/ims/RcsThreadQueryParamsTest.java | 3 +- tests/RollbackTest/Android.mk | 2 +- tests/RollbackTest/RollbackTest.xml | 2 +- .../RollbackTest/RollbackTest/AndroidManifest.xml | 2 +- .../android/tests/rollback/LocalIntentSender.java | 3 +- .../tests/rollback/RollbackBroadcastReceiver.java | 3 +- .../com/android/tests/rollback/RollbackTest.java | 11 ++++--- .../android/tests/rollback/RollbackTestUtils.java | 11 ++++--- tests/ServiceCrashTest/Android.mk | 2 +- tests/UsageStatsPerfTests/Android.mk | 2 +- tests/UsageStatsPerfTests/AndroidManifest.xml | 2 +- tests/UsageStatsPerfTests/AndroidTest.xml | 2 +- .../usage/tests/UsageStatsDatabasePerfTest.java | 7 ++-- tests/UsbTests/Android.mk | 2 +- tests/UsbTests/AndroidManifest.xml | 2 +- tests/UsbTests/AndroidTest.xml | 2 +- .../server/usb/UsbDescriptorParserTests.java | 20 ++++++------ .../src/com/android/server/usb/UsbHandlerTest.java | 8 ++--- tests/WindowAnimationJank/Android.mk | 2 +- .../FullscreenRotationTest.java | 5 +-- .../WindowAnimationJankTestBase.java | 6 ++-- 113 files changed, 265 insertions(+), 225 deletions(-) (limited to 'tests/DynamicCodeLoggerIntegrationTests') diff --git a/core/tests/BroadcastRadioTests/Android.mk b/core/tests/BroadcastRadioTests/Android.mk index 6b0484ec366d..faffc4b28a58 100644 --- a/core/tests/BroadcastRadioTests/Android.mk +++ b/core/tests/BroadcastRadioTests/Android.mk @@ -25,7 +25,7 @@ LOCAL_MODULE_TAGS := tests # LOCAL_SDK_VERSION := current LOCAL_PRIVATE_PLATFORM_APIS := true -LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util androidx.test.rules testng +LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt androidx.test.rules testng LOCAL_JAVA_LIBRARIES := android.test.base diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk index 596e5f530970..99d3197f8bf3 100644 --- a/keystore/tests/Android.mk +++ b/keystore/tests/Android.mk @@ -21,7 +21,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test + androidx.test.rules hamcrest-library LOCAL_PACKAGE_NAME := KeystoreTests LOCAL_PRIVATE_PLATFORM_APIS := true diff --git a/keystore/tests/AndroidManifest.xml b/keystore/tests/AndroidManifest.xml index 9bf2d0c761e6..6833cd1e35b9 100644 --- a/keystore/tests/AndroidManifest.xml +++ b/keystore/tests/AndroidManifest.xml @@ -20,7 +20,7 @@ - diff --git a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java index 32f8ec44d11f..fca2775a34bb 100644 --- a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java +++ b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java @@ -22,16 +22,20 @@ import static org.junit.Assert.assertThat; import android.os.Parcel; import android.security.keystore.KeyGenParameterSpec; -import android.security.keystore.ParcelableKeyGenParameterSpec; import android.security.keystore.KeyProperties; -import android.support.test.runner.AndroidJUnit4; +import android.security.keystore.ParcelableKeyGenParameterSpec; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + import java.math.BigInteger; import java.security.spec.ECGenParameterSpec; import java.security.spec.RSAKeyGenParameterSpec; import java.util.Date; + import javax.security.auth.x500.X500Principal; -import org.junit.Test; -import org.junit.runner.RunWith; /** Unit tests for {@link ParcelableKeyGenParameterSpec}. */ @RunWith(AndroidJUnit4.class) diff --git a/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java b/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java index 865cad472eb5..b2edfd05d13f 100644 --- a/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java +++ b/keystore/tests/src/android/security/keystore/KeyGenParameterSpecTest.java @@ -20,10 +20,12 @@ import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import android.security.ParcelableKeyGenParameterSpecTest; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; -import android.security.ParcelableKeyGenParameterSpecTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk index fb473f0581c9..167d255af74c 100644 --- a/media/tests/MediaFrameworkTest/Android.mk +++ b/media/tests/MediaFrameworkTest/Android.mk @@ -9,7 +9,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_STATIC_JAVA_LIBRARIES := \ mockito-target-minus-junit4 \ - android-support-test \ + androidx.test.rules \ android-ex-camera2 LOCAL_PACKAGE_NAME := mediaframeworktest diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml index e50a3757d14f..fb2d630faaf6 100644 --- a/media/tests/MediaFrameworkTest/AndroidManifest.xml +++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml @@ -86,7 +86,7 @@ android:label="MediaFramework integration tests InstrumentationRunner"> - diff --git a/media/tests/MediaFrameworkTest/AndroidTest.xml b/media/tests/MediaFrameworkTest/AndroidTest.xml index 204959ff2749..132028ce98dc 100644 --- a/media/tests/MediaFrameworkTest/AndroidTest.xml +++ b/media/tests/MediaFrameworkTest/AndroidTest.xml @@ -21,7 +21,7 @@