a stack canary
Coal miners once carried a canary in a cage down the shaft. The bird was more sensitive to poison gas than people, so if it stopped singing or keeled over, the miners knew danger had arrived in time to flee. A stack canary borrows the name and the idea: place a fragile little sentinel right where an attack would first do damage, and check whether it has been harmed. If the canary is dead, you know the attack happened and you stop before it can finish.
Recall how a stack buffer overflow does its harm: it writes past a local buffer and overwrites the function's saved return address, which sits just beyond the buffer on the stack, so that when the function returns the CPU jumps to attacker-chosen code. A stack canary defends this exact spot. When a function starts, the compiler inserts a secret guard value — the canary — into the stack just before the saved return address. Right before the function returns, it inserts a check: is the canary still the value we placed there? An overflow large enough to reach and corrupt the return address must, on its way, overwrite the canary that sits in front of it. So if the canary has changed, the program knows the stack was smashed and aborts immediately, refusing to return into whatever the attacker planted. To stop the attacker from simply writing the correct canary value back in, the canary is random (chosen fresh per process) and secret, and often includes a zero byte to trip up string-copy attacks.
Stack canaries are a cheap, automatic, and very widely used defense — modern compilers add them with a flag, and they turn many would-be code-execution exploits into mere crashes. But they are honestly a targeted guard, not a general one, and a clever attacker has ways around them. If a bug leaks the canary value, the attacker can write it back unchanged and sail past the check. Overflows that do not run contiguously over the canary — for instance writing to an attacker-chosen offset, or overwriting a different pointer or a local variable rather than the return address — can sidestep it entirely. And the canary protects the return address, not other sensitive stack data. That is precisely why canaries are deployed together with ASLR, no-execute memory, and ultimately memory-safe coding, as one layer of defense in depth rather than a complete fix.
On entry a function stores a secret 8-byte canary just below the return address. An overflow of buf writes past it and corrupts the canary on the way to the return address. Just before returning, the inserted check sees the canary no longer matches and calls an abort routine — the program dies cleanly instead of jumping into the attacker's code.
Corrupt the canary on the way to the return address, and the check catches it.
A canary guards the return address specifically. If a bug leaks the canary value an attacker can rewrite it and pass the check, and overflows that skip over it (or hit other data) bypass it — so it is one layer, not a complete fix.