boringssl/crypto/abi_self_test.cc
David Benjamin 17d553d299 Add a CFI tester to CHECK_ABI.
This uses the x86 trap flag and libunwind to test CFI works at each
instruction. For now, it just uses the system one out of pkg-config and
disables unwind tests if unavailable. We'll probably want to stick a
copy into //third_party and perhaps try the LLVM one later.

This tester caught two bugs in P-256 CFI annotations already:
I47b5f9798b3bcee1748e537b21c173d312a14b42 and
I9f576d868850312d6c14d1386f8fbfa85021b347

An earlier design used PTRACE_SINGLESTEP with libunwind's remote
unwinding features. ptrace is a mess around stop signals (see group-stop
discussion in ptrace(2)) and this is 10x faster, so I went with it. The
question of which is more future-proof is complex:

- There are two libunwinds with the same API,
  https://www.nongnu.org/libunwind/ and LLVM's. This currently uses the
  system nongnu.org for convenience. In future, LLVM's should be easier
  to bundle (less complex build) and appears to even support Windows,
  but I haven't tested this.  Moreover, setting the trap flag keeps the
  test single-process, which is less complex on Windows. That suggests
  the trap flag design and switching to LLVM later. However...

- Not all architectures have a trap flag settable by userspace. As far
  as I can tell, ARMv8's PSTATE.SS can only be set from the kernel. If
  we stick with nongnu.org libunwind, we can use PTRACE_SINGLESTEP and
  remote unwinding. Or we implement it for LLVM. Another thought is for
  the ptracer to bounce SIGTRAP back into the process, to share the
  local unwinding code.

- ARMv7 has no trap flag at all and PTRACE_SINGLESTEP fails. Debuggers
  single-step by injecting breakpoints instead. However, ARMv8's trap
  flag seems to work in both AArch32 and AArch64 modes, so we may be
  able to condition it on a 64-bit kernel.

Sadly, neither strategy works with Intel SDE. Adding flags to cpucap
vectors as we do with ARM would help, but it would not emulate CPUs
newer than the host CPU. For now, I've just had SDE tests disable these.

Annoyingly, CMake does not allow object libraries to have dependencies,
so make test_support a proper static library. Rename the target to
test_support_lib to avoid
https://gitlab.kitware.com/cmake/cmake/issues/17785

Update-Note: This adds a new optional test dependency, but it's disabled
by default (define BORINGSSL_HAVE_LIBUNWIND), so consumers do not need
to do anything. We'll probably want to adjust this in the future.

Bug: 181
Change-Id: I817263d7907aff0904a9cee83f8b26747262cc0c
Reviewed-on: https://boringssl-review.googlesource.com/c/33966
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
2019-01-03 22:01:55 +00:00

206 lines
8.1 KiB
C++

/* Copyright (c) 2018, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <gtest/gtest.h>
#include <gtest/gtest-spi.h>
#include <openssl/rand.h>
#include "test/abi_test.h"
#if defined(OPENSSL_WINDOWS)
#include <windows.h>
#endif
static bool test_function_ok;
static int TestFunction(int a1, int a2, int a3, int a4, int a5, int a6, int a7,
int a8, int a9, int a10) {
test_function_ok = a1 == 1 || a2 == 2 || a3 == 3 || a4 == 4 || a5 == 5 ||
a6 == 6 || a7 == 7 || a8 == 8 || a9 == 9 || a10 == 10;
return 42;
}
TEST(ABITest, SanityCheck) {
EXPECT_NE(0, CHECK_ABI(strcmp, "hello", "world"));
test_function_ok = false;
EXPECT_EQ(42, CHECK_ABI(TestFunction, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
EXPECT_TRUE(test_function_ok);
#if defined(SUPPORTS_ABI_TEST)
abi_test::internal::CallerState state;
RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
const char *arg1 = "hello", *arg2 = "world";
crypto_word_t argv[2] = {
reinterpret_cast<crypto_word_t>(arg1),
reinterpret_cast<crypto_word_t>(arg2),
};
CHECK_ABI(abi_test_trampoline, reinterpret_cast<crypto_word_t>(strcmp),
&state, argv, 2, 0 /* no breakpoint */);
if (abi_test::UnwindTestsEnabled()) {
EXPECT_NONFATAL_FAILURE(CHECK_ABI(abi_test_bad_unwind_wrong_register),
"was not recovered unwinding");
EXPECT_NONFATAL_FAILURE(CHECK_ABI(abi_test_bad_unwind_temporary),
"was not recovered unwinding");
CHECK_ABI_NO_UNWIND(abi_test_bad_unwind_wrong_register);
CHECK_ABI_NO_UNWIND(abi_test_bad_unwind_temporary);
}
#endif // SUPPORTS_ABI_TEST
}
#if defined(OPENSSL_X86_64) && defined(SUPPORTS_ABI_TEST)
extern "C" {
void abi_test_clobber_rax(void);
void abi_test_clobber_rbx(void);
void abi_test_clobber_rcx(void);
void abi_test_clobber_rdx(void);
void abi_test_clobber_rsi(void);
void abi_test_clobber_rdi(void);
void abi_test_clobber_rbp(void);
void abi_test_clobber_r8(void);
void abi_test_clobber_r9(void);
void abi_test_clobber_r10(void);
void abi_test_clobber_r11(void);
void abi_test_clobber_r12(void);
void abi_test_clobber_r13(void);
void abi_test_clobber_r14(void);
void abi_test_clobber_r15(void);
void abi_test_clobber_xmm0(void);
void abi_test_clobber_xmm1(void);
void abi_test_clobber_xmm2(void);
void abi_test_clobber_xmm3(void);
void abi_test_clobber_xmm4(void);
void abi_test_clobber_xmm5(void);
void abi_test_clobber_xmm6(void);
void abi_test_clobber_xmm7(void);
void abi_test_clobber_xmm8(void);
void abi_test_clobber_xmm9(void);
void abi_test_clobber_xmm10(void);
void abi_test_clobber_xmm11(void);
void abi_test_clobber_xmm12(void);
void abi_test_clobber_xmm13(void);
void abi_test_clobber_xmm14(void);
void abi_test_clobber_xmm15(void);
} // extern "C"
TEST(ABITest, X86_64) {
// abi_test_trampoline hides unsaved registers from the caller, so we can
// safely call the abi_test_clobber_* functions below.
abi_test::internal::CallerState state;
RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
CHECK_ABI_NO_UNWIND(abi_test_trampoline,
reinterpret_cast<crypto_word_t>(abi_test_clobber_rbx),
&state, nullptr, 0, 0 /* no breakpoint */);
CHECK_ABI_NO_UNWIND(abi_test_clobber_rax);
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rbx),
"rbx was not restored after return");
CHECK_ABI_NO_UNWIND(abi_test_clobber_rcx);
CHECK_ABI_NO_UNWIND(abi_test_clobber_rdx);
#if defined(OPENSSL_WINDOWS)
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rdi),
"rdi was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rsi),
"rsi was not restored after return");
#else
CHECK_ABI_NO_UNWIND(abi_test_clobber_rdi);
CHECK_ABI_NO_UNWIND(abi_test_clobber_rsi);
#endif
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rbp),
"rbp was not restored after return");
CHECK_ABI_NO_UNWIND(abi_test_clobber_r8);
CHECK_ABI_NO_UNWIND(abi_test_clobber_r9);
CHECK_ABI_NO_UNWIND(abi_test_clobber_r10);
CHECK_ABI_NO_UNWIND(abi_test_clobber_r11);
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r12),
"r12 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r13),
"r13 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r14),
"r14 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r15),
"r15 was not restored after return");
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm0);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm1);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm2);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm3);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm4);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm5);
#if defined(OPENSSL_WINDOWS)
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm6),
"xmm6 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm7),
"xmm7 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm8),
"xmm8 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm9),
"xmm9 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm10),
"xmm10 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm11),
"xmm11 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm12),
"xmm12 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm13),
"xmm13 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm14),
"xmm14 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm15),
"xmm15 was not restored after return");
#else
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm6);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm7);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm8);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm9);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm10);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm11);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm12);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm13);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm14);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm15);
#endif
}
#if defined(OPENSSL_WINDOWS)
static void ThrowWindowsException() {
DebugBreak();
}
static void ExceptionTest() {
bool handled = false;
__try {
CHECK_ABI_NO_UNWIND(ThrowWindowsException);
} __except (GetExceptionCode() == EXCEPTION_BREAKPOINT
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
handled = true;
}
EXPECT_TRUE(handled);
}
// Test that the trampoline's SEH metadata works.
TEST(ABITest, TrampolineSEH) {
// Wrap the test in |CHECK_ABI|, to confirm the register-restoring annotations
// were correct.
CHECK_ABI_NO_UNWIND(ExceptionTest);
}
#endif // OPENSSL_WINDOWS
#endif // OPENSSL_X86_64 && SUPPORTS_ABI_TEST