pointers-memory · intermediate · ~25 min

Detect a buffer overflow with a canary

The mechanism behind GCC's -fstack-protector.

Challenge

Implement two functions over this struct:

typedef struct { uint32_t canary_lo; char buf[16]; uint32_t canary_hi; } guarded_t;
void guarded_init(guarded_t *g);
int  guarded_check(const guarded_t *g);   /* 1 if both canaries intact, 0 otherwise */

After guarded_init, both canaries hold the magic value 0xDEADBEEFu. guarded_check reports whether either has since been overwritten.

(In a real program the canary would sit between a local buffer and the saved return address. To keep this exercise safe to run under -fstack-protector we simulate corruption by writing to g->canary_hi directly from the test code — no actual overflow.)

Why this matters

Stack canaries are the cheap, ubiquitous defense against buffer overflows — every modern compiler emits them. Implementing the concept yourself in pure C makes the mechanism obvious.

Input format

Pointer to a guarded_t.

Output format

0 or 1 from guarded_check.

Constraints

No allocations; just set / compare fields.

Starter code

#include <stdint.h>
#ifndef GUARDED_T_DEFINED
#define GUARDED_T_DEFINED
typedef struct { uint32_t canary_lo; char buf[16]; uint32_t canary_hi; } guarded_t;
#endif
void guarded_init(guarded_t *g);
int  guarded_check(const guarded_t *g);

Common mistakes

Setting the canary to 0 (any uninitialized memory looks like a corrupted canary); checking only one canary (real overflows can come from either side via under/over-runs); using == against the wrong magic word.

Edge cases to handle

Both canaries intact — return 1. Either canary changed — return 0.

Complexity

O(1).

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.