1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

Nice stack smashing postmortem message (#8670)

Wire everything that relies on stack smashing detection to call
`__stack_chk_fail()` (aka what libssp / ssp / stack-protector uses)
Expose it in our debugging header

Rename overflow -> smashing, as these are different things we are trying
to detect (meaning, that we check for things writing there, not some
kind of `alloca` issue or the way `-fstack-check` would have worked)
ref. #8666

`-fstack-protector` continues to work as it always did
CONT replaces `abort()`, also moves its check to the loop wrapper to
avoid dumping otherwise useless SYS context memory
StackThunk replaces a similar `abort()` call
This commit is contained in:
Max Prokhorov 2022-10-31 07:15:42 +03:00 committed by GitHub
parent 5f94a60d78
commit bde8ef7af7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 36 additions and 27 deletions

View File

@ -142,11 +142,12 @@ void stack_thunk_dump_stack()
ets_printf("<<<stack<<<\n"); ets_printf("<<<stack<<<\n");
} }
/* Called when the stack overflow is detected by a thunk. Main memory is corrupted at this point. Do not return. */ /* Called when the stack overflow is detected by a thunk. Main memory is corrupted at this point.
void stack_thunk_fatal_overflow() * Do not return, use libssp-compatible function to notify postmortem and immediately reboot. */
void stack_thunk_fatal_smashing()
{ {
ets_printf("FATAL ERROR: BSSL stack overflow\n"); ets_printf("FATAL ERROR: BSSL stack smashing detected\n");
abort(); __stack_chk_fail();
} }
}; }

View File

@ -41,7 +41,7 @@ extern uint32_t stack_thunk_get_stack_bot();
extern uint32_t stack_thunk_get_cont_sp(); extern uint32_t stack_thunk_get_cont_sp();
extern uint32_t stack_thunk_get_max_usage(); extern uint32_t stack_thunk_get_max_usage();
extern void stack_thunk_dump_stack(); extern void stack_thunk_dump_stack();
extern void stack_thunk_fatal_overflow(); extern void stack_thunk_fatal_smashing();
// Globals required for thunking operation // Globals required for thunking operation
extern uint32_t *stack_thunk_ptr; extern uint32_t *stack_thunk_ptr;
@ -75,7 +75,7 @@ thunk_"#fcnToThunk":\n\
l32i.n a15, a15, 0 /* A15 now has contents of last stack entry */\n\ l32i.n a15, a15, 0 /* A15 now has contents of last stack entry */\n\
l32r a0, .LC_STACK_VALUE"#fcnToThunk" /* A0 now has the check value */\n\ l32r a0, .LC_STACK_VALUE"#fcnToThunk" /* A0 now has the check value */\n\
beq a0, a15, .L1"#fcnToThunk"\n\ beq a0, a15, .L1"#fcnToThunk"\n\
call0 stack_thunk_fatal_overflow\n\ call0 stack_thunk_fatal_smashing\n\
.L1"#fcnToThunk":\n\ .L1"#fcnToThunk":\n\
movi a15, stack_thunk_save /* Restore A1(SP) */\n\ movi a15, stack_thunk_save /* Restore A1(SP) */\n\
l32i.n a1, a15, 0\n\ l32i.n a1, a15, 0\n\

View File

@ -62,9 +62,8 @@ void cont_run(cont_t*, void (*pfn)(void));
// execution state (registers and stack) // execution state (registers and stack)
void cont_suspend(cont_t*); void cont_suspend(cont_t*);
// Check guard bytes around the stack. Return 0 in case everything is ok, // Check guard bytes around the stack. Immediately panics on failure.
// return 1 if guard bytes were overwritten. void cont_check(cont_t*);
int cont_check(cont_t* cont);
// Go through stack and check how many bytes are most probably still unchanged // Go through stack and check how many bytes are most probably still unchanged
// and thus weren't used by the user code. i.e. that stack space is free. (high water mark) // and thus weren't used by the user code. i.e. that stack space is free. (high water mark)

View File

@ -18,14 +18,18 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "cont.h" #include <ets_sys.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include "ets_sys.h"
extern "C" { #include "cont.h"
#include "debug.h"
#define CONT_STACKGUARD 0xfeefeffe extern "C"
{
static constexpr unsigned int CONT_STACKGUARD { 0xfeefeffe };
void cont_init(cont_t* cont) { void cont_init(cont_t* cont) {
memset(cont, 0, sizeof(cont_t)); memset(cont, 0, sizeof(cont_t));
@ -42,10 +46,15 @@ void cont_init(cont_t* cont) {
} }
} }
int IRAM_ATTR cont_check(cont_t* cont) { void IRAM_ATTR cont_check(cont_t* cont) {
if(cont->stack_guard1 != CONT_STACKGUARD || cont->stack_guard2 != CONT_STACKGUARD) return 1; if ((cont->stack_guard1 == CONT_STACKGUARD)
&& (cont->stack_guard2 == CONT_STACKGUARD))
{
return;
}
return 0; __stack_chk_fail();
__builtin_unreachable();
} }
// No need for this to be in IRAM, not expected to be IRQ called // No need for this to be in IRAM, not expected to be IRQ called

View File

@ -245,21 +245,21 @@ static void loop_wrapper() {
} }
loop(); loop();
loop_end(); loop_end();
cont_check(g_pcont);
if (serialEventRun) { if (serialEventRun) {
serialEventRun(); serialEventRun();
} }
esp_schedule(); esp_schedule();
} }
extern "C" void __stack_chk_fail(void);
static void loop_task(os_event_t *events) { static void loop_task(os_event_t *events) {
(void) events; (void) events;
s_cycles_at_resume = ESP.getCycleCount(); s_cycles_at_resume = ESP.getCycleCount();
ESP.resetHeap(); ESP.resetHeap();
cont_run(g_pcont, &loop_wrapper); cont_run(g_pcont, &loop_wrapper);
ESP.setDramHeap(); ESP.setDramHeap();
if (cont_check(g_pcont) != 0) {
panic();
}
} }
extern "C" { extern "C" {

View File

@ -42,9 +42,12 @@ static int s_panic_line = 0;
static const char* s_panic_func = 0; static const char* s_panic_func = 0;
static const char* s_panic_what = 0; static const char* s_panic_what = 0;
// Our wiring for abort() and C++ exceptions
static bool s_abort_called = false; static bool s_abort_called = false;
static const char* s_unhandled_exception = NULL; static const char* s_unhandled_exception = NULL;
// Common way to notify about where the stack smashing happened
// (but, **only** if caller uses our handler function)
static uint32_t s_stacksmash_addr = 0; static uint32_t s_stacksmash_addr = 0;
void abort() __attribute__((noreturn)); void abort() __attribute__((noreturn));
@ -154,7 +157,7 @@ void __wrap_system_restart_local() {
ets_printf_P(PSTR("\nSoft WDT reset\n")); ets_printf_P(PSTR("\nSoft WDT reset\n"));
} }
else if (rst_info.reason == REASON_USER_STACK_SMASH) { else if (rst_info.reason == REASON_USER_STACK_SMASH) {
ets_printf_P(PSTR("\nStack overflow detected.\n")); ets_printf_P(PSTR("\nStack smashing detected.\n"));
ets_printf_P(PSTR("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n"), ets_printf_P(PSTR("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n"),
5 /* Alloca exception, closest thing to stack fault*/, s_stacksmash_addr, 0, 0, 0, 0); 5 /* Alloca exception, closest thing to stack fault*/, s_stacksmash_addr, 0, 0, 0, 0);
} }
@ -310,8 +313,6 @@ void __panic_func(const char* file, int line, const char* func) {
uintptr_t __stack_chk_guard = 0x08675309 ^ RANDOM_REG32; uintptr_t __stack_chk_guard = 0x08675309 ^ RANDOM_REG32;
void __stack_chk_fail(void) { void __stack_chk_fail(void) {
s_user_reset_reason = REASON_USER_STACK_SMASH; s_user_reset_reason = REASON_USER_STACK_SMASH;
ets_printf_P(PSTR("\nPANIC: Stack overrun"));
s_stacksmash_addr = (uint32_t)__builtin_return_address(0); s_stacksmash_addr = (uint32_t)__builtin_return_address(0);
if (gdb_present()) if (gdb_present())
@ -319,8 +320,7 @@ void __stack_chk_fail(void) {
__wrap_system_restart_local(); __wrap_system_restart_local();
while (1); // never reached, needed to satisfy "noreturn" attribute __builtin_unreachable(); // never reached, needed to satisfy "noreturn" attribute
} }
} // extern "C"
};

View File

@ -26,7 +26,7 @@ void hexdump(const void* mem, uint32_t len, uint8_t cols);
extern "C" extern "C"
{ {
#endif #endif
void __stack_chk_fail(void) __attribute__((noreturn));
void __unhandled_exception(const char* str) __attribute__((noreturn)); void __unhandled_exception(const char* str) __attribute__((noreturn));
void __panic_func(const char* file, int line, const char* func) __attribute__((noreturn)); void __panic_func(const char* file, int line, const char* func) __attribute__((noreturn));
#define panic() __panic_func(PSTR(__FILE__), __LINE__, __func__) #define panic() __panic_func(PSTR(__FILE__), __LINE__, __func__)