summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2022-02-10 21:00:56 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2022-02-10 21:00:56 +0000
commitdae8e486bf616b63059f0d8f5a94bb9733a403cc (patch)
tree518b653134631011e3c9fb4472c724d600d5d53c
parentf2d6b0a31d994c966d16b355ebda81650c8c0dbf (diff)
parent7176306861698babc4a6e40d73300e532404e4de (diff)
downloadbase-android-t-preview-1.tar.gz
Merge "BootReceiver: drop code processing dmesg, employ dmesgd"android-t-preview-2android-t-preview-1android-t-beta-3android-t-preview-1
-rw-r--r--services/core/java/com/android/server/BootReceiver.java171
-rw-r--r--services/tests/servicestests/src/com/android/server/BootReceiverTest.java72
2 files changed, 9 insertions, 234 deletions
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index a0575cf6bab9..26d76a848a02 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -51,15 +51,12 @@ import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.Matcher;
@@ -128,11 +125,9 @@ public class BootReceiver extends BroadcastReceiver {
// Location of ftrace pipe for notifications from kernel memory tools like KFENCE and KASAN.
private static final String ERROR_REPORT_TRACE_PIPE =
"/sys/kernel/tracing/instances/bootreceiver/trace_pipe";
- // Stop after sending this many reports. See http://b/182159975.
+ // Stop after sending too many reports. See http://b/182159975.
private static final int MAX_ERROR_REPORTS = 8;
private static int sSentReports = 0;
- // Avoid reporing the same bug from processDmesg() twice.
- private static String sLastReportedBug = null;
@Override
public void onReceive(final Context context, Intent intent) {
@@ -175,7 +170,8 @@ public class BootReceiver extends BroadcastReceiver {
* We read from /sys/kernel/tracing/instances/bootreceiver/trace_pipe (set up by the
* system), which will print an ftrace event when a memory corruption is detected in the
* kernel.
- * When an error is detected, we run the dmesg shell command and process its output.
+ * When an error is detected, we set the dmesg.start system property to notify dmesgd
+ * about a new error.
*/
OnFileDescriptorEventListener traceCallback = new OnFileDescriptorEventListener() {
final int mBufferSize = 1024;
@@ -191,8 +187,7 @@ public class BootReceiver extends BroadcastReceiver {
* line, but to be on the safe side we keep reading until the buffer
* contains a '\n' character. In the unlikely case of a very buggy kernel
* the buffer may contain multiple tracing events that cannot be attributed
- * to particular error reports. In that case the latest error report
- * residing in dmesg is picked.
+ * to particular error reports. dmesgd will take care of all errors.
*/
try {
int nbytes = Os.read(fd, mTraceBuffer, 0, mBufferSize);
@@ -201,10 +196,13 @@ public class BootReceiver extends BroadcastReceiver {
if (readStr.indexOf("\n") == -1) {
return OnFileDescriptorEventListener.EVENT_INPUT;
}
- processDmesg(context);
+ if (sSentReports < MAX_ERROR_REPORTS) {
+ SystemProperties.set("dmesgd.start", "1");
+ sSentReports++;
+ }
}
} catch (Exception e) {
- Slog.wtf(TAG, "Error processing dmesg output", e);
+ Slog.wtf(TAG, "Error watching for trace events", e);
return 0; // Unregister the handler.
}
return OnFileDescriptorEventListener.EVENT_INPUT;
@@ -216,157 +214,6 @@ public class BootReceiver extends BroadcastReceiver {
}
- /**
- * Check whether it is safe to collect this dmesg line or not.
- *
- * We only consider lines belonging to KASAN or KFENCE reports, but those may still contain
- * user information, namely the process name:
- *
- * [ 69.547684] [ T6006]c7 6006 CPU: 7 PID: 6006 Comm: sh Tainted: G S C O ...
- *
- * hardware information:
- *
- * [ 69.558923] [ T6006]c7 6006 Hardware name: <REDACTED>
- *
- * or register dump (in KASAN reports only):
- *
- * ... RIP: 0033:0x7f96443109da
- * ... RSP: 002b:00007ffcf0b51b08 EFLAGS: 00000202 ORIG_RAX: 00000000000000af
- * ... RAX: ffffffffffffffda RBX: 000055dc3ee521a0 RCX: 00007f96443109da
- *
- * (on x86_64)
- *
- * ... pc : lpm_cpuidle_enter+0x258/0x384
- * ... lr : lpm_cpuidle_enter+0x1d4/0x384
- * ... sp : ffffff800820bea0
- * ... x29: ffffff800820bea0 x28: ffffffc2305f3ce0
- * ... ...
- * ... x9 : 0000000000000001 x8 : 0000000000000000
- * (on ARM64)
- *
- * We therefore omit the lines that contain "Comm:", "Hardware name:", or match the general
- * purpose register regexp.
- *
- * @param line single line of `dmesg` output.
- * @return updated line with sensitive data removed, or null if the line must be skipped.
- */
- public static String stripSensitiveData(String line) {
- /*
- * General purpose register names begin with "R" on x86_64 and "x" on ARM64. The letter is
- * followed by two symbols (numbers, letters or spaces) and a colon, which is followed by a
- * 16-digit hex number. The optional "_" prefix accounts for ORIG_RAX on x86.
- */
- final String registerRegex = "[ _][Rx]..: [0-9a-f]{16}";
- final Pattern registerPattern = Pattern.compile(registerRegex);
-
- final String corruptionRegex = "Detected corrupted memory at 0x[0-9a-f]+";
- final Pattern corruptionPattern = Pattern.compile(corruptionRegex);
-
- if (line.contains("Comm: ") || line.contains("Hardware name: ")) return null;
- if (registerPattern.matcher(line).find()) return null;
-
- Matcher cm = corruptionPattern.matcher(line);
- if (cm.find()) return cm.group(0);
- return line;
- }
-
- /*
- * Search dmesg output for the last error report from KFENCE or KASAN and copy it to Dropbox.
- *
- * Example report printed by the kernel (redacted to fit into 100 column limit):
- * [ 69.236673] [ T6006]c7 6006 =========================================================
- * [ 69.245688] [ T6006]c7 6006 BUG: KFENCE: out-of-bounds in kfence_handle_page_fault
- * [ 69.245688] [ T6006]c7 6006
- * [ 69.257816] [ T6006]c7 6006 Out-of-bounds access at 0xffffffca75c45000 (...)
- * [ 69.267102] [ T6006]c7 6006 kfence_handle_page_fault+0x1bc/0x208
- * [ 69.273536] [ T6006]c7 6006 __do_kernel_fault+0xa8/0x11c
- * ...
- * [ 69.355427] [ T6006]c7 6006 kfence-#2 [0xffffffca75c46f30-0xffffffca75c46fff, ...
- * [ 69.366938] [ T6006]c7 6006 __d_alloc+0x3c/0x1b4
- * [ 69.371946] [ T6006]c7 6006 d_alloc_parallel+0x48/0x538
- * [ 69.377578] [ T6006]c7 6006 __lookup_slow+0x60/0x15c
- * ...
- * [ 69.547684] [ T6006]c7 6006 CPU: 7 PID: 6006 Comm: sh Tainted: G S C O ...
- * [ 69.558923] [ T6006]c7 6006 Hardware name: <REDACTED>
- * [ 69.567059] [ T6006]c7 6006 =========================================================
- *
- * We rely on the kernel printing task/CPU ID for every log line (CONFIG_PRINTK_CALLER=y).
- * E.g. for the above report the task ID is T6006. Report lines may interleave with lines
- * printed by other kernel tasks, which will have different task IDs, so in order to collect
- * the report we:
- * - find the next occurrence of the "BUG: " line in the kernel log, parse it to obtain the
- * task ID and the tool name;
- * - scan the rest of dmesg output and pick every line that has the same task ID, until we
- * encounter a horizontal ruler, i.e.:
- * [ 69.567059] [ T6006]c7 6006 ======================================================
- * - add that line to the error report, unless it contains sensitive information (see
- * logLinePotentiallySensitive())
- * - repeat the above steps till the last report is found.
- */
- private void processDmesg(Context ctx) throws IOException {
- if (sSentReports == MAX_ERROR_REPORTS) return;
- /*
- * Only SYSTEM_KASAN_ERROR_REPORT and SYSTEM_KFENCE_ERROR_REPORT are supported at the
- * moment.
- */
- final String[] bugTypes = new String[] { "KASAN", "KFENCE" };
- final String tsRegex = "^\\[[^]]+\\] ";
- final String bugRegex =
- tsRegex + "\\[([^]]+)\\].*BUG: (" + String.join("|", bugTypes) + "):";
- final Pattern bugPattern = Pattern.compile(bugRegex);
-
- Process p = new ProcessBuilder("/system/bin/timeout", "-k", "90s", "60s",
- "dmesg").redirectErrorStream(true).start();
- BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
- String line = null;
- String task = null;
- String tool = null;
- String bugTitle = null;
- Pattern reportPattern = null;
- ArrayList<String> currentReport = null;
- String lastReport = null;
-
- while ((line = reader.readLine()) != null) {
- if (currentReport == null) {
- Matcher bm = bugPattern.matcher(line);
- if (!bm.find()) continue;
- task = bm.group(1);
- tool = bm.group(2);
- bugTitle = line;
- currentReport = new ArrayList<String>();
- currentReport.add(line);
- String reportRegex = tsRegex + "\\[" + task + "\\].*";
- reportPattern = Pattern.compile(reportRegex);
- continue;
- }
- Matcher rm = reportPattern.matcher(line);
- if (!rm.matches()) continue;
- if ((line = stripSensitiveData(line)) == null) continue;
- if (line.contains("================================")) {
- lastReport = String.join("\n", currentReport);
- currentReport = null;
- continue;
- }
- currentReport.add(line);
- }
- if (lastReport == null) {
- Slog.w(TAG, "Could not find report in dmesg.");
- return;
- }
-
- // Avoid sending the same bug report twice.
- if (bugTitle.equals(sLastReportedBug)) return;
-
- final String reportTag = "SYSTEM_" + tool + "_ERROR_REPORT";
- final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
- final String headers = getCurrentBootHeaders();
- final String reportText = headers + lastReport;
-
- addTextToDropBox(db, reportTag, reportText, "/dev/kmsg", LOG_SIZE);
- sLastReportedBug = bugTitle;
- sSentReports++;
- }
-
private void removeOldUpdatePackages(Context context) {
Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS);
}
diff --git a/services/tests/servicestests/src/com/android/server/BootReceiverTest.java b/services/tests/servicestests/src/com/android/server/BootReceiverTest.java
deleted file mode 100644
index 489e2f769a3d..000000000000
--- a/services/tests/servicestests/src/com/android/server/BootReceiverTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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;
-
-import android.test.AndroidTestCase;
-
-/**
- * Tests for {@link com.android.server.BootReceiver}
- */
-public class BootReceiverTest extends AndroidTestCase {
- public void testLogLinePotentiallySensitive() throws Exception {
- /*
- * Strings to be dropped from the log as potentially sensitive: register dumps, process
- * names, hardware info.
- */
- final String[] becomeNull = {
- "CPU: 4 PID: 120 Comm: kunit_try_catch Tainted: G W 5.8.0-rc6+ #7",
- "Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014",
- "[ 0.083207] RSP: 0000:ffffffff8fe07ca8 EFLAGS: 00010046 ORIG_RAX: 0000000000000000",
- "[ 0.084709] RAX: 0000000000000000 RBX: ffffffffff240000 RCX: ffffffff815fcf01",
- "[ 0.086109] RDX: dffffc0000000000 RSI: 0000000000000001 RDI: ffffffffff240004",
- "[ 0.087509] RBP: ffffffff8fe07d60 R08: fffffbfff1fc0f21 R09: fffffbfff1fc0f21",
- "[ 0.088911] R10: ffffffff8fe07907 R11: fffffbfff1fc0f20 R12: ffffffff8fe07d38",
- "R13: 0000000000000001 R14: 0000000000000001 R15: ffffffff8fe07e80",
- "x29: ffff00003ce07150 x28: ffff80001aa29cc0",
- "x1 : 0000000000000000 x0 : ffff00000f628000",
- };
-
- /* Strings to be left unchanged, including non-sensitive registers and parts of reports. */
- final String[] leftAsIs = {
- "FS: 0000000000000000(0000) GS:ffffffff92409000(0000) knlGS:0000000000000000",
- "[ 69.2366] [ T6006]c7 6006 =======================================================",
- "[ 69.245688] [ T6006] BUG: KFENCE: out-of-bounds in kfence_handle_page_fault",
- "[ 69.257816] [ T6006]c7 6006 Out-of-bounds access at 0xffffffca75c45000 ",
- "[ 69.273536] [ T6006]c7 6006 __do_kernel_fault+0xa8/0x11c",
- "pc : __mutex_lock+0x428/0x99c ",
- "sp : ffff00003ce07150",
- "Call trace:",
- "",
- };
-
- final String[][] stripped = {
- { "Detected corrupted memory at 0xffffffffb6797ff9 [ 0xac . . . . . . ]:",
- "Detected corrupted memory at 0xffffffffb6797ff9" },
- };
- for (int i = 0; i < becomeNull.length; i++) {
- assertEquals(BootReceiver.stripSensitiveData(becomeNull[i]), null);
- }
-
- for (int i = 0; i < leftAsIs.length; i++) {
- assertEquals(BootReceiver.stripSensitiveData(leftAsIs[i]), leftAsIs[i]);
- }
-
- for (int i = 0; i < stripped.length; i++) {
- assertEquals(BootReceiver.stripSensitiveData(stripped[i][0]), stripped[i][1]);
- }
- }
-}