
Proof-of-concept for CVE-2026-33317, an out-of-bounds write in OP-TEE PKCS#11 TA, demonstrating Secure World heap corruption via a malformed attribute template.
This repository contains the Normal World proof of concept, reproduction notes, and captured logs for CVE-2026-33317 / GHSA-8cqw-mg7v-c9p9.
The official OP-TEE advisory describes missing validation in
entry_get_attribute_value() for PKCS11_CMD_GET_ATTRIBUTE_VALUE. The bug can
cause out-of-bounds reads from the PKCS#11 TA heap and, with a malformed
attribute template, writes beyond the temporary template buffer. This PoC
targets the out-of-bounds write case and demonstrates Secure World heap
corruption in the PKCS#11 TA.
CVE-2026-33317>= 3.13.04.11 and later8.7 HighCWE-125, CWE-787Use this only in a local lab or another environment where you are authorized to test OP-TEE.
The local working copy this README was prepared from was a flattened OP-TEE
QEMUv8 workspace. The .repo directory and all .git metadata files/directories
were removed, so that local archive is no longer usable with repo sync or
normal git history commands.
The GitHub repository intentionally excludes the bulky OP-TEE/QEMU source trees,
toolchains, and build outputs. Recreate those from qemu-v8-setup.md, or copy
the PoC files into an existing OP-TEE qemu_v8 build root, before running the
automated QEMU reproduction from a fresh clone.
Important top-level files:
The prepared local archive also had source/build directories such as optee_os,
optee_client, qemu, linux, trusted-firmware-a, u-boot, buildroot,
out-br, and toolchains; these are ignored for publication.
In the vulnerable optee_os tree, ta/pkcs11/src/object.c iterates over a
client-supplied serialized attribute template:
cur = (char *)template + sizeof(struct pkcs11_object_head);
end = cur + template->attrs_size;
...
data_ptr = cli_head.size ? cli_ref->data : NULL;
rc = get_attribute(obj->attributes, cli_head.id, data_ptr, &cli_head.size);
The loop does not prove that each attribute header and its data area are fully inside the allocated template. The PoC sends:
attrs_size = 8, exactly one pkcs11_attribute_head and no data bytes.attrs_count = 1.cli_head.id = CKA_LABEL.cli_head.size = 16, matching the created object's 16-byte label.That creates a 16-byte template allocation:
sizeof(pkcs11_object_head) + attrs_size = 8 + 8 = 16
cli_ref->data then points at template + 16, exactly one byte past the end of
the allocation. get_attribute() in ta/pkcs11/src/attributes.c sees that the
caller-provided size is large enough and copies the 16-byte label to that
out-of-bounds pointer, corrupting the PKCS#11 TA heap.
Prerequisites used by the prepared QEMUv8 workspace:
expectqemu_v8 workspace with build outputs, toolchains, and QEMU binary
laid out like the local archive described in qemu-v8-setup.mdBuild the PoC:
./build_poc.sh
Expected build result:
Built: out/bin/c01_poc
Run the automated QEMUv8 reproduction:
./run_c01.sh
The wrapper checks for these staged files before booting:
out/bin/bl1.binout/bin/Imageout/bin/rootfs.cpio.gzout/bin/c01_pocIf the build artifacts are missing, recreate/build the OP-TEE workspace first
and then rerun ./build_poc.sh.
The Normal World log should show the crafted request:
[+] TEEC session with PKCS#11 TA opened
[+] INIT_TOKEN rc=0x00000000 OK
[+] OPEN_SESSION rc=0x00000000, session_handle=0x00000001
[+] CREATE_OBJECT rc=0x00000000, obj_handle=0x00000001
[+] Object has CKA_LABEL = "AAAAAAAAAAAAAAAA" (16 bytes)
[+] Sending malicious C_GetAttributeValue (attrs_size=8, cli_head.size=16)...
[+] GET_ATTRIBUTE_VALUE[0] rc=0xffffffff
The Secure World log should contain the allocator assertion and TA panic:
E/TA: assertion 'BH((char *) b - b->bh.bsize)->prevfree == 0' failed at lib/libutils/isoc/bget.c:1022 in brel()
E/TC:? 0 TA panicked with code 0xffff0000
E/LD: Status of TA fd02c9da-306c-48c7-a49c-bbd827ae86ee
Captured logs from a successful run are already present at:
out/bin/c01_nw.logout/bin/c01_sw.logc01_poc.c invokes the PKCS#11 TA UUID
fd02c9da-306c-48c7-a49c-bbd827ae86ee through libteec:
CKA_LABEL = "AAAAAAAAAAAAAAAA".CMD_GET_ATTRIBUTE_VALUE request with attrs_size = 8
and cli_head.size = 16.The first malicious request is enough to corrupt heap metadata. The TA then panics when the OP-TEE bget allocator detects the corrupted block metadata.
run_c01.sh shares out/bin into the guest over virtio-9p and writes logs
back to the same directory.out/bin should point
to artifacts inside that archive. The published GitHub repository only tracks
the captured out/bin/c01_*.log files.C-01-reproduction.md documents an earlier x86 ASAN harness approach. The
runnable PoC in this folder is the QEMUv8 TEEC PoC: c01_poc.c.| Path | Purpose |
|---|
c01_poc.c | AArch64 Normal World PoC using raw libteec calls |
build_poc.sh | Cross-compiles c01_poc.c into out/bin/c01_poc |
run_c01.sh | Boots QEMUv8 and runs the PoC through expect |
c01_check.exp | Automates guest login, virtio-9p mount, and PoC execution |
out/bin/c01_nw.log | Captured Normal World reproduction log |
out/bin/c01_sw.log | Captured Secure World log with the PKCS#11 TA panic |
reproduction-log.md | Full QEMUv8 reproduction notes |
qemu-v8-setup.md | OP-TEE QEMUv8 setup and baseline validation notes |
C-01-reproduction.md | Earlier ASAN harness notes; not the main runnable PoC in this folder |
AGENTS.md | Maintenance notes for future AI/code agents |