Exploit Mitigations for Embedded C
Buffer overflows still work on microcontrollers largely because the mitigations are turned off. Most of them are a compiler flag or a linker setting away, and each one removes a rung from the attacker’s ladder. Here are the embedded exploit mitigations that matter and how to confirm they are actually doing their job.
Why Mitigations Matter More on MCUs
On a desktop, a memory bug usually meets canaries, non-executable memory, and address randomization before it becomes an exploit. On bare-metal firmware those layers are often absent by default, so a single bug goes straight to control. Enabling the equivalents is the cheapest security work available on embedded.
Building With Protection On
Start with the compiler. A stack canary alone converts many exploitable overflows into clean resets:

arm-none-eabi-gcc -fstack-protector-strong \ -fstack-clash-protection -O2 fw.c -o fw.elf
Confirming the Canary Fires
Build it, then smash the stack and watch the guard catch it instead of the return executing:
# overflow the buffer at runtime
python3 -c "print('A'*80)" | ./send_to_device
*** stack smashing detected *** __stack_chk_fail invoked System reset (fault handler)
Instead of jumping to 0x41414141, the device detected the corruption and reset. The bug is still there, but it is no longer a reliable exploit primitive.
Three Mitigations Worth Enabling
If you do nothing else, enable these three:

Defense in Depth
Add MPU regions to isolate tasks and mark RAM non-executable, keep bounds-checked string handling in the parsers, and fail safe by resetting on any detected fault rather than continuing in a corrupted state. None of these is sufficient alone; together they raise exploitation cost sharply.
Where This Fits
Reviewing build hardening and confirming mitigations are active on shipping firmware is part of a product security assessment. That review is the kind of work we do at Berkner Tech.