27 #if defined(OPENSSL_X86_64) && defined(SUPPORTS_ABI_TEST)
28 #if defined(OPENSSL_LINUX) && defined(BORINGSSL_HAVE_LIBUNWIND)
29 #define SUPPORTS_UNWIND_TEST
30 #define UNW_LOCAL_ONLY
33 #include <libunwind.h>
39 #include <sys/types.h>
41 #elif defined(OPENSSL_WINDOWS)
42 #define SUPPORTS_UNWIND_TEST
48 #endif // X86_64 && SUPPORTS_ABI_TEST
51 #if defined(BORINGSSL_FIPS)
52 #undef SUPPORTS_UNWIND_TEST
64 size_t idx =
ret.find(
',');
65 if (
idx == std::string::npos) {
68 size_t idx2 =
idx + 1;
69 while (idx2 <
ret.size() &&
ret[idx2] ==
' ') {
75 return ret.substr(0,
idx) +
"(" +
ret.substr(idx2) +
")";
78 #if defined(SUPPORTS_ABI_TEST)
80 template <
typename Func>
81 static void ForEachMismatch(
const CallerState &a,
const CallerState &
b,
83 #define CALLER_STATE_REGISTER(type, name) \
84 if (a.name != b.name) { \
87 LOOP_CALLER_STATE_REGISTERS()
88 #undef CALLER_STATE_REGISTER
92 static void ReadUnwindResult(
Result *
out);
95 const crypto_word_t *argv,
size_t argc,
101 CallerState state2 =
state;
103 #if defined(OPENSSL_X86_64) || defined(OPENSSL_X86)
107 #endif // OPENSSL_X86_64 || OPENSSL_X86
110 ForEachMismatch(
state, state2, [&](
const char *reg) {
111 out->errors.push_back(
std::string(reg) +
" was not restored after return");
113 #if defined(OPENSSL_X86_64) || defined(OPENSSL_X86)
118 if (direction_flag) {
119 out->errors.emplace_back(
"Direction flag set after return");
121 #endif // OPENSSL_X86_64 || OPENSSL_X86
123 ReadUnwindResult(
out);
127 #endif // SUPPORTS_ABI_TEST
129 #if defined(SUPPORTS_UNWIND_TEST)
137 static bool IsAncestorStackFrame(crypto_word_t a_sp, crypto_word_t b_sp) {
138 #if defined(OPENSSL_X86_64)
142 #error "unknown architecture"
150 #if !defined(OPENSSL_WINDOWS)
159 for (
size_t i = 0;
i <
len / 2;
i++) {
165 #endif // !OPENSSL_WINDOWS
167 static std::array<char,
sizeof(crypto_word_t) * 2 + 1> WordToHex(
169 static const char kHex[] =
"0123456789abcdef";
171 for (
size_t i =
sizeof(crypto_word_t) - 1;
i <
sizeof(crypto_word_t);
i--) {
174 ret[
i * 2] = kHex[
b >> 4];
175 ret[
i * 2 + 1] = kHex[
b & 0xf];
177 ret[
sizeof(crypto_word_t) * 2] =
'\0';
181 static void StrCatSignalSafeImpl(bssl::Span<char>
out) {}
183 template <
typename...
Args>
184 static void StrCatSignalSafeImpl(bssl::Span<char>
out,
const char *
str,
187 StrCatSignalSafeImpl(
out,
args...);
190 template <
typename...
Args>
191 static void StrCatSignalSafe(bssl::Span<char>
out,
Args...
args) {
196 StrCatSignalSafeImpl(
out,
args...);
199 template <
typename...
Args>
200 [[noreturn]]
static void FatalError(
Args...
args) {
203 StrCatSignalSafe(
buf,
args...,
"\n");
204 #if defined(OPENSSL_WINDOWS)
205 HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
208 WriteFile(stderr_handle,
buf, strlen(
buf), &unused,
nullptr);
218 UnwindStatus() : err_(nullptr) {}
219 explicit UnwindStatus(
const char *
err) : err_(
err) {}
221 bool ok()
const {
return err_ ==
nullptr; }
222 const char *Error()
const {
return err_; }
229 class UnwindStatusOr {
238 const char *Error()
const {
return status_.Error(); }
240 const T &ValueOrDie(
const char *
msg =
"Unexpected error")
const {
242 FatalError(
msg,
": ", Error());
254 #if defined(OPENSSL_WINDOWS)
257 explicit UnwindCursor(
const CONTEXT &
ctx) :
ctx_(
ctx) {
258 starting_ip_ =
ctx_.Rip;
261 crypto_word_t starting_ip()
const {
return starting_ip_; }
265 UnwindStatusOr<bool> Step() {
266 bool is_top = is_top_;
270 RUNTIME_FUNCTION *entry =
271 RtlLookupFunctionEntry(
ctx_.Rip, &image_base,
nullptr);
272 if (entry ==
nullptr) {
276 return UnwindStatus(
"leaf function found below the top frame");
286 DWORD64 establisher_frame;
287 RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base,
ctx_.Rip, entry, &
ctx_,
288 &handler_data, &establisher_frame,
nullptr);
289 return ctx_.Rip != 0;
293 UnwindStatusOr<crypto_word_t> GetIP() {
return ctx_.Rip; }
296 UnwindStatusOr<crypto_word_t> GetSP() {
return ctx_.Rsp; }
299 UnwindStatusOr<CallerState> GetCallerState() {
325 StrCatSignalSafe(starting_ip_buf_,
"0x", WordToHex(starting_ip_).
data());
326 return starting_ip_buf_;
331 crypto_word_t starting_ip_;
332 char starting_ip_buf_[64];
335 #else // !OPENSSL_WINDOWS
338 explicit UnwindCursor(unw_context_t *
ctx) :
ctx_(
ctx) {
339 int ret = InitAtSignalFrame(&cursor_);
341 FatalError(
"Error getting unwind context: ", unw_strerror(
ret));
343 starting_ip_ = GetIP().ValueOrDie(
"Error getting instruction pointer");
348 UnwindStatusOr<bool> Step() {
349 int ret = unw_step(&cursor_);
351 return UNWError(
ret);
357 UnwindStatusOr<crypto_word_t> GetIP() {
359 int ret = GetReg(&ip, UNW_REG_IP);
361 return UNWError(
ret);
367 UnwindStatusOr<crypto_word_t> GetSP() {
369 int ret = GetReg(&sp, UNW_REG_SP);
371 return UNWError(
ret);
377 UnwindStatusOr<CallerState> GetCallerState() {
380 #if defined(OPENSSL_X86_64)
388 #error "unknown architecture"
391 return UNWError(
ret);
404 if (InitAtSignalFrame(&cursor) != 0 ||
405 unw_get_proc_name(&cursor, starting_ip_buf_,
sizeof(starting_ip_buf_),
407 StrCatSignalSafe(starting_ip_buf_,
"0x", WordToHex(starting_ip_).
data());
408 return starting_ip_buf_;
410 size_t len = strlen(starting_ip_buf_);
413 StrCatSignalSafe(bssl::Span<char>(starting_ip_buf_).subspan(
len),
"+",
414 WordToDecimal(off).
data(),
" (0x",
415 WordToHex(starting_ip_).
data(),
")");
416 return starting_ip_buf_;
420 static UnwindStatus UNWError(
int ret) {
422 const char *
msg = unw_strerror(
ret);
423 return UnwindStatus(
msg ==
nullptr ?
"unknown error" :
msg);
426 int InitAtSignalFrame(unw_cursor_t *cursor) {
431 int ret = unw_init_local(cursor,
ctx_);
436 ret = unw_is_signal_frame(cursor);
443 ret = unw_step(cursor);
450 int GetReg(crypto_word_t *
out, unw_regnum_t reg) {
452 int ret = unw_get_reg(&cursor_, reg, &val);
454 static_assert(
sizeof(crypto_word_t) ==
sizeof(unw_word_t),
455 "crypto_word_t and unw_word_t are inconsistent");
462 unw_cursor_t cursor_;
463 crypto_word_t starting_ip_;
464 char starting_ip_buf_[64];
466 #endif // OPENSSL_WINDOWS
470 static bool g_in_trampoline =
false;
473 static bool g_unwind_function_done;
476 static CallerState g_trampoline_state;
479 static crypto_word_t g_trampoline_sp;
484 static constexpr
size_t kMaxUnwindErrors = 10;
488 static size_t g_num_unwind_errors = 0;
491 #if defined(OPENSSL_WINDOWS)
497 static UnwindError g_unwind_errors[kMaxUnwindErrors];
499 template <
typename...
Args>
500 static void AddUnwindError(UnwindCursor *cursor,
Args...
args) {
501 if (g_num_unwind_errors >= kMaxUnwindErrors) {
504 #if defined(OPENSSL_WINDOWS)
507 g_unwind_errors[g_num_unwind_errors].ip = cursor->starting_ip();
508 StrCatSignalSafe(g_unwind_errors[g_num_unwind_errors].
str,
args...);
510 StrCatSignalSafe(g_unwind_errors[g_num_unwind_errors].
str,
511 "unwinding at ", cursor->ToString(),
": ",
args...);
513 g_num_unwind_errors++;
516 static void CheckUnwind(UnwindCursor *cursor) {
517 const crypto_word_t kStartAddress =
519 const crypto_word_t kReturnAddress =
521 const crypto_word_t kStopAddress =
524 crypto_word_t sp = cursor->GetSP().ValueOrDie(
"Error getting stack pointer");
526 cursor->GetIP().ValueOrDie(
"Error getting instruction pointer");
527 if (!g_in_trampoline) {
528 if (ip != kStartAddress) {
529 FatalError(
"Unexpected SIGTRAP at ", cursor->ToString());
533 g_in_trampoline =
true;
534 g_unwind_function_done =
false;
535 g_trampoline_sp = sp;
536 g_trampoline_state = cursor->GetCallerState().ValueOrDie(
537 "Error getting initial caller state");
539 if (sp == g_trampoline_sp || g_unwind_function_done) {
545 if (ip == kReturnAddress && sp == g_trampoline_sp) {
546 g_unwind_function_done =
true;
548 if (ip == kStopAddress && sp == g_trampoline_sp) {
550 g_in_trampoline =
false;
552 }
else if (IsAncestorStackFrame(sp, g_trampoline_sp)) {
555 AddUnwindError(cursor,
"stack frame is before caller");
556 g_in_trampoline =
false;
557 }
else if (g_num_unwind_errors < kMaxUnwindErrors) {
559 UnwindStatusOr<bool> step_ret = cursor->Step();
560 if (!step_ret.ok()) {
561 AddUnwindError(cursor,
"error unwinding: ", step_ret.Error());
565 if (!step_ret.ValueOrDie()) {
566 AddUnwindError(cursor,
"could not unwind to starting frame");
570 UnwindStatusOr<crypto_word_t> cur_sp = cursor->GetSP();
572 AddUnwindError(cursor,
573 "error recovering stack pointer: ", cur_sp.Error());
576 if (IsAncestorStackFrame(cur_sp.ValueOrDie(), g_trampoline_sp)) {
577 AddUnwindError(cursor,
"unwound past starting frame");
580 if (cur_sp.ValueOrDie() == g_trampoline_sp) {
582 UnwindStatusOr<crypto_word_t> cur_ip = cursor->GetIP();
584 AddUnwindError(cursor,
585 "error recovering return address: ", cur_ip.Error());
586 }
else if (cur_ip.ValueOrDie() != kReturnAddress) {
587 AddUnwindError(cursor,
"wrong return address");
591 UnwindStatusOr<CallerState>
state = cursor->GetCallerState();
593 AddUnwindError(cursor,
594 "error recovering registers: ",
state.Error());
596 ForEachMismatch(
state.ValueOrDie(), g_trampoline_state,
597 [&](
const char *reg) {
598 AddUnwindError(cursor, reg,
" was not recovered");
608 static void ReadUnwindResult(
Result *
out) {
609 for (
size_t i = 0;
i < g_num_unwind_errors;
i++) {
610 #if defined(OPENSSL_WINDOWS)
611 const crypto_word_t ip = g_unwind_errors[
i].ip;
613 DWORD64 displacement;
618 memset(&symbol, 0,
sizeof(symbol));
619 symbol.info.SizeOfStruct =
sizeof(symbol.info);
620 symbol.info.MaxNameLen =
sizeof(symbol.name_buf);
621 if (SymFromAddr(GetCurrentProcess(), ip, &displacement, &symbol.info)) {
622 snprintf(
buf,
sizeof(
buf),
"unwinding at %s+%llu (0x%s): %s",
623 symbol.info.Name, displacement, WordToHex(ip).
data(),
624 g_unwind_errors[i].
str);
626 snprintf(
buf,
sizeof(
buf),
"unwinding at 0x%s: %s",
627 WordToHex(ip).
data(), g_unwind_errors[i].
str);
629 out->errors.emplace_back(
buf);
631 out->errors.emplace_back(g_unwind_errors[i].
str);
634 if (g_num_unwind_errors == kMaxUnwindErrors) {
635 out->errors.emplace_back(
"(additional errors omitted)");
637 g_num_unwind_errors = 0;
640 #if defined(OPENSSL_WINDOWS)
641 static DWORD g_main_thread;
643 static long ExceptionHandler(EXCEPTION_POINTERS *info) {
644 if (info->ExceptionRecord->ExceptionCode != EXCEPTION_SINGLE_STEP ||
645 GetCurrentThreadId() != g_main_thread) {
646 return EXCEPTION_CONTINUE_SEARCH;
649 UnwindCursor cursor(*info->ContextRecord);
650 CheckUnwind(&cursor);
651 if (g_in_trampoline) {
653 info->ContextRecord->EFlags |= 0x100;
655 return EXCEPTION_CONTINUE_EXECUTION;
659 if (IsDebuggerPresent()) {
662 fprintf(
stderr,
"Debugger detected. Disabling unwind tests.\n");
666 g_main_thread = GetCurrentThreadId();
668 SymSetOptions(SYMOPT_DEFERRED_LOADS);
669 if (!SymInitialize(GetCurrentProcess(),
nullptr, TRUE)) {
670 fprintf(
stderr,
"Could not initialize symbols.\n");
673 if (AddVectoredExceptionHandler(0, ExceptionHandler) ==
nullptr) {
674 fprintf(
stderr,
"Error installing exception handler.\n");
680 #else // !OPENSSL_WINDOWS
683 template <
typename Func>
684 static auto HandleEINTR(
const Func &
func) -> decltype(
func()) {
688 }
while (
ret < 0 && errno == EINTR);
695 int fd = HandleEINTR([&] {
return open(
path, O_RDONLY); });
711 out->append(
buf,
static_cast<size_t>(
ret));
715 static bool IsBeingDebugged() {
717 if (!ReadFileToString(&
status,
"/proc/self/status")) {
718 perror(
"error reading /proc/self/status");
723 if (
idx == std::string::npos) {
730 static pthread_t g_main_thread;
732 static void TrapHandler(
int sig) {
739 if (!pthread_equal(g_main_thread, pthread_self())) {
740 FatalError(
"SIGTRAP on background thread");
744 int ret = unw_getcontext(&
ctx);
746 FatalError(
"Error getting unwind context: ", unw_strerror(
ret));
749 UnwindCursor cursor(&
ctx);
750 CheckUnwind(&cursor);
754 if (IsBeingDebugged()) {
756 fprintf(
stderr,
"Debugger detected. Disabling unwind tests.\n");
760 g_main_thread = pthread_self();
762 struct sigaction trap_action;
764 sigemptyset(&trap_action.sa_mask);
765 trap_action.sa_handler = TrapHandler;
766 if (sigaction(SIGTRAP, &trap_action, NULL) != 0) {
773 #endif // OPENSSL_WINDOWS
775 #else // !SUPPORTS_UNWIND_TEST
777 #if defined(SUPPORTS_ABI_TEST)
778 static void ReadUnwindResult(
Result *) {}
782 #endif // SUPPORTS_UNWIND_TEST