Merge "Add permissive MTE mode."
This commit is contained in:
commit
514c41c6e2
|
@ -38,6 +38,8 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <android-base/macros.h>
|
#include <android-base/macros.h>
|
||||||
|
#include <android-base/parsebool.h>
|
||||||
|
#include <android-base/properties.h>
|
||||||
#include <android-base/unique_fd.h>
|
#include <android-base/unique_fd.h>
|
||||||
#include <async_safe/log.h>
|
#include <async_safe/log.h>
|
||||||
#include <bionic/reserved_signals.h>
|
#include <bionic/reserved_signals.h>
|
||||||
|
@ -49,7 +51,10 @@
|
||||||
|
|
||||||
#include "handler/fallback.h"
|
#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.
|
// 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.
|
// 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);
|
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) {
|
static inline void futex_wait(volatile void* ftx, int value) {
|
||||||
syscall(__NR_futex, ftx, FUTEX_WAIT, value, nullptr, nullptr, 0);
|
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
|
// If the signal is fatal, don't unlock the mutex to prevent other crashing threads from
|
||||||
// starting to dump right before our death.
|
// starting to dump right before our death.
|
||||||
pthread_mutex_unlock(&crash_mutex);
|
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 the signal, so that either the debugger or the parent's waitpid sees it.
|
||||||
resend_signal(info);
|
resend_signal(info);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"],
|
||||||
|
}
|
|
@ -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>
|
|
@ -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 New Issue