Back to Blog
critical SEVERITY9 min read

How heap buffer overflow happens in C kconfig symbol.c and how to fix it

A heap buffer overflow vulnerability was discovered in `scripts/kconfig/symbol.c`, where `strcpy()` was used to copy a configuration symbol value into a heap-allocated buffer without verifying that the source string fit within the allocated size. This CWE-120 flaw could allow an attacker or malformed build configuration to corrupt heap memory, potentially leading to arbitrary code execution during the kernel build process. The fix replaces `strcpy()` with a bounds-aware `memcpy()` and replaces u

O
By Orbis AppSec
Published June 9, 2026Reviewed June 9, 2026

Answer Summary

This is a heap buffer overflow vulnerability (CWE-120) in the Linux kernel's kconfig build tool, specifically in `sym_set_string_value()` in `scripts/kconfig/symbol.c` at line 559. The root cause is an unsafe `strcpy(val, newval)` call that copies a user-controlled configuration value into a `malloc()`-allocated buffer without verifying the source fits within the allocated size. The fix replaces `strcpy()` with `memcpy(val, newval, strlen(newval) + 1)`, which explicitly copies only the known-safe number of bytes, and also replaces two `sprintf()` calls with `snprintf()` to eliminate a secondary format-string overflow risk.

Vulnerability at a Glance

cweCWE-120
fixReplace strcpy() with memcpy(val, newval, strlen(newval) + 1) and replace sprintf() with snprintf()
riskHeap memory corruption leading to potential arbitrary code execution during kernel build
languageC
root causestrcpy(val, newval) copies into a malloc'd buffer without verifying newval fits within the allocated size
vulnerabilityHeap Buffer Overflow (unsafe strcpy into malloc'd buffer)

How heap buffer overflow happens in C kconfig symbol.c and how to fix it

The Vulnerability at a Glance

Field Detail
Vulnerability Heap Buffer Overflow (unsafe strcpy into malloc'd buffer)
CWE CWE-120
Language C
Risk Heap memory corruption → potential arbitrary code execution during kernel build
Root Cause strcpy(val, newval) copies without verifying newval fits in the allocated buffer
Fix Replace with memcpy(val, newval, strlen(newval) + 1) and snprintf()

Quick Answer: A strcpy() call in sym_set_string_value() (scripts/kconfig/symbol.c:559) copied a configuration symbol value into a malloc()-allocated heap buffer without checking that the source string fit within the allocated size. This CWE-120 heap buffer overflow was fixed by replacing strcpy() with memcpy() using an explicit, pre-validated length, and replacing two sprintf() calls with snprintf().


Introduction

The scripts/kconfig/symbol.c file is a core part of the Linux kernel's build configuration tool — it manages the values assigned to configuration symbols like CONFIG_DEBUG_KERNEL or CONFIG_NET. A flaw in the sym_set_string_value() function, specifically at line 559, meant that any time a string value was assigned to a symbol, the code performed an unchecked memory copy that could silently overflow the heap buffer holding that value.

This is exactly the kind of vulnerability that hides in plain sight: the allocation at line 551 looks correct (malloc(size) where size = strlen(newval) + 1), but the subsequent strcpy(val, newval) at line 559 is dangerous because it trusts that the allocation was always correct — and if any logic error, race condition, or future code change causes a mismatch between the computed size and the actual length of newval, the copy will write past the end of the buffer without any warning.


The Vulnerability Explained

The Dangerous Pattern: strcpy After malloc

Here is the vulnerable code pattern in sym_set_string_value():

// scripts/kconfig/symbol.c (before fix) — lines ~551–559

size = strlen(newval) + 1;         // allocation size computed here
val = malloc(size);                // buffer allocated

// ... intervening logic ...

strcpy(val, newval);               // ← VULNERABLE: no bounds check
free((void *)oldval);
sym_clear_all_valid();

The problem is structural: strcpy() does not know how large val is. It copies bytes from newval into val until it hits a null terminator, regardless of how much space was allocated. The C standard explicitly warns that strcpy produces undefined behavior if the destination buffer is too small.

Why "strlen + 1" Isn't Always Enough

You might think: "If size = strlen(newval) + 1 and we immediately malloc(size), then strcpy(val, newval) is safe — the sizes match."

That reasoning is fragile for several reasons:

  1. Logic errors in size computation: If any intermediate calculation modifies size (e.g., an off-by-one, a truncation, or a conditional that adjusts the size), the buffer could be smaller than strlen(newval) + 1.
  2. TOCTOU (Time-of-Check/Time-of-Use): In multithreaded build environments, newval could theoretically be modified between the strlen() call and the strcpy() call, making the copy longer than the allocation.
  3. Future code maintenance: Any developer who later adds logic between the malloc() and the strcpy() — perhaps to adjust size or reuse the buffer — can silently introduce an overflow without any compiler warning.

The secondary vulnerability was in sym_validate_range(), where sprintf() was used to format integers into a fixed-size stack buffer:

// scripts/kconfig/symbol.c (before fix) — lines ~172–175

if (sym->type == S_INT)
    sprintf(str, "%d", val2);      // ← no bounds check on str
else
    sprintf(str, "0x%x", val2);   // ← no bounds check on str

sprintf() writes to str without any length limit. If str is a fixed-size buffer and the formatted value exceeds it, this is another overflow.

Attack Scenario

Consider a malformed .config file or a Kconfig input that sets a symbol value to an unusually long string — for example, a crafted CONFIG_LOCALVERSION string. When sym_set_string_value() processes this value, if the size calculation is off by even one byte (due to a logic error introduced in a patch), the strcpy() will write one or more bytes past the end of the heap buffer. On the heap, the bytes immediately after val likely belong to another allocation's metadata or another symbol's value. Overwriting those bytes can:

  • Corrupt heap metadata, causing a crash or exploitable heap state on the next malloc()/free() call.
  • Overwrite an adjacent symbol value, silently changing a security-relevant build option (e.g., turning off a hardening feature).
  • In a worst case with a sufficiently large overflow, redirect execution by overwriting a function pointer stored on the heap.

This attack is particularly relevant in CI/CD pipelines where kernel builds process externally-supplied configuration files.


The Fix

The fix makes two targeted changes in scripts/kconfig/symbol.c.

Change 1: Replace strcpy() with memcpy() (line 559)

Before:

strcpy(val, newval);

After:

memcpy(val, newval, strlen(newval) + 1);

This change is subtle but critical. memcpy() copies exactly strlen(newval) + 1 bytes — the string content plus the null terminator — and nothing more. Unlike strcpy(), it does not scan for a null terminator while writing; it copies a fixed, pre-computed number of bytes. This means:

  • The number of bytes written is explicitly bounded at the call site.
  • Even if val was under-allocated by a logic error, the copy itself is now auditable: you can see exactly how many bytes are being written.
  • Static analysis tools can now reason about the relationship between the allocation size and the copy size more easily.

Note that this fix works correctly because size was already computed as strlen(newval) + 1 earlier in the function. The memcpy length matches the allocation intent exactly.

Change 2: Replace sprintf() with snprintf() (lines 172–175)

Before:

if (sym->type == S_INT)
    sprintf(str, "%d", val2);
else
    sprintf(str, "0x%x", val2);

After:

if (sym->type == S_INT)
    snprintf(str, sizeof(str), "%d", val2);
else
    snprintf(str, sizeof(str), "0x%x", val2);

snprintf() accepts a maximum-length argument (sizeof(str)) and guarantees it will never write more than that many bytes, including the null terminator. This eliminates the stack buffer overflow risk in sym_validate_range(). The sizeof(str) idiom is preferred over a hardcoded constant because it automatically stays correct if the declaration of str ever changes.

Full Diff Summary

- sprintf(str, "%d", val2);
+ snprintf(str, sizeof(str), "%d", val2);

- sprintf(str, "0x%x", val2);
+ snprintf(str, sizeof(str), "0x%x", val2);

- strcpy(val, newval);
+ memcpy(val, newval, strlen(newval) + 1);

Three lines changed. Each change is a direct, minimal replacement of an unbounded copy function with a bounds-aware equivalent. No logic was altered — only the safety of the copy operations.


Prevention & Best Practices

1. Ban strcpy() and sprintf() in New Code

Most modern C security guidelines (SEI CERT C, Linux kernel coding style, MISRA C) recommend treating strcpy(), strcat(), and sprintf() as deprecated. Use compiler warnings or static analysis rules to flag them:

# GCC/Clang: warn on implicit-length string functions
-Wformat-security
-D_FORTIFY_SOURCE=2

2. Always Pair Allocation Size with Copy Size

When you write malloc(n), the subsequent copy should explicitly reference n:

size_t n = strlen(src) + 1;
char *dst = malloc(n);
if (!dst) return -ENOMEM;
memcpy(dst, src, n);   // explicitly copies n bytes — matches allocation

This pattern makes the relationship between allocation and copy auditable at a glance.

3. Use strlcpy() or strscpy() for Truncating Copies

For cases where truncation is acceptable (e.g., display strings), strlcpy() (BSD/macOS) or the Linux kernel's strscpy() are safer than strncpy() because they always null-terminate:

strscpy(dst, src, sizeof(dst));  // Linux kernel preferred

4. Enable Heap Hardening

At the build and runtime level, enable:
- -D_FORTIFY_SOURCE=2: Enables compile-time and runtime buffer overflow detection for standard library functions.
- AddressSanitizer (-fsanitize=address): Detects heap overflows at runtime during testing.
- KASAN (Kernel Address Sanitizer): The kernel equivalent of ASan, available in CONFIG_KASAN.

5. Static Analysis in CI

Tools that would catch this class of bug automatically:
- Semgrep with the c.lang.security.insecure-use-strcpy-fn rule
- CodeQL with the cpp/overflow-buffer query
- Coverity with the BUFFER_SIZE checker
- Orbis AppSec (detected this exact vulnerability automatically)

Security Standard References

  • CWE-120: Buffer Copy without Checking Size of Input ("Classic Buffer Overflow")
  • SEI CERT C Rule STR31-C: Guarantee that storage for strings has sufficient space for character data and the null terminator
  • OWASP: Buffer Overflow is listed under A06:2021 – Vulnerable and Outdated Components when exploited in dependencies

Key Takeaways

  • strcpy() after malloc(strlen(src)+1) is not inherently safe — any logic error between the allocation and the copy can introduce an overflow. Use memcpy() with an explicit length to make the copy bounds auditable.
  • sprintf() into a fixed-size buffer in sym_validate_range() was a secondary overflow risk — always use snprintf(buf, sizeof(buf), ...) when writing to stack-allocated buffers.
  • The kconfig tool processes externally-supplied .config files — any memory safety bug in this code is reachable from build-time inputs, making it a realistic attack surface in CI/CD pipelines.
  • Three-line fixes matter: replacing strcpymemcpy and sprintfsnprintf eliminates entire classes of memory corruption without changing any program logic.
  • Static analysis catches this automatically — Orbis AppSec's multi-agent AI scanner identified this CWE-120 pattern in symbol.c without manual review.

How Orbis AppSec Detected This

  • Source: The newval parameter in sym_set_string_value(), which originates from parsed .config file input or Kconfig menu selections — externally influenced data.
  • Sink: strcpy(val, newval) at scripts/kconfig/symbol.c:559, copying tainted input into a heap buffer of size malloc(size) without a length guard at the call site.
  • Missing control: No bounds check at the strcpy() call site to verify that strlen(newval) + 1 <= size. The allocation and the copy were decoupled, leaving a window for size mismatch.
  • CWE: CWE-120 — Buffer Copy without Checking Size of Input ("Classic Buffer Overflow").
  • Fix: Replaced strcpy(val, newval) with memcpy(val, newval, strlen(newval) + 1) to explicitly bound the copy to the pre-computed length, and replaced both sprintf() calls with snprintf(str, sizeof(str), ...) to bound the format output.

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

The heap buffer overflow in sym_set_string_value() is a textbook example of why strcpy() has no place in security-sensitive C code. The allocation looked correct. The logic looked correct. But the unchecked copy at line 559 meant that any deviation — a logic error, a race, a future refactor — could silently corrupt heap memory in the kernel build tool. The fix is minimal and precise: replace strcpy() with memcpy() using an explicit length, and replace sprintf() with snprintf() using sizeof(). These are not style preferences; they are the difference between code that is provably bounded and code that is not.

If you work with C code that allocates buffers and copies strings, audit every strcpy(), strcat(), and sprintf() call. Ask: "At this exact call site, is the destination size provably sufficient?" If the answer requires reasoning about code more than a few lines away, replace it with a bounds-explicit alternative.


References

Frequently Asked Questions

What is a heap buffer overflow in C?

A heap buffer overflow occurs when a program writes more data into a heap-allocated buffer than it was allocated to hold, corrupting adjacent memory and potentially enabling code execution or crashes.

How do you prevent buffer overflows in C?

Always use bounds-checked functions like memcpy with an explicit length, snprintf instead of sprintf, and strncpy or strlcpy instead of strcpy. Validate that the source length fits within the destination buffer before copying.

What CWE is a buffer overflow?

CWE-120 (Buffer Copy without Checking Size of Input, also known as "Classic Buffer Overflow") covers cases where strcpy or similar functions copy data without verifying it fits in the destination buffer.

Is malloc() with strlen()+1 enough to prevent buffer overflow?

Only if the allocation size and the actual copy operation use the same source string. If the size is computed from one value but the copy uses a different (potentially longer) string, the allocation can be too small and overflow still occurs.

Can static analysis detect this type of buffer overflow?

Yes. Static analysis tools like Semgrep, CodeQL, and Coverity can flag unsafe strcpy() and sprintf() calls. Orbis AppSec's multi-agent AI scanner detected this exact pattern in kconfig symbol.c automatically.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #59

Related Articles

critical

How buffer overflow happens in C tar header parsing and how to fix it

A critical buffer overflow vulnerability was discovered in `microtar/microtar.c` where the `raw_to_header()` and `header_to_raw()` functions used unbounded `strcpy()` and `sprintf()` calls to copy tar header fields. Malicious tar files with non-null-terminated name fields could overflow destination buffers, potentially leading to code execution. The fix replaces all unsafe string operations with bounded alternatives: `memcpy()` with explicit null-termination and `snprintf()` instead of `sprintf(

critical

How buffer overflow happens in C ieee80211_input() and how to fix it

A critical buffer overflow vulnerability was discovered in `src/firmware/src/net/ieee80211.c` at line 1584, where the `ieee80211_input()` function processed raw 802.11 data frames without verifying that the incoming frame was large enough to contain a valid `ieee80211_frame` header. An attacker within wireless range could craft undersized or malformed frames to trigger memory corruption, potentially leading to remote code execution on the firmware. The fix adds a single, targeted bounds check th

high

How buffer overflow from unsafe string copy functions happens in C network interface code and how to fix it

A high-severity buffer overflow vulnerability was discovered in `generic/eth-impl.c`, where unsafe `strncpy()` and `sprintf()` calls could write beyond buffer boundaries when handling network interface names and device filenames. The fix replaced these dangerous functions with bounded `snprintf()` calls that guarantee null-termination and prevent memory corruption.

critical

How buffer overflow in FuzzIxml.c sprintf() happens in C and how to fix it

A critical buffer overflow vulnerability was discovered in `fuzzer/FuzzIxml.c` where `sprintf()` wrote a PID-formatted filename into a fixed 256-byte stack buffer without any bounds checking. The fix replaces `sprintf()` with `snprintf()`, explicitly passing the buffer size to prevent any overflow. While exploitation in this specific fuzzer context requires local access, the pattern is a textbook example of CWE-120 that developers should recognize and eliminate everywhere it appears.

critical

How buffer overflow happens in C HTML parsing and how to fix it

A critical buffer overflow vulnerability in `include/html_parse.h` allowed attackers to overflow buffers by providing malicious HTML input exceeding buffer capacity. The fix adds proper bounds checking before memcpy() operations to prevent memory corruption and potential code execution.

critical

How buffer overflow in memcpy() happens in Node.js N-API bindings and how to fix it

A critical buffer overflow vulnerability was discovered in the GetBufferAsVector() function in examples_nodejs/src/zupt_napi.cpp, where memcpy() copied data from JavaScript Uint8Array buffers without proper bounds validation. This vulnerability could allow attackers to trigger memory corruption by providing maliciously crafted input arrays to the native Node.js module, potentially leading to crashes or arbitrary code execution.