summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuy Truong <duytruong@google.com>2021-10-27 22:22:20 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-10-27 22:22:20 +0000
commite48ac12d35320e912a07b19147ba9a24984d4351 (patch)
treecc29982bbc39ddf62052ae614174e74f28047992
parentced436b3eeb11c59ca12e7832c4c21bea0d237ea (diff)
parente03111efb55a5ae2323b3a84d0e7798d5dce0e71 (diff)
downloadplatform_testing-e48ac12d35320e912a07b19147ba9a24984d4351.tar.gz
CP from aosp/1854060 am: e03111efb5
Original change: https://googleplex-android-review.googlesource.com/c/platform/platform_testing/+/16125754 Change-Id: I471b775f4988bc66bdcee040b826ad1c28f29787
-rw-r--r--libraries/compatibility-common-util/src/com/android/compatibility/common/util/CrashUtils.java132
-rw-r--r--libraries/compatibility-common-util/tests/src/com/android/compatibility/common/util/CrashUtilsTest.java156
2 files changed, 274 insertions, 14 deletions
diff --git a/libraries/compatibility-common-util/src/com/android/compatibility/common/util/CrashUtils.java b/libraries/compatibility-common-util/src/com/android/compatibility/common/util/CrashUtils.java
index 785139595..5e0d12718 100644
--- a/libraries/compatibility-common-util/src/com/android/compatibility/common/util/CrashUtils.java
+++ b/libraries/compatibility-common-util/src/com/android/compatibility/common/util/CrashUtils.java
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.math.BigInteger;
import org.json.JSONArray;
@@ -68,8 +69,7 @@ public class CrashUtils {
"\\w+? \\d+? \\((.*?)\\), code -*?\\d+? \\(.*?\\), fault addr "
+ "(?:0x(\\p{XDigit}+)|-+)");
// Matches the abort message line
- private static Pattern sAbortMessagePattern =
- Pattern.compile("(?i)Abort message: (.*)");
+ private static Pattern sAbortMessagePattern = Pattern.compile("(?i)Abort message: (.*)");
// Matches one backtrace NOTE line, exactly as tombstone_proto_to_text's print_thread_backtrace
private static Pattern sBacktraceNotePattern =
Pattern.compile("[0-9\\-\\s:.]+[A-Z] DEBUG\\s+:\\s+NOTE: .*");
@@ -172,6 +172,37 @@ public class CrashUtils {
continue;
}
}
+
+ JSONArray backtrace = crash.getJSONArray(BACKTRACE);
+
+ /* if backtrace "includes" patterns are present, ignore this crash if there is no
+ * frame that matches any of the patterns
+ */
+ List<Config.BacktraceFilterPattern> backtraceIncludes =
+ config.getBacktraceIncludes();
+ if (!backtraceIncludes.isEmpty()) {
+ if (!IntStream.range(0, backtrace.length())
+ .mapToObj(j -> backtrace.optJSONObject(j))
+ .flatMap(frame -> backtraceIncludes.stream().map(p -> p.match(frame)))
+ .anyMatch(matched -> matched)) {
+ continue;
+ }
+ }
+
+ /* if backtrace "excludes" patterns are present, ignore this crash if there is any
+ * frame that matches any of the patterns
+ */
+ List<Config.BacktraceFilterPattern> backtraceExcludes =
+ config.getBacktraceExcludes();
+ if (!backtraceExcludes.isEmpty()) {
+ if (IntStream.range(0, backtrace.length())
+ .mapToObj(j -> backtrace.optJSONObject(j))
+ .flatMap(frame -> backtraceExcludes.stream().map(p -> p.match(frame)))
+ .anyMatch(matched -> matched)) {
+ continue;
+ }
+ }
+
securityCrashes.put(crash);
} catch (JSONException | NullPointerException e) {}
}
@@ -208,10 +239,12 @@ public class CrashUtils {
if (pidtidNameMatcher.find()) {
try {
pid = Integer.parseInt(pidtidNameMatcher.group(1));
- } catch (NumberFormatException e) {}
+ } catch (NumberFormatException e) {
+ }
try {
tid = Integer.parseInt(pidtidNameMatcher.group(2));
- } catch (NumberFormatException e) {}
+ } catch (NumberFormatException e) {
+ }
name = pidtidNameMatcher.group(3).trim();
process = pidtidNameMatcher.group(4).trim();
}
@@ -223,7 +256,8 @@ public class CrashUtils {
if (faultAddrMatch != null) {
try {
faultAddress = new BigInteger(faultAddrMatch, 16);
- } catch (NumberFormatException e) {}
+ } catch (NumberFormatException e) {
+ }
}
}
@@ -278,8 +312,7 @@ public class CrashUtils {
crash.put(TID, tid);
crash.put(NAME, name);
crash.put(PROCESS, process);
- crash.put(FAULT_ADDRESS,
- faultAddress == null ? null : faultAddress.toString(16));
+ crash.put(FAULT_ADDRESS, faultAddress == null ? null : faultAddress.toString(16));
crash.put(SIGNAL, signal);
crash.put(ABORT_MESSAGE, abortMessage);
JSONArray backtrace = new JSONArray();
@@ -321,6 +354,8 @@ public class CrashUtils {
private List<Pattern> processPatterns;
private List<Pattern> abortMessageIncludes;
private List<Pattern> abortMessageExcludes;
+ private List<BacktraceFilterPattern> backtraceIncludes;
+ private List<BacktraceFilterPattern> backtraceExcludes;
public Config() {
checkMinAddress = true;
@@ -329,6 +364,8 @@ public class CrashUtils {
abortMessageIncludes = new ArrayList<>();
setAbortMessageExcludes("CHECK_", "CANNOT LINK EXECUTABLE");
processPatterns = new ArrayList();
+ backtraceIncludes = new ArrayList();
+ backtraceExcludes = new ArrayList();
}
public Config setMinAddress(BigInteger minCrashAddress) {
@@ -415,6 +452,87 @@ public class CrashUtils {
Collections.addAll(this.processPatterns, processPatterns);
return this;
}
+
+ public Config setBacktraceIncludes(BacktraceFilterPattern... patterns) {
+ this.backtraceIncludes = new ArrayList<>(Arrays.asList(patterns));
+ return this;
+ }
+
+ public List<BacktraceFilterPattern> getBacktraceIncludes() {
+ return Collections.unmodifiableList(this.backtraceIncludes);
+ }
+
+ public Config appendBacktraceIncludes(BacktraceFilterPattern... patterns) {
+ Collections.addAll(this.backtraceIncludes, patterns);
+ return this;
+ }
+
+ public Config setBacktraceExcludes(BacktraceFilterPattern... patterns) {
+ this.backtraceExcludes = new ArrayList<>(Arrays.asList(patterns));
+ return this;
+ }
+
+ public List<BacktraceFilterPattern> getBacktraceExcludes() {
+ return Collections.unmodifiableList(this.backtraceExcludes);
+ }
+
+ public Config appendBacktraceExcludes(BacktraceFilterPattern... patterns) {
+ Collections.addAll(this.backtraceExcludes, patterns);
+ return this;
+ }
+
+ /**
+ * A utility class that contains patterns to filter backtraces on.
+ *
+ * <p>A filter matches if any of the backtrace frame matches any of the patterns.
+ *
+ * <p>Either filenamePattern or methodPattern can be null, in which case it will act like a
+ * wildcard pattern and matches anything.
+ *
+ * <p>A null filename or method name will not match any non-null pattern.
+ */
+ public static class BacktraceFilterPattern {
+ private final Pattern filenamePattern;
+ private final Pattern methodPattern;
+
+ /**
+ * Constructs a BacktraceFilterPattern with the given file and method name patterns.
+ *
+ * <p>Null patterns are interpreted as wildcards and match anything.
+ *
+ * @param filenamePattern Regex string for the filename pattern. Can be null.
+ * @param methodPattern Regex string for the method name pattern. Can be null.
+ */
+ public BacktraceFilterPattern(String filenamePattern, String methodPattern) {
+ if (filenamePattern == null) {
+ this.filenamePattern = null;
+ } else {
+ this.filenamePattern = Pattern.compile(filenamePattern);
+ }
+
+ if (methodPattern == null) {
+ this.methodPattern = null;
+ } else {
+ this.methodPattern = Pattern.compile(methodPattern);
+ }
+ }
+
+ /** Returns true if the current patterns match a backtrace frame. */
+ public boolean match(JSONObject frame) {
+ if (frame == null) return false;
+
+ String filename = frame.optString(FILENAME);
+ String method = frame.optString(METHOD);
+
+ boolean filenameMatches =
+ (filenamePattern == null
+ || (filename != null && filenamePattern.matcher(filename).find()));
+ boolean methodMatches =
+ (methodPattern == null
+ || (method != null && methodPattern.matcher(method).find()));
+ return filenameMatches && methodMatches;
+ }
+ }
}
private static List<Pattern> toPatterns(String... patternStrings) {
diff --git a/libraries/compatibility-common-util/tests/src/com/android/compatibility/common/util/CrashUtilsTest.java b/libraries/compatibility-common-util/tests/src/com/android/compatibility/common/util/CrashUtilsTest.java
index 78e78be64..92be36639 100644
--- a/libraries/compatibility-common-util/tests/src/com/android/compatibility/common/util/CrashUtilsTest.java
+++ b/libraries/compatibility-common-util/tests/src/com/android/compatibility/common/util/CrashUtilsTest.java
@@ -16,6 +16,7 @@
package com.android.compatibility.common.util;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
import com.google.common.collect.ImmutableList;
import java.io.BufferedReader;
import java.io.IOException;
@@ -501,13 +502,13 @@ public class CrashUtilsTest {
}
public JSONObject createCrashJson(
- int pid,
- int tid,
- String name,
- String process,
- String faultaddress,
- String signal,
- String abortMessage) {
+ int pid,
+ int tid,
+ String name,
+ String process,
+ String faultaddress,
+ String signal,
+ String abortMessage) {
return createCrashJson(
pid, tid, name, process, faultaddress, signal, abortMessage, ImmutableList.of());
}
@@ -656,4 +657,145 @@ public class CrashUtilsTest {
.setProcessPatterns(Pattern.compile("CVE-2015-6616-2"))));
}
+
+ @Test
+ public void testBacktraceFilterIncludeFilename() throws Exception {
+ Assert.assertTrue(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceIncludes(
+ new BacktraceFilterPattern("libaudioutils", null))));
+ Assert.assertTrue(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceIncludes(
+ new BacktraceFilterPattern("libstagefright", null),
+ new BacktraceFilterPattern("libaudioflinger\\.so", null))));
+ Assert.assertFalse(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceIncludes(
+ new BacktraceFilterPattern("libstagefright", null))));
+ }
+
+ @Test
+ public void testBacktraceFilterExcludeFilename() throws Exception {
+ Assert.assertFalse(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceExcludes(
+ new BacktraceFilterPattern("libaudioutils", null))));
+ Assert.assertFalse(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceExcludes(
+ new BacktraceFilterPattern("libstagefright", null),
+ new BacktraceFilterPattern("libaudioflinger\\.so", null))));
+ Assert.assertTrue(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceExcludes(
+ new BacktraceFilterPattern("libstagefright", null))));
+ }
+
+ @Test
+ public void testBacktraceFilterIncludeMethodName() throws Exception {
+ Assert.assertTrue(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceIncludes(
+ new BacktraceFilterPattern(null, "memcpy_to_float"))));
+ Assert.assertTrue(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceIncludes(
+ new BacktraceFilterPattern(null, "strlen"),
+ new BacktraceFilterPattern(null, "memcpy_[^_]+_float"))));
+ Assert.assertFalse(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceIncludes(new BacktraceFilterPattern(null, "strlen"))));
+ }
+
+ @Test
+ public void testBacktraceFilterExcludeMethodName() throws Exception {
+ Assert.assertFalse(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceExcludes(
+ new BacktraceFilterPattern(null, "memcpy_to_float"))));
+ Assert.assertFalse(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceExcludes(
+ new BacktraceFilterPattern(null, "strlen"),
+ new BacktraceFilterPattern(null, "memcpy_[^_]+_float"))));
+ Assert.assertTrue(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceExcludes(new BacktraceFilterPattern(null, "strlen"))));
+ }
+
+ @Test
+ public void testBacktraceFilterCombinations() throws Exception {
+ Assert.assertTrue(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceIncludes(new BacktraceFilterPattern(null, null))));
+ Assert.assertTrue(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceIncludes(
+ new BacktraceFilterPattern("libaudioutils", "memcpy"))));
+ Assert.assertFalse(
+ CrashUtils.securityCrashDetected(
+ mCrashes,
+ new CrashUtils.Config()
+ .checkMinAddress(true)
+ .setProcessPatterns(Pattern.compile("synthetic_process_0"))
+ .setBacktraceIncludes(
+ new BacktraceFilterPattern("libaudioutils", "strlen"))));
+ }
}