Commit 3a143f52 authored by Richard Townsend's avatar Richard Townsend Committed by Commit Bot

fix: get CFI tests passing for Windows on Arm

Corrects a problem with the inline assembly formatting on Windows
(Clang's assembler behaves differently with line-breaks vs semi-colons
on Windows than it does on other systems - was incorrectly squashing
nops). It also ensures that the right number of instructions are
skipped to avoid an instruction alignment crash when the linker's
configured incorrectly.

Bug: 1108769
Change-Id: I1f1f1ac7866c72d62068ad1db87f12c08204303c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2320570Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Commit-Queue: Richard Townsend <richard.townsend@arm.com>
Cr-Commit-Position: refs/heads/master@{#792378}
parent daaaa93b
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/check.h" #include "base/check.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "build/build_config.h"
namespace base { namespace base {
namespace debug { namespace debug {
...@@ -17,9 +18,21 @@ namespace win { ...@@ -17,9 +18,21 @@ namespace win {
namespace { namespace {
#if defined(ARCH_CPU_X86_FAMILY)
// On x86/x64 systems, nop instructions are generally 1 byte.
static constexpr int kNopInstructionSize = 1;
#elif defined(ARCH_CPU_ARM64)
// On Arm systems, all instructions are 4 bytes, fixed size.
static constexpr int kNopInstructionSize = 4;
#else
#error "Unsupported architecture"
#endif
// Function that can be jumped midway into safely. // Function that can be jumped midway into safely.
__attribute__((naked)) int nop_sled() { __attribute__((naked)) int nop_sled() {
asm("nop; nop; ret"); asm("nop\n"
"nop\n"
"ret\n");
} }
using FuncType = decltype(&nop_sled); using FuncType = decltype(&nop_sled);
...@@ -66,8 +79,8 @@ void TerminateWithHeapCorruption() { ...@@ -66,8 +79,8 @@ void TerminateWithHeapCorruption() {
void TerminateWithControlFlowViolation() { void TerminateWithControlFlowViolation() {
// Call into the middle of the NOP sled. // Call into the middle of the NOP sled.
FuncType func = FuncType func = reinterpret_cast<FuncType>(
reinterpret_cast<FuncType>((reinterpret_cast<uintptr_t>(nop_sled)) + 0x1); (reinterpret_cast<uintptr_t>(nop_sled)) + kNopInstructionSize);
__try { __try {
// Generates a STATUS_STACK_BUFFER_OVERRUN exception if CFG triggers. // Generates a STATUS_STACK_BUFFER_OVERRUN exception if CFG triggers.
IndirectCall(&func); IndirectCall(&func);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace sandbox { namespace sandbox {
...@@ -21,6 +22,16 @@ namespace sandbox { ...@@ -21,6 +22,16 @@ namespace sandbox {
namespace { namespace {
#if defined(ARCH_CPU_X86_FAMILY)
// On x86/x64 systems, nop instructions are generally 1 byte.
static constexpr int kNopInstructionSize = 1;
#elif defined(ARCH_CPU_ARM64)
// On Arm systems, all instructions are 4 bytes, fixed size.
static constexpr int kNopInstructionSize = 4;
#else
#error "Unsupported architecture"
#endif
DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER total_file_size, DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER total_file_size,
LARGE_INTEGER total_bytes_transferred, LARGE_INTEGER total_bytes_transferred,
LARGE_INTEGER stream_size, LARGE_INTEGER stream_size,
...@@ -30,11 +41,9 @@ DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER total_file_size, ...@@ -30,11 +41,9 @@ DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER total_file_size,
HANDLE source_file, HANDLE source_file,
HANDLE destination_file, HANDLE destination_file,
LPVOID context) { LPVOID context) {
__asm { asm("nop\n"
nop "nop\n"
nop "ret\n");
ret
}
return PROGRESS_CONTINUE; return PROGRESS_CONTINUE;
} }
...@@ -57,7 +66,7 @@ TEST(CFGSupportTests, MsIndirectFailure) { ...@@ -57,7 +66,7 @@ TEST(CFGSupportTests, MsIndirectFailure) {
// Create a bad callback pointer to midway into the callback function. This // Create a bad callback pointer to midway into the callback function. This
// should cause a CFG violation in MS code. // should cause a CFG violation in MS code.
auto bad_callback_func = reinterpret_cast<ProcessCallbackRoutineType>( auto bad_callback_func = reinterpret_cast<ProcessCallbackRoutineType>(
(reinterpret_cast<uintptr_t>(CopyProgressRoutine)) + 0x1); (reinterpret_cast<uintptr_t>(CopyProgressRoutine)) + kNopInstructionSize);
base::ScopedTempDir temp_dir; base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment