Skip to content

feat(health_monitor): implement ARM MTE memory provider - #630

Draft
SebStefenel wants to merge 3 commits into
eclipse-score:mainfrom
SebStefenel:feat/arm-mte-memory-provider
Draft

feat(health_monitor): implement ARM MTE memory provider#630
SebStefenel wants to merge 3 commits into
eclipse-score:mainfrom
SebStefenel:feat/arm-mte-memory-provider

Conversation

@SebStefenel

@SebStefenel SebStefenel commented Sep 13, 2026

Copy link
Copy Markdown

Summary

Implements the ARM MTE memory provider requested in #119: ProtectedMemoryAllocator allocates memory regions protected by the ARM Memory Tagging Extension. The provider is gated behind the new //config:enable_arm_mte Bazel flag (default: off) and the mte Cargo feature, so it can be enabled once the target hardware and OS support it.

Behavior by configuration:

  • Flag off (default): regions are plain, zero-initialized, 16-byte aligned memory served by the Rust allocator (portable across Linux and QNX).
  • Flag on, aarch64 Linux: regions are mapped with mmap(PROT_MTE), MTE support is detected at runtime (getauxval(AT_HWCAP2)), synchronous tag checking is enabled per thread (prctl(PR_SET_TAGGED_ADDR_CTRL)), and a random non-zero tag is assigned to every 16-byte granule.
  • Flag on, any other target, or a CPU/kernel without MTE: the provider logs an error and degrades to plain memory.

Degrading instead of failing

Allocation never fails because MTE is unavailable. The alternative -- returning an error -- would make the flag unusable on the x86_64 hosts that run the unit tests and the sanitizer builds, and would turn a capability mismatch into a startup failure on targets that are otherwise fine.

Degrading is deliberately not silent, so a caller that must not run unprotected can detect it:

  • ProtectedMemoryAllocator::is_protection_active() reports whether the platform provides protection.
  • ProtectedMemoryRegion::is_protected() reports whether that specific region is hardware-tagged.
  • Every degraded allocation logs an error.

Happy to switch to a hard failure when the flag is explicitly enabled if that matches the safety concept better.

Implementation notes

  • The core::arch::aarch64::__arm_mte_* intrinsics are nightly-only (stdarch_aarch64_mte, Tracking Issue for AArch64 MTE memory tagging intrinsics rust-lang/rust#129010), so irg and stg are emitted as inline assembly from functions carrying #[target_feature(enable = "mte")]. This keeps the backend buildable with the Ferrocene toolchain.
  • PR_SET_TAGGED_ADDR_CTRL is 55 (56 reads the setting back), PR_TAGGED_ADDR_ENABLE is bit 0, and the control word sets the tag inclusion mask. The kernel reads that field as the set of tags irg may generate, so leaving it zero would exclude all 16 tags and yield tag 0 only.
  • //score/health_monitor/src/rust:health_monitoring_lib_mte builds the MTE backend unconditionally for aarch64 Linux, and is skipped elsewhere. Without it no CI configuration compiles that code, since it is gated on both the feature and the target.
  • ProtectedMemoryAllocator remains a unit struct, so all existing construction sites (builders, tests) are unchanged.
  • Monitor builders keep receiving &ProtectedMemoryAllocator unchanged; moving monitor state into protected regions is intentionally left for a follow-up.
  • Known MTE limitations are documented in the module docs (16 tags, per-thread tag-check configuration).

Closes #119

Implement ARM Memory Tagging Extension (MTE) memory provider to protect
allocated memory regions via hardware tagging. Guarded behind the
//config:enable_arm_mte Bazel flag so users can enable it once the
target hardware and OS support MTE.

Closes eclipse-score#119

Signed-off-by: Sebastian Stefenel <stefenel.sebastian@gmail.com>
Fix the borrow checker error in the read/write boundary test, which broke
every Rust build, the Clippy job and the sanitizer jobs.

Replace the `core::arch::aarch64::__arm_mte_*` intrinsics by inline `irg`
and `stg` instructions. The intrinsics are nightly-only (stdarch_aarch64_mte),
so the backend could never have been compiled by the stable toolchain.

Correct the prctl definitions: PR_SET_TAGGED_ADDR_CTRL is 55 (56 queries the
setting), PR_TAGGED_ADDR_ENABLE is bit 0, and the tag inclusion mask has to be
set, otherwise `irg` is only allowed to generate tag 0.

Degrade to plain, unprotected memory instead of failing the allocation when
MTE is requested but unavailable, so x86_64, sanitizer and QNX builds keep
working with the feature enabled. `is_protection_active` and the new
`is_protected` report whether a region is hardware-protected, so the degraded
configuration stays detectable.

Build the MTE backend for aarch64 Linux so that it gets compile coverage, no
default configuration compiles it.

Sort the imports and the BUILD attributes as the formatter expects.

Signed-off-by: Sebastian Stefenel <stefenel.sebastian@gmail.com>
A pointer read straight out of the `irg` `asm!` block carries no provenance
of the mapping it points into, which the strict provenance model does not
allow to be dereferenced. Take only the tagged address from the block and
rebuild the pointer with `with_addr`, which keeps the provenance of the
mapping. The nightly `__arm_mte_create_random_tag` intrinsic preserves it the
same way.

Document that tags cover whole 16-byte granules, so an access up to 15 bytes
past the requested size still matches the tag of the region and is not
detected.

Document that querying `is_protection_active` enables tag checking for the
calling thread, which is a per-thread kernel setting.

Signed-off-by: Sebastian Stefenel <stefenel.sebastian@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Implement MTE memory provider

1 participant