Back to Blog
critical SEVERITY8 min read

How buffer overflow happens in C SGX enclave memcpy and how to fix it

A critical buffer overflow vulnerability was discovered in `backend/sgx/enclave/enclave.c` where the `ecall_store_data` function performed `memcpy` operations without proper bounds checking against the actual destination buffer size. An attacker could supply a malicious `data_len` parameter to overflow the enclave's secure storage buffer, potentially corrupting trusted execution environment memory. The fix replaces a hardcoded magic number check with a precise size comparison against the actual

O
By Orbis AppSec
Published July 26, 2026Reviewed July 26, 2026

Answer Summary

This is a buffer overflow vulnerability (CWE-120) in C code inside an Intel SGX enclave (`backend/sgx/enclave/enclave.c`). The `ecall_store_data` function checked `data_len > 256` — a hardcoded magic number — instead of comparing against the actual destination buffer size (`sizeof(secure_storage[storage_count].data)`). This meant an attacker could pass a `data_len` that exceeds the real buffer boundary, triggering a heap/stack overflow inside the trusted execution environment. The fix adds a two-part check: reject zero-length inputs and reject any length exceeding `sizeof(secure_storage[storage_count].data)`, ensuring the memcpy can never write past the buffer.

Vulnerability at a Glance

cweCWE-120 (Buffer Copy without Checking Size of Input)
fixReplace `data_len > 256` with `data_len == 0 || data_len > sizeof(secure_storage[storage_count].data)`
riskAttacker-controlled data_len can overflow secure enclave memory, corrupting trusted execution environment state
languageC
root causeBounds check used hardcoded constant 256 instead of actual destination buffer size
vulnerabilityBuffer Overflow via Unchecked memcpy in SGX Enclave

How Buffer Overflow Happens in C SGX Enclave memcpy and How to Fix It

Summary

A critical buffer overflow vulnerability was discovered in backend/sgx/enclave/enclave.c where the ecall_store_data function performed memcpy operations without proper bounds checking against the actual destination buffer size. An attacker could supply a malicious data_len parameter to overflow the enclave's secure storage buffer, potentially corrupting trusted execution environment memory. The fix replaces a hardcoded magic number check with a precise size comparison against the actual destination buffer, closing the vulnerability entirely.


Introduction

The backend/sgx/enclave/enclave.c file sits at the heart of a trusted execution environment: an Intel SGX enclave responsible for securely storing sensitive data. The ecall_store_data function is an ECALL — an entry point that untrusted application code calls to pass data into the enclave for protected storage. This is exactly the boundary where input validation is most critical.

But a subtle flaw in the bounds check at line 78 created a critical security gap. The check read:

if (data_len > 256) {
    return SGX_ERROR_INVALID_PARAMETER;
}

This looks reasonable at a glance. But 256 is a hardcoded magic number with no structural relationship to the actual size of the destination buffer (secure_storage[storage_count].data). If the real buffer is smaller than 256 bytes — or if it was ever resized — this check silently becomes incorrect, and a subsequent memcpy will write past the end of the buffer.

For developers writing C code that interfaces with trusted execution environments, this is a textbook example of why hardcoded size limits are dangerous.


The Vulnerability Explained

What Went Wrong

Inside ecall_store_data, data passed from untrusted code is copied into the enclave's internal secure_storage structure using memcpy. Before the copy, the code validates data_len to prevent overflows:

// VULNERABLE CODE (before fix)
if (data_len > 256) {
    return SGX_ERROR_INVALID_PARAMETER;
}

The problem: the check is against the literal integer 256, not against sizeof(secure_storage[storage_count].data). These two values may or may not be equal. If the data field in the storage struct is, say, 128 bytes, then an attacker can pass data_len = 200 — which passes the > 256 check — and the subsequent memcpy writes 200 bytes into a 128-byte buffer, overflowing by 72 bytes.

There's a second issue the fix also addresses: a data_len of 0 was not rejected. Passing zero length to memcpy is a no-op in standard C, but it can cause logic errors downstream and represents malformed input that should be explicitly rejected.

How an Attacker Could Exploit This

The attack surface here is the ECALL interface itself. An attacker (or a malicious application running outside the enclave) calls ecall_store_data with a crafted data_len that is:

  • Greater than the actual buffer size (e.g., 200 when the buffer is 128 bytes)
  • But less than or equal to 256 (so it passes the broken check)

The memcpy then writes attacker-controlled bytes past the end of secure_storage[storage_count].data, corrupting adjacent fields in the secure_storage array or other enclave memory. In an SGX context, this is particularly severe:

  1. Enclave memory corruption can subvert the integrity guarantees SGX is designed to provide.
  2. Sensitive data leakage: adjacent memory in the enclave may contain cryptographic keys, decrypted secrets, or other protected values.
  3. Control flow hijacking: if a function pointer or return address is adjacent to the overflowed buffer, an attacker may redirect execution within the trusted context.

The PR notes that similar patterns exist at lines 95 and 115 of the same file, suggesting this vulnerability class was applied inconsistently throughout the enclave's input-handling code.

Real-World Impact

SGX enclaves are used specifically because they are supposed to be more trustworthy than regular application memory. A buffer overflow that corrupts enclave memory doesn't just crash the program — it can silently undermine the security model that the entire system is built on. Secrets that were supposed to be protected by the enclave could be exposed or manipulated.


The Fix

What Changed

The fix is a single-line change at line 78 of backend/sgx/enclave/enclave.c:

// BEFORE (vulnerable)
if (data_len > 256) {
    return SGX_ERROR_INVALID_PARAMETER;
}

// AFTER (fixed)
if (data_len == 0 || data_len > sizeof(secure_storage[storage_count].data)) {
    return SGX_ERROR_INVALID_PARAMETER;
}

Why This Fix Works

The new check does two things:

  1. data_len == 0: Rejects zero-length inputs explicitly. This closes an edge case where zero-length copies could cause downstream logic errors.

  2. data_len > sizeof(secure_storage[storage_count].data): This is the critical improvement. Instead of comparing against the magic number 256, the check now uses sizeof() to query the actual compile-time size of the destination buffer. This means:
    - If the struct is ever refactored and data changes size, the check automatically stays correct.
    - There is no gap between what the check allows and what the buffer can hold.
    - The bounds check is structurally coupled to the allocation it protects.

This is the canonical safe pattern for bounds-checking before memcpy in C.

Before vs. After

Before After
Check data_len > 256 data_len == 0 \|\| data_len > sizeof(...)
Zero-length rejected? No Yes
Tied to actual buffer size? No (magic number) Yes (sizeof)
Safe if struct is refactored? No Yes

Key Takeaways

  • data_len > 256 is not a safe bounds check if the actual destination buffer (secure_storage[storage_count].data) is not guaranteed to be exactly 256 bytes — use sizeof() instead.
  • ECALL parameters in SGX enclaves must be treated as untrusted input, even if the enclave itself is trusted; the data crossing the boundary is not.
  • Magic numbers in security-critical checks are a code smell: if the buffer size ever changes, the hardcoded check silently becomes wrong.
  • Zero-length inputs should be explicitly rejected in memcpy contexts to prevent logic errors downstream.
  • Lines 95 and 115 in enclave.c use similar patterns and should be reviewed for the same class of vulnerability.

How Orbis AppSec Detected This

  • Source: The data_len parameter of ecall_store_data — supplied by untrusted application code calling into the SGX enclave via the ECALL interface.
  • Sink: The memcpy call in backend/sgx/enclave/enclave.c:78 that copies data_len bytes into secure_storage[storage_count].data without validating against the actual buffer size.
  • Missing control: The existing check (data_len > 256) used a hardcoded magic number rather than sizeof(secure_storage[storage_count].data), creating a gap between the allowed length and the actual buffer capacity.
  • CWE: CWE-120 — Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
  • Fix: The condition was updated to data_len == 0 || data_len > sizeof(secure_storage[storage_count].data), structurally tying the bounds check to the actual destination buffer size.

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

Buffer overflows from unchecked memcpy calls are one of the oldest vulnerability classes in C programming — and one of the most dangerous when they occur inside a trusted execution environment like an Intel SGX enclave. The root cause here wasn't a complex algorithmic flaw; it was a single hardcoded magic number (256) that had no structural relationship to the actual destination buffer size.

The fix is equally simple: replace the magic number with sizeof(secure_storage[storage_count].data). This one-line change ensures the bounds check is always accurate, regardless of how the underlying struct evolves over time.

For developers writing C code — especially code that runs inside security-sensitive contexts like SGX enclaves — the lesson is clear: always tie your bounds checks to the actual allocation, never to a constant you think is right.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #4908

Related Articles

critical

How buffer overflow happens in C++ and how to fix it

A critical buffer overflow in `create_hex_string()` within `hmlangw.cpp` let an unconditional 16-iteration loop write past the bounds of a 100-byte `hex` buffer using unchecked `sprintf` calls. The fix replaces `sprintf` with `snprintf` and caps the loop iterations based on the actual destination buffer size, closing off a memory corruption path reachable from serial or network input.

high

How insecure-use-string-copy-fn happens in C and how to fix it

A high-severity vulnerability was identified in `plugin/bin/install.c` where `strcpy()` and `strncpy()` were used to handle path strings without proper bounds checking or guaranteed null-termination. The fix replaces `strcpy()` with direct character assignment and `strncpy()` with `snprintf()`, eliminating both buffer overflow and missing null-terminator risks in the plugin installation workflow.

critical

How Buffer Overflow via strcpy() Happens in C++ XML Parsers and How to Fix It

A critical buffer overflow vulnerability was discovered in `buildroot-external/package/libxmlparser/xmlParser.cpp`, where the `toXMLString` function used `_tcscpy()` to write XML escape sequences into a destination buffer without any bounds checking. An attacker supplying a crafted XML document could overflow the buffer and potentially execute arbitrary code. The fix replaces all five unsafe `_tcscpy()` calls with `memcpy()` calls that copy only the exact number of bytes required for each escape

high

How insecure string copy functions happen in C and how to fix it

A high-severity buffer overflow vulnerability was discovered in `tools/claude-vscode-wrapper.c`, where an unbounded `strcpy()` call copied a file path into a fixed-size `MAX_PATH` buffer without any size validation. The fix replaces `strcpy()` with `snprintf()` and swaps `malloc()` for `calloc()`, ensuring both string operations and memory allocation are bounds-safe and zero-initialized.

critical

How Heap Buffer Overflows Happen in C++ ZIP Extraction and How to Fix Them

A critical heap buffer overflow vulnerability was discovered in `TKLiveSync/unzip.cpp`, where ZIP archive entry names were copied into a `PATH_MAX`-sized heap buffer using `strcpy()` without any length validation. Since the ZIP specification allows entry names up to 65,535 bytes — far exceeding typical `PATH_MAX` values of 1,024 to 4,096 bytes — a crafted archive could overflow the buffer and corrupt heap memory. The fix replaces the unsafe `strcpy`/`dirname` pattern with `std::string` operation

medium

How Integer Overflow happens in C++ image processing and how to fix it

A signed integer overflow in OpenCV's `bilateralFilter.cpp` allowed the buffer size calculation `cal_width * cal_height * cn` to wrap around to a small or negative value, causing `padding.resize()` to allocate far less memory than needed. Subsequent `memcpy` operations would then write beyond the allocated buffer, creating a heap corruption primitive. The fix is a single targeted cast to `size_t` that promotes the multiplication to unsigned 64-bit arithmetic before any overflow can occur.