1 /* 2 * Copyright (C) 2019 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.compatibility.common.util; 18 19 import java.io.BufferedReader; 20 import java.io.IOException; 21 import java.io.InputStreamReader; 22 import org.json.JSONArray; 23 import org.json.JSONException; 24 import org.json.JSONObject; 25 import org.junit.Assert; 26 import org.junit.Before; 27 import org.junit.Test; 28 import org.junit.runner.RunWith; 29 import org.junit.runners.JUnit4; 30 import java.util.regex.Pattern; 31 32 /** Unit tests for {@link CrashUtils}. */ 33 @RunWith(JUnit4.class) 34 public class CrashUtilsTest { 35 36 private JSONArray mCrashes; 37 38 @Before setUp()39 public void setUp() throws IOException { 40 try (BufferedReader txtReader = 41 new BufferedReader( 42 new InputStreamReader( 43 getClass().getClassLoader().getResourceAsStream("logcat.txt")))) { 44 StringBuffer input = new StringBuffer(); 45 String tmp; 46 while ((tmp = txtReader.readLine()) != null) { 47 input.append(tmp + "\n"); 48 } 49 mCrashes = CrashUtils.addAllCrashes(input.toString(), new JSONArray()); 50 } 51 } 52 53 @Test testGetAllCrashes()54 public void testGetAllCrashes() throws Exception { 55 JSONArray expectedResults = new JSONArray(); 56 expectedResults.put(createCrashJson( 57 11071, 11189, "AudioOut_D", "/system/bin/audioserver", "e9380000", "SIGSEGV", null)); 58 expectedResults.put(createCrashJson( 59 12736, 12761, "Binder:12736_2", "/system/bin/audioserver", "0", "SIGSEGV", null)); 60 expectedResults.put(createCrashJson( 61 26201, 26227, "Binder:26201_3", "/system/bin/audioserver", "0", "SIGSEGV", null)); 62 expectedResults.put(createCrashJson( 63 26246, 26282, "Binder:26246_5", "/system/bin/audioserver", "0", "SIGSEGV", null)); 64 expectedResults.put(createCrashJson( 65 245, 245, "installd", "/system/bin/installd", null, "SIGABRT", 66 "'utils.cpp:67] Check failed: is_valid_package_name(package_name) == 0 '")); 67 expectedResults.put(createCrashJson( 68 6371, 8072, "media.codec", "omx@1.0-service", "ed000000", "SIGSEGV", null)); 69 expectedResults.put(createCrashJson( 70 8373, 8414, "loo", "com.android.bluetooth", null, "SIGABRT", 71 "'[FATAL:allocation_tracker.cc(143)] Check failed: map_entry != allocations.end().")); 72 expectedResults.put(createCrashJson( 73 8080, 11665, "generic", "/system/bin/mediaserver", null, "SIGABRT", 74 "'frameworks/av/media/libstagefright/MPEG4Extractor.cpp:6853 CHECK_EQ( (unsigned)ptr[0],1u) failed: 129 vs. 1'")); 75 expectedResults.put(createCrashJson( 76 11071, 11189, "synthetic_thread", "synthetic_process_0", "e9380000", "SIGSEGV", null)); 77 expectedResults.put(createCrashJson( 78 12736, 12761, "synthetic_thread", "synthetic_process_1", "0", "SIGSEGV", null)); 79 80 Assert.assertEquals(expectedResults.toString() + "\n" + mCrashes.toString() + "\n", expectedResults.toString(), mCrashes.toString()); 81 } 82 createCrashJson( int pid, int tid, String name, String process, String faultaddress, String signal, String abortMessage)83 public JSONObject createCrashJson( 84 int pid, 85 int tid, 86 String name, 87 String process, 88 String faultaddress, 89 String signal, 90 String abortMessage) { 91 JSONObject json = new JSONObject(); 92 try { 93 json.put(CrashUtils.PID, pid); 94 json.put(CrashUtils.TID, tid); 95 json.put(CrashUtils.NAME, name); 96 json.put(CrashUtils.PROCESS, process); 97 json.put(CrashUtils.FAULT_ADDRESS, faultaddress); 98 json.put(CrashUtils.SIGNAL, signal); 99 json.put(CrashUtils.ABORT_MESSAGE, abortMessage); 100 } catch (JSONException e) {} 101 return json; 102 } 103 104 @Test testValidCrash()105 public void testValidCrash() throws Exception { 106 Assert.assertTrue(CrashUtils.securityCrashDetected(mCrashes, new CrashUtils.Config() 107 .checkMinAddress(true) 108 .setProcessPatterns(Pattern.compile("synthetic_process_0")))); 109 } 110 111 @Test testMissingName()112 public void testMissingName() throws Exception { 113 Assert.assertFalse(CrashUtils.securityCrashDetected(mCrashes, new CrashUtils.Config() 114 .checkMinAddress(true) 115 .setProcessPatterns(Pattern.compile("")))); 116 } 117 118 @Test testSIGABRT()119 public void testSIGABRT() throws Exception { 120 Assert.assertFalse(CrashUtils.securityCrashDetected(mCrashes, new CrashUtils.Config() 121 .checkMinAddress(true) 122 .setProcessPatterns(Pattern.compile("installd")))); 123 } 124 125 @Test testFaultAddressBelowMin()126 public void testFaultAddressBelowMin() throws Exception { 127 Assert.assertFalse(CrashUtils.securityCrashDetected(mCrashes, new CrashUtils.Config() 128 .checkMinAddress(true) 129 .setProcessPatterns(Pattern.compile("synthetic_process_1")))); 130 } 131 132 @Test testIgnoreMinAddressCheck()133 public void testIgnoreMinAddressCheck() throws Exception { 134 Assert.assertTrue(CrashUtils.securityCrashDetected(mCrashes, new CrashUtils.Config() 135 .checkMinAddress(false) 136 .setProcessPatterns(Pattern.compile("synthetic_process_1")))); 137 } 138 139 @Test testBadAbortMessage()140 public void testBadAbortMessage() throws Exception { 141 Assert.assertFalse(CrashUtils.securityCrashDetected(mCrashes, new CrashUtils.Config() 142 .checkMinAddress(true) 143 .setProcessPatterns(Pattern.compile("generic")))); 144 } 145 146 @Test testGoodAndBadCrashes()147 public void testGoodAndBadCrashes() throws Exception { 148 Assert.assertTrue(CrashUtils.securityCrashDetected(mCrashes, new CrashUtils.Config() 149 .checkMinAddress(true) 150 .setProcessPatterns( 151 Pattern.compile("synthetic_process_0"), 152 Pattern.compile("generic")))); 153 } 154 155 @Test testNullFaultAddress()156 public void testNullFaultAddress() throws Exception { 157 JSONArray crashes = new JSONArray(); 158 crashes.put(createCrashJson(8373, 8414, "loo", "com.android.bluetooth", null, "SIGSEGV", "")); 159 Assert.assertTrue(CrashUtils.securityCrashDetected(crashes, new CrashUtils.Config() 160 .checkMinAddress(true) 161 .setProcessPatterns(Pattern.compile("com\\.android\\.bluetooth")))); 162 } 163 164 @Test testAbortMessageInclude()165 public void testAbortMessageInclude() throws Exception { 166 JSONArray crashes = new JSONArray(); 167 crashes.put(createCrashJson(8373, 8414, "loo", "com.android.bluetooth", null, "SIGABRT", 168 "'[FATAL:allocation_tracker.cc(143)] Check failed: map_entry != allocations.end().")); 169 Assert.assertTrue(CrashUtils.securityCrashDetected(crashes, new CrashUtils.Config() 170 .appendSignals(CrashUtils.SIGABRT) 171 .appendAbortMessageIncludes("Check failed:") 172 .setProcessPatterns(Pattern.compile("com\\.android\\.bluetooth")))); 173 174 Assert.assertFalse(CrashUtils.securityCrashDetected(crashes, new CrashUtils.Config() 175 .appendSignals(CrashUtils.SIGABRT) 176 .appendAbortMessageIncludes("include not matches") 177 .setProcessPatterns(Pattern.compile("com\\.android\\.bluetooth")))); 178 } 179 180 @Test testAbortMessageExclude()181 public void testAbortMessageExclude() throws Exception { 182 JSONArray crashes = new JSONArray(); 183 crashes.put(createCrashJson(8373, 8414, "loo", "com.android.bluetooth", null, "SIGABRT", 184 "'[FATAL:allocation_tracker.cc(143)] Check failed: map_entry != allocations.end().")); 185 Assert.assertFalse(CrashUtils.securityCrashDetected(crashes, new CrashUtils.Config() 186 .appendSignals(CrashUtils.SIGABRT) 187 .appendAbortMessageExcludes("Check failed:") 188 .setProcessPatterns(Pattern.compile("com\\.android\\.bluetooth")))); 189 190 Assert.assertTrue(CrashUtils.securityCrashDetected(crashes, new CrashUtils.Config() 191 .appendSignals(CrashUtils.SIGABRT) 192 .appendAbortMessageExcludes("exclude not matches") 193 .setProcessPatterns(Pattern.compile("com\\.android\\.bluetooth")))); 194 } 195 196 @Test testAbortMessageExcludeCannotLink()197 public void testAbortMessageExcludeCannotLink() throws Exception { 198 JSONArray crashes = new JSONArray(); 199 crashes.put(createCrashJson( 200 18959, 18959, "CVE-2020-0073", "/data/local/tmp/CVE-2020-0073", null, "SIGABRT", 201 "'CANNOT LINK EXECUTABLE \"/data/local/tmp/CVE-2020-0073\": library " 202 + "\"libnfc-nci.so\" (\"(default)\", \"/data/local/tmp/CVE-2020-0073\", \"\") " 203 + "not found'")); 204 Assert.assertFalse(CrashUtils.securityCrashDetected(crashes, new CrashUtils.Config() 205 .appendSignals(CrashUtils.SIGABRT) 206 .setProcessPatterns(Pattern.compile("CVE-2020-0073")))); 207 208 crashes.put(createCrashJson( 209 5105, 5105, "CVE-2015-6616-2", "/data/local/tmp/CVE-2015-6616-2", null, "SIGABRT", 210 "'CANNOT LINK EXECUTABLE \"/data/local/tmp/CVE-2015-6616-2\": " 211 + "cannot locate symbol \"" 212 + "_ZN7android14MediaExtractor17CreateFromServiceERKNS_2spINS_10DataSourceEEEPKc" 213 + "\" referenced by \"/data/local/tmp/CVE-2015-6616-2\"...'")); 214 Assert.assertFalse(CrashUtils.securityCrashDetected(crashes, new CrashUtils.Config() 215 .appendSignals(CrashUtils.SIGABRT) 216 .setProcessPatterns(Pattern.compile("CVE-2015-6616-2")))); 217 218 } 219 } 220