Milestone 3
Milestone Status
This milestone is delivered. All deliverables are implemented, validated on both RISC-V and Arm, and submitted upstream. The patchsets are under review.
Background
ASLR makes memory-corruption attacks more difficult by varying where executable code is loaded. Compiler-instrumented stack canaries place a runtime guard in selected stack frames and detect modification before a function returns.
Both ASLR and stack canaries are already supported upstream for OP-TEE core and trusted applications, however, there is a lack of RISC-V CI coverage proving that randomization and stack-smashing detection work at runtime.
Milestone Description
Milestone 3 adds automated validation for the RISC-V ASLR and compiler-instrumented stack-canary features that are already present in OP-TEE.
Milestone Update
The ASLR and stack-canary validation work is complete and submitted upstream. Five patchsets were posted on Oct 1, 2026 and a sixth, covering the LLVM/Clang build coverage, on Oct 4, 2026. All are under review, and the review comments received so far have been addressed.
The work splits along the same lines as Milestone 7: each feature is an OP-TEE core pull request that adds a command to the invoke_tests pseudo TA, paired with an optee_test pull request that adds the xtest case driving it. Two further core patchsets stand alongside them: a prerequisite that makes the pseudo TA usable on RISC-V at all, and the Clang build coverage. The mapping offset and the stack guard are only visible inside the core, so the checks that need them live in a pseudo TA and return status flags only, never addresses.
PR #8066 makes the invoke_tests pseudo TA build and run on RISC-V. It implements cache_operation(), without which the pseudo TA cannot link, and enables the embedded tests by default on the QEMU rv64 virt platform.
PR #8067 adds a pseudo TA command that reports whether core ASLR was applied and verifies the mapping is coherent, and exports CFG_TA_ASLR to the TA dev kit so a test trusted application can report its own state. Selecting ASLR is not sufficient to activate it: randomization only happens when the boot seed is non-zero, and the seed is best effort, so a build can have the feature selected and still be mapped at its link address.
PR #8068 adds a pseudo TA command that reports the state of the stack protector and corrupts a canary to confirm detection fires. Because the core panics unconditionally on detection, which is the correct production behaviour, the patchset also adds a test hook to __stack_chk_fail() that lets a test take control before the panic and return to a good stack frame. The hook is compiled only with CFG_TEE_CORE_EMBED_INTERNAL_TESTS=y; the production path is unchanged.
PR #850 adds regression_1047, with sub-cases Core ASLR and TA ASLR. The trusted-application sub-case opens a fresh os_test session eight times and requires more than one distinct load address and a constant distance between the code and data addresses, which is what distinguishes a relocated image from a bad read. An earlier page-alignment check was dropped on review, as it assumed a granularity the randomizer does not promise.
PR #851 adds regression_1048, with sub-cases Core stack canaries and TA stack canaries. The expected behaviour differs between the two: a trusted application is meant to die on detection, so that sub-case triggers a real stack overflow and requires the trusted application to be reported dead with an error originating in the TEE.
PR #8081 adds a Clang entry to the RISC-V build matrix, which previously built virt only with GCC. The default virt configuration already selects core and trusted-application ASLR together with the STRONG stack-protector level, so the single entry exercises both features under Clang alongside the existing GCC coverage. It was split out of PR #8067 during review, being useful on its own and not specific to ASLR testing.
Both test cases skip automatically when the pseudo TA is absent or the feature is configured out, and neither is architecture specific.
The two optee_test pull requests report a CI failure until the core pull requests merge. optee_test is built against optee_os master, where the new pseudo TA command identifiers do not yet exist. The build guard that allowed them to compile standalone was removed at the maintainers' request, the stated plan being to merge the optee_os dependency first.
Validation
regression_1047 and regression_1048 pass on the QEMU RISC-V runtime-test infrastructure established by Milestone 2, with all four sub-cases reporting OK and no panics. The trusted-application sub-case reports eight distinct load addresses in eight loads.
Both cases were also run on Arm under QEMUv8, where all four sub-cases report OK. The full regression suite was additionally run with SPMC_AT_EL=2, using Hafnium as the S-EL2 secure partition manager: 43508 subtests, none failed.
The core changes build clean with -Werror for RISC-V (virt, sifive, cva6, with ASLR disabled and with the ALL and STRONG stack-protector levels, under both GCC and Clang) and for Arm (vexpress-qemu_armv8a and vexpress-qemu_virt, including with the pager enabled, which is the configuration where a core virtual address has no fixed relation to its physical address, and with CFG_FTRACE_SUPPORT=y).
Test Instructions
All deliverables are pushed to the RISE optee_os rp022-m3-aslr-stack-canaries and RISE optee_test rp022-m3-aslr-stack-canaries branches, and can be tested via xtest under the buildroot rp022-m3-aslr-stack-canaries branch.
# Fetch buildroot code
$ git clone https://gitlab.com/riseproject/riscv-optee/buildroot.git -b rp022-m3-aslr-stack-canaries
# Build the default config
# Use 'qemu_riscv64_virt_optee_llvm_defconfig' for Clang or 'qemu_riscv64_virt_optee_defconfig' for GCC
$ cd buildroot
$ make qemu_riscv64_virt_optee_llvm_defconfig
# Build all components
# Both defconfigs select core and trusted-application ASLR together with
# the STRONG stack-protector level, so no extra flags are needed
$ make -j$(nproc)
# Start QEMU
# 'make' regenerates start-qemu.sh with a non-vector CPU; this buildroot's
# kernel needs the vector extension even though OP-TEE itself does not
$ sed -i 's/-cpu rv64,zkr=on /-cpu rv64,zkr=on,v=true,vlen=128,zvkned=on,zvkb=on /' \
output/images/start-qemu.sh
$ ./output/images/start-qemu.sh
# Open a console and telnet to launch the kernel
$ telnet localhost 64320
# Run the relevant xtest after kernel login to verify ASLR and stack canaries
$ xtest 1047 1048
# Or just run all xtest
$ xtest
Both test cases pass on the QEMU RISC-V runtime-test infrastructure, with all four sub-cases reporting OK and no failures:
| Test case | Sub-case | Result |
|---|---|---|
regression_1047 — Test ASLR | Core ASLR | OK |
| TA ASLR | OK | |
regression_1048 — Test stack canaries | Core stack canaries | OK |
| TA stack canaries | OK |
| Count | Failed | |
|---|---|---|
| Subtests | 42 | 0 |
| Test cases | 2 | 0 |
The core sub-cases confirm that the core was relocated by ASLR and that a deliberately corrupted canary was detected. The trusted-application ASLR sub-case observed eight distinct load addresses in eight loads.
Full output:
# xtest 1047 1048
Test ID: 1047
Test ID: 1048
Run test suite with level=0
TEE test application started over default TEE instance
######################################################
#
# regression
#
######################################################
* regression_1047 Test ASLR
o regression_1047.1 Core ASLR
- 1047 - core relocated by ASLR
regression_1047.1 OK
o regression_1047.2 TA ASLR
- 1047 - 8 distinct TA load addresses in 8 loads
regression_1047.2 OK
regression_1047 OK
* regression_1048 Test stack canaries
o regression_1048.1 Core stack canaries
- 1048 - corrupted canary detected
regression_1048.1 OK
o regression_1048.2 TA stack canaries
regression_1048.2 OK
regression_1048 OK
+-----------------------------------------------------
Result of testsuite regression filtered by "1047":
Result of testsuite regression filtered by "1048":
regression_1047 OK
regression_1048 OK
+-----------------------------------------------------
42 subtests of which 0 failed
2 test cases of which 0 failed
112 test cases were skipped
TEE test application done!
Upstream Submissions
The following OP-TEE upstream submissions relate to this milestone:
| Date Submitted | Submission | Pull Request | Patchset Status |
|---|---|---|---|
| Oct 1, 2026 | Run the embedded tests on QEMU rv64 virt (core) | PR #8066 | Under Review |
| Oct 1, 2026 | Verify ASLR at runtime (core) | PR #8067 | Under Review |
| Oct 1, 2026 | Verify stack canary detection at runtime (core) | PR #8068 | Under Review |
| Oct 1, 2026 | ASLR xtest (regression 1047) | PR #850 | Under Review |
| Oct 1, 2026 | Stack canary xtest (regression 1048) | PR #851 | Under Review |
| Oct 4, 2026 | Build RISC-V with Clang (CI) | PR #8081 | Under Review |
Requirements
- Add
optee_testcoverage that verifies ASLR randomization in RISC-V OP-TEE core. - Add
optee_testcoverage that verifies ASLR randomization for trusted applications. - Add
optee_testcoverage that verifies compiler-instrumented stack canaries in RISC-V OP-TEE core. - Add
optee_testcoverage that verifies compiler-instrumented stack canaries in trusted applications. - Ensure the tests can run in the QEMU RISC-V runtime-test infrastructure established by Milestone 2.
Deliverables
ASLR
- OP-TEE core ASLR tests.
- Trusted-application ASLR tests.
- CI integration for the new RISC-V ASLR validation coverage.
- Enable ASLR for OP-TEE core and Trusted Applications for LLVM/Clang
- Validate ASLR for OP-TEE core and trusted applications with both compiler families.
Stack Canaries
- OP-TEE core stack-canary tests.
- Trusted-application stack-canary tests.
- CI integration for the new RISC-V stack-canary validation coverage.
- Enable stack canaries for OP-TEE core and Trusted Applications for LLVM/Clang
- Validate stack canaries for OP-TEE core and trusted applications with both compiler families.