cybersecurity · intermediate · ~15 min · safe pentest lab

Fix a toy buffer overflow

Apply bounded-copy + early failure on overflow.

Challenge

Patch a deliberately vulnerable function that copies a string into a fixed buffer with no bounds check:

void render(const char *user_input, char *banner) {
    strcpy(banner, "Welcome, ");
    strcat(banner, user_input);   // unbounded — overflows banner
}

Task

Implement int render_safe(const char *user_input, char *banner, size_t banner_sz) that writes "Welcome, <user_input>" into banner without ever overflowing it.

Input

  • user_input: a NUL-terminated string the grader passes.
  • banner: the destination buffer.
  • banner_sz: the size of banner in bytes.

Output

Returns 0 on success (with banner holding "Welcome, <user_input>"), or -1 if the full result would not fit. On overflow, banner is guaranteed NUL-terminated.

Example

render_safe("Alice", buf, 32)               ->   0, buf = "Welcome, Alice"
render_safe("Very Long User Name", buf, 12) ->   -1, buf NUL-terminated

Edge cases

  • Result exactly fills the buffer (counting the trailing NUL): success.
  • Result one byte too long: return -1, leave banner NUL-terminated.
  • banner_sz == 0: return -1.

Rules

  • Use a bounded write (e.g. snprintf) and detect truncation via its return value.

Why this matters

Patching a deliberately vulnerable function teaches the diagnostic mindset: spot the unbounded write, audit the destination size, replace with a bounded equivalent. This is the daily work of security auditors.

Input format

A NUL-terminated user_input, a destination buffer banner, and its size banner_sz.

Output format

0 on success (banner = "Welcome, "); -1 on overflow (banner NUL-terminated).

Constraints

Never write past banner_sz; always NUL-terminate; detect truncation.

Starter code

#include <stdio.h>
#include <string.h>

int render_safe(const char *user_input, char *banner, size_t banner_sz) {
    /* TODO */
    return -1;
}

Common mistakes

Replacing only the symptom (the obvious strcpy) without checking the rest of the function — overflows often come in pairs. Using strncpy (gotcha — doesn't NUL-terminate when source fits exactly).

Edge cases to handle

Maximum-length input. Empty input. Input containing NUL bytes (rare in text, common in binary).

Complexity

O(input length).

Background lessons

Up next

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