Merge "Add permissive MTE mode." am: 514c41c6e2
Original change: https://android-review.googlesource.com/c/platform/system/core/+/2101441 Change-Id: I65fb04fe5ad6eba01e8a7533baf18c45ff606da7 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
226258d02f
5 changed files with 222 additions and 2 deletions
|
@ -38,6 +38,8 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <android-base/macros.h>
|
||||
#include <android-base/parsebool.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <async_safe/log.h>
|
||||
#include <bionic/reserved_signals.h>
|
||||
|
@ -49,7 +51,10 @@
|
|||
|
||||
#include "handler/fallback.h"
|
||||
|
||||
using android::base::Pipe;
|
||||
using ::android::base::GetBoolProperty;
|
||||
using ::android::base::ParseBool;
|
||||
using ::android::base::ParseBoolResult;
|
||||
using ::android::base::Pipe;
|
||||
|
||||
// We muck with our fds in a 'thread' that doesn't share the same fd table.
|
||||
// Close fds in that thread with a raw close syscall instead of going through libc.
|
||||
|
@ -82,6 +87,13 @@ static pid_t __gettid() {
|
|||
return syscall(__NR_gettid);
|
||||
}
|
||||
|
||||
static bool is_permissive_mte() {
|
||||
// Environment variable for testing or local use from shell.
|
||||
char* permissive_env = getenv("MTE_PERMISSIVE");
|
||||
return GetBoolProperty("persist.sys.mte.permissive", false) ||
|
||||
(permissive_env && ParseBool(permissive_env) == ParseBoolResult::kTrue);
|
||||
}
|
||||
|
||||
static inline void futex_wait(volatile void* ftx, int value) {
|
||||
syscall(__NR_futex, ftx, FUTEX_WAIT, value, nullptr, nullptr, 0);
|
||||
}
|
||||
|
@ -592,7 +604,28 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c
|
|||
// If the signal is fatal, don't unlock the mutex to prevent other crashing threads from
|
||||
// starting to dump right before our death.
|
||||
pthread_mutex_unlock(&crash_mutex);
|
||||
} else {
|
||||
}
|
||||
#ifdef __aarch64__
|
||||
else if (info->si_signo == SIGSEGV &&
|
||||
(info->si_code == SEGV_MTESERR || info->si_code == SEGV_MTEAERR) &&
|
||||
is_permissive_mte()) {
|
||||
// If we are in permissive MTE mode, we do not crash, but instead disable MTE on this thread,
|
||||
// and then let the failing instruction be retried. The second time should work (except
|
||||
// if there is another non-MTE fault).
|
||||
int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
|
||||
if (tagged_addr_ctrl < 0) {
|
||||
fatal_errno("failed to PR_GET_TAGGED_ADDR_CTRL");
|
||||
}
|
||||
tagged_addr_ctrl = (tagged_addr_ctrl & ~PR_MTE_TCF_MASK) | PR_MTE_TCF_NONE;
|
||||
if (prctl(PR_SET_TAGGED_ADDR_CTRL, tagged_addr_ctrl, 0, 0, 0) < 0) {
|
||||
fatal_errno("failed to PR_SET_TAGGED_ADDR_CTRL");
|
||||
}
|
||||
async_safe_format_log(ANDROID_LOG_ERROR, "libc",
|
||||
"MTE ERROR DETECTED BUT RUNNING IN PERMISSIVE MODE. CONTINUING.");
|
||||
pthread_mutex_unlock(&crash_mutex);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
// Resend the signal, so that either the debugger or the parent's waitpid sees it.
|
||||
resend_signal(info);
|
||||
}
|
||||
|
|
34
debuggerd/test_permissive_mte/Android.bp
Normal file
34
debuggerd/test_permissive_mte/Android.bp
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Copyright (C) 2022 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.
|
||||
|
||||
cc_binary {
|
||||
name: "mte_crash",
|
||||
srcs: ["mte_crash.cpp"],
|
||||
sanitize: {
|
||||
memtag_heap: true,
|
||||
diag: {
|
||||
memtag_heap: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
java_test_host {
|
||||
name: "permissive_mte_test",
|
||||
libs: ["tradefed"],
|
||||
static_libs: ["frameworks-base-hostutils", "cts-install-lib-host"],
|
||||
srcs: ["src/**/PermissiveMteTest.java", ":libtombstone_proto-src"],
|
||||
data: [":mte_crash"],
|
||||
test_config: "AndroidTest.xml",
|
||||
test_suites: ["general-tests"],
|
||||
}
|
29
debuggerd/test_permissive_mte/AndroidTest.xml
Normal file
29
debuggerd/test_permissive_mte/AndroidTest.xml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2022 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.
|
||||
-->
|
||||
<configuration description="Runs the permissive MTE tests">
|
||||
<option name="test-suite-tag" value="init_test_upgrade_mte" />
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
|
||||
<!-- For tombstone inspection. -->
|
||||
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
|
||||
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
|
||||
<option name="cleanup" value="true" />
|
||||
<option name="push" value="mte_crash->/data/local/tmp/mte_crash" />
|
||||
</target_preparer>
|
||||
<test class="com.android.tradefed.testtype.HostTest" >
|
||||
<option name="jar" value="permissive_mte_test.jar" />
|
||||
</test>
|
||||
</configuration>
|
24
debuggerd/test_permissive_mte/mte_crash.cpp
Normal file
24
debuggerd/test_permissive_mte/mte_crash.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int, char**) {
|
||||
volatile char* f = (char*)malloc(1);
|
||||
printf("%c\n", f[17]);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.tests.init;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import com.android.server.os.TombstoneProtos.Tombstone;
|
||||
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
|
||||
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
|
||||
import com.android.tradefed.util.CommandResult;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(DeviceJUnit4ClassRunner.class)
|
||||
public class PermissiveMteTest extends BaseHostJUnit4Test {
|
||||
String mUUID;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mUUID = java.util.UUID.randomUUID().toString();
|
||||
CommandResult result =
|
||||
getDevice().executeShellV2Command("/data/local/tmp/mte_crash setUp " + mUUID);
|
||||
assumeTrue("mte_crash needs to segfault", result.getExitCode() == 139);
|
||||
}
|
||||
|
||||
Tombstone parseTombstone(String tombstonePath) throws Exception {
|
||||
File tombstoneFile = getDevice().pullFile(tombstonePath);
|
||||
InputStream istr = new FileInputStream(tombstoneFile);
|
||||
Tombstone tombstoneProto;
|
||||
try {
|
||||
tombstoneProto = Tombstone.parseFrom(istr);
|
||||
} finally {
|
||||
istr.close();
|
||||
}
|
||||
return tombstoneProto;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
String[] tombstones = getDevice().getChildren("/data/tombstones");
|
||||
for (String tombstone : tombstones) {
|
||||
if (!tombstone.endsWith(".pb")) {
|
||||
continue;
|
||||
}
|
||||
String tombstonePath = "/data/tombstones/" + tombstone;
|
||||
Tombstone tombstoneProto = parseTombstone(tombstonePath);
|
||||
if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains(mUUID))) {
|
||||
continue;
|
||||
}
|
||||
getDevice().deleteFile(tombstonePath);
|
||||
// remove the non .pb file as well.
|
||||
getDevice().deleteFile(tombstonePath.substring(0, tombstonePath.length() - 3));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrash() throws Exception {
|
||||
CommandResult result = getDevice().executeShellV2Command(
|
||||
"MTE_PERMISSIVE=1 /data/local/tmp/mte_crash testCrash " + mUUID);
|
||||
assertThat(result.getExitCode()).isEqualTo(0);
|
||||
int numberTombstones = 0;
|
||||
String[] tombstones = getDevice().getChildren("/data/tombstones");
|
||||
for (String tombstone : tombstones) {
|
||||
if (!tombstone.endsWith(".pb")) {
|
||||
continue;
|
||||
}
|
||||
String tombstonePath = "/data/tombstones/" + tombstone;
|
||||
Tombstone tombstoneProto = parseTombstone(tombstonePath);
|
||||
if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains(mUUID))) {
|
||||
continue;
|
||||
}
|
||||
if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains("testCrash"))) {
|
||||
continue;
|
||||
}
|
||||
numberTombstones++;
|
||||
}
|
||||
assertThat(numberTombstones).isEqualTo(1);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue