Affected Versions
| Affected | First-party SGX enclave code with ecall_store_data/ecall_retrieve_data functions using unbounded memcpy |
| Fixed in | Unreleased; fix available in proposed PR |
| Ecosystem | N/A (first-party C code for Intel SGX) |
| CVE / GHSA | not assigned |
| CWE | CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer |
The Vulnerability Explained
Intel SGX enclaves promise that even a compromised operating system cannot inspect or tamper with protected memory. This guarantee collapses when the enclave's own code contains memory safety bugs.
The ecall_store_data function receives untrusted data_len from the host application and copies that many bytes into secure_storage[index].data—a fixed 256-byte buffer. While the code checks data_len against some limit, the actual memcpy at line 84 trusts this value without secondary enforcement:
// Vulnerable pattern in ecall_store_data
memcpy(secure_storage[index].data, data, data_len);
The companion function ecall_retrieve_data mirrors this flaw on the output path. It copies secure_storage[index].length bytes into the caller-supplied data buffer without knowing if that buffer can hold the data:
// Vulnerable pattern in ecall_retrieve_data (before fix)
memcpy(data, secure_storage[index].data, secure_storage[index].length);
An attacker who compromises the host application can manipulate data_len during storage operations, or craft a stored entry with an inflated length field, then trigger retrieval into an undersized buffer. The result is heap corruption inside the trusted execution environment—precisely the scenario SGX was designed to prevent.
Real-world impact: A malicious cloud provider or compromised hypervisor could overflow secure_storage to overwrite adjacent enclave data structures, potentially altering attestation quotes or extracting cryptographic keys that should remain sealed.
The Fix
The patch introduces explicit contract enforcement through a new max_len parameter and runtime validation:
// Fixed ecall_retrieve_data signature and validation
sgx_status_t ecall_retrieve_data(
uint32_t index,
uint8_t* data,
uint32_t max_len, // NEW: caller declares buffer capacity
uint32_t* data_len
) {
if (index >= storage_count) {
return SGX_ERROR_INVALID_PARAMETER;
}
// NEW: explicit bounds check before any copy
if (secure_storage[index].length > max_len) {
return SGX_ERROR_INVALID_PARAMETER;
}
memcpy(data, secure_storage[index].data, secure_storage[index].length);
*data_len = secure_storage[index].length;
// ...
}
This change transforms an implicit assumption—that callers never provide undersized buffers—into an explicit, enforced contract. The max_len parameter forces the caller to declare intent, and the enclave validates against that declaration before any memory operation.
Notably, the fix addresses the output path (ecall_retrieve_data) where the caller's buffer size is externally determined and thus most likely to be mismatched. The input path's validation remains dependent on caller-side checks, reflecting the asymmetric trust model where enclaves must distrust all host-provided sizes.
Key Takeaways
-
SGX enclaves are not magically memory-safe: The trusted boundary protects against external observation, not internal bugs. Every
memcpyinside an enclave requires the same scrutiny as any other C code. -
Output buffer sizing is the caller's responsibility, but the enclave's duty to enforce: When an enclave writes to caller-allocated memory, it must accept and validate a capacity declaration. Implicit assumptions about buffer sizes fail across trust boundaries.
-
The
data_lenparameter inecall_store_dataremains single-point-of-failure: The fix does not add redundant bounds checking on the input path. Defense in depth would validatedata_lenagainstsizeof(secure_storage[0].data)even when callers are expected to check first. -
SGX status codes can signal policy violations: The fix returns
SGX_ERROR_INVALID_PARAMETERfor size violations, using the existing error taxonomy rather than inventing new codes. This preserves compatibility with existing host-side error handling.
How Orbis AppSec Detected This
Source: The data_len parameter in ecall_store_data and secure_storage[index].length field in ecall_retrieve_data, both controllable by the untrusted host application through the SGX edge interface.
Sink: memcpy() calls copying into secure_storage[index].data (256-byte fixed buffer) and into caller-supplied data output buffer without size validation.
Missing control: No comparison of source length against destination buffer capacity before memory copy operations; no max_len parameter to declare output buffer bounds.
CWE: CWE-119 — Improper Restriction of Operations within the Bounds of a Memory Buffer
Fix: Added max_len parameter to ecall_retrieve_data with explicit validation that secure_storage[index].length <= max_len before memcpy.
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
This vulnerability demonstrates that trusted execution environments inherit all the memory safety risks of their implementation language. The SGX enclave's secure_storage mechanism—designed to protect sensitive data—became an attack surface when memcpy operations trusted externally-influenced length values. The fix enforces explicit contracts at the trust boundary: callers must declare buffer capacities, and enclaves must validate before copying. For developers building SGX applications, every edge call represents a potential decompression of the trusted computing base—treat each one with the defensive coding practices that the surrounding infrastructure cannot provide.