MTE 是 ARMv9 架构推出的硬件级内存安全技术,通过为每 16 字节内存块 分配 4 位随机标签(指针同步嵌入匹配标签),在每次内存访问时硬件自动校验标签一致性。其核心价值在于高效拦截 缓冲区溢出释放后使用(UAF)野指针解引用 等关键漏洞(实测覆盖 90%+ 内存攻击),以近零性能损耗(<2%)实现崩溃防御异步审计,目前已在 Android 系统核心层、Linux 内核及 AWS 云服务器规模化部署,推动内存安全从被动修复转向主动预防。

本次实验,我们将依托MetaComputing即将推出的MetaComputing AI PC with Framework Laptop 13设备展开深入测试——该设备搭载此芯CP8180 Arm架构处理器,作为Framework模块化硬件生态中填补Arm架构空白的核心产品,它采用8颗Arm Cortex-A720核心+4颗Arm Cortex-A520核心的CPU设计,适配标准Framework Laptop13机身,预装Ubuntu 25.04 aarch64系统,其原生对Arm架构硬件安全特性的良好支持,为我们探索MTE技术的实际防护效能提供了理想的硬件载体与适配性极强的软件环境。

系统环境

开启MTE功能

  • MTE功能默认处于关闭状态,需要手动开启。

  • MTE功能开启步骤:

  1. 设备开机启动时按esc按键进入BIOS环境,如下图
  2. 选择MateComputing System Manager选择项进入,进入后如下图
  3. 选择SE Configuration进入MTE开关设置,把开关设置为Enabled。
  4. 设置完成后按F10保存,保存后重启即可生效

MTE功能探索

测试目标

  • 启用 MTE 同步检测模式

  • 分配带标签保护的内存页

  • 主动为指针打标并写入内存标签

  • 执行合法访问(应成功)

  • 构造标签错配的非法访问(应触发 SIGSEGV)

  • 捕获异常并判定为 MTE 同步错误(SEGV_MTESERR)

MTE功能测试

  • MTE功能检查

zcat /proc/config.gz | grep CONFIG_ARM64_MTE
CONFIG_ARM64_MTE=y
  • 查看GCC编译器版本:gcc -v 。若提示“未找到命令”,需先通过包管理器安装(例如 Ubuntu 下 sudo apt install gcc )。

$roma@roma-MC-FML13V04-Board ~> gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/aarch64-linux-gnu/14/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: aarch64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 14.2.0-19ubuntu2' --with-bugurl=file:///usr/share/doc/gcc-14/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2,rust --prefix=/usr --with-gcc-major-version-only --program-suffix=-14 --program-prefix=aarch64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-offload-targets=nvptx-none=/build/gcc-14-g1I132/gcc-14-14.2.0/debian/tmp-nvptx/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=aarch64-linux-gnu --host=aarch64-linux-gnu --target=aarch64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=4
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 14.2.0 (Ubuntu 14.2.0-19ubuntu2)
  • 准备测试代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <signal.h>
#include<string.h>

/* MTE-related macros (fallback definitions if not in system headers) */
#ifndef PR_SET_TAGGED_ADDR_CTRL
#define PR_SET_TAGGED_ADDR_CTRL 55
#define PR_GET_TAGGED_ADDR_CTRL 56
#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
#define PR_MTE_TCF_SHIFT 1
#define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
#define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
#define PR_MTE_TAG_SHIFT 3
#endif

#ifndef PROT_MTE
#define PROT_MTE 0x20
#endif

/* Signal handler for MTE faults */
void mte_sig_handler(int sig, siginfo_t *si, void *unused) {
    printf("\n[MTE TEST] ---> SIGSEGV Received!\n");
    printf("|_ Fault Address: %p\n", si->si_addr);
    printf("|_ Error Code: 0x%x\n", si->si_code);

    // MTE-specific error codes (Linux 5.10+)
    #ifdef SEGV_MTESERR
    if (si->si_code == SEGV_MTESERR) {
        printf("|_ MTE Sync Tag Check Failed!\n");
        printf("[TEST RESULT] MTE PROTECTION ACTIVE - TEST PASSED\n");
        exit(0);
    }
    #endif

    printf("[TEST RESULT] UNKNOWN ERROR - TEST FAILED\n");
    exit(1);
}

int main() {
    printf("\n===== ARM64 MTE FUNCTIONAL TEST =====\n");

    // Register signal handler
    struct sigaction sa;
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = mte_sig_handler;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGSEGV, &sa, NULL);

    // Verify hardware support
    printf("\n[PHASE 1] Hardware/Kernel Support Check\n");
    FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
    if (cpuinfo) {
        char line[256];
        int mte_found = 0;
        while (fgets(line, sizeof(line), cpuinfo)) {
            if (strstr(line, "mte") || strstr(line, "mte3")) {
                printf("|_ CPU Feature: %s", line);
                mte_found = 1;
            }
        }
        fclose(cpuinfo);
        if (!mte_found) {
            printf("[ERROR] MTE not supported in CPU features\n");
            return 1;
        }
    }
    printf("|_ Status: Hardware support verified\n");

    // Enable MTE
    printf("\n[PHASE 2] Enable MTE via prctl()\n");
    unsigned long mte_ctrl = PR_TAGGED_ADDR_ENABLE |
                            PR_MTE_TCF_SYNC |
                            (0xfffe << PR_MTE_TAG_SHIFT);

    if (prctl(PR_SET_TAGGED_ADDR_CTRL, mte_ctrl, 0, 0, 0)) {
        perror("|_ prctl(PR_SET_TAGGED_ADDR_CTRL) failed");
        printf("[ERROR] Kernel may lack CONFIG_ARM64_MTE support\n");
        return 1;
    }
    printf("|_ Status: MTE enabled (sync mode)\n");

    // Allocate MTE-protected memory
    printf("\n[PHASE 3] Memory Allocation with PROT_MTE\n");
    size_t page_size = getpagesize();
    void *ptr = mmap(NULL, page_size,
                    PROT_READ | PROT_WRITE | PROT_MTE,
                    MAP_PRIVATE | MAP_ANONYMOUS,
                    -1, 0);

    if (ptr == MAP_FAILED) {
        perror("|_ mmap() failed");
        return 1;
    }
    printf("|_ Allocated Address: %p\n", ptr);

    // Generate and apply memory tag
    printf("\n[PHASE 4] Apply Memory Tag\n");
    asm volatile(
        "irg %0, %0\n"   // Generate random tag
        : "+r"(ptr)
    );
    asm volatile(
        "stg %0, [%0]\n" // Store tag to memory
        :
        : "r"(ptr)
    );
    printf("|_ Tagged Pointer: %p\n", ptr);
    printf("|_ Tag Value: 0x%lx\n", (unsigned long)ptr >> 56);

    // Valid access test
    printf("\n[PHASE 5] Valid Access Test\n");
    *(int *)ptr = 0xDEADBEEF;
    printf("|_ Write Value: 0x%x\n", 0xDEADBEEF);
    printf("|_ Read Value: 0x%x\n", *(int *)ptr);
    printf("|_ Status: Valid access successful\n");

    // Invalid access test
    printf("\n[PHASE 6] Invalid Access Test\n");
    void *bad_ptr = (void *)((unsigned long)ptr ^ (1UL << 56)); // Flip tag bit
    printf("|_ Corrupted Pointer: %p\n", bad_ptr);
    printf("|_ Attempting access...\n");
    fflush(stdout);

    // This should trigger SIGSEGV
    *(int *)bad_ptr = 0xCAFEBABE;

    // Should never reach here if MTE works
    printf("[TEST RESULT] MTE FAILED TO TRIGGER!\n");
    return 1;
}
  • 编译测试

#
roma@roma-MC-FML13V04-Board ~> gcc -march=armv8.5-a+memtag MTE_TEST.c -o mte_test
roma@roma-MC-FML13V04-Board ~> ./mte_test

===== ARM64 MTE FUNCTIONAL TEST =====

[PHASE 1] Hardware/Kernel Support Check
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ CPU Feature: t svei8mm svebf16 i8mm bf16 dgh bti mte ecv afp mte3 wfxt
|_ Status: Hardware support verified

[PHASE 2] Enable MTE via prctl()
|_ Status: MTE enabled (sync mode)

[PHASE 3] Memory Allocation with PROT_MTE
|_ Allocated Address: 0xffffa0f80000

[PHASE 4] Apply Memory Tag
|_ Tagged Pointer: 0x900ffffa0f80000
|_ Tag Value: 0x9

[PHASE 5] Valid Access Test
|_ Write Value: 0xdeadbeef
|_ Read Value: 0xdeadbeef
|_ Status: Valid access successful

[PHASE 6] Invalid Access Test
|_ Corrupted Pointer: 0x800ffffa0f80000
|_ Attempting access...

[MTE TEST] ---> SIGSEGV Received!
|_ Fault Address: 0xffffa0f80000
|_ Error Code: 0x9
|_ MTE Sync Tag Check Failed!
[TEST RESULT] MTE PROTECTION ACTIVE - TEST PASSED

测试成功验证了硬件(CPU特性支持MTE)和内核功能,通过prctl()启用MTE同步模式后,分配了带PROT_MTE标志的内存(地址0xffffa0f80000),并应用标签(0x9);在有效访问测试中,读写操作正常(值0xdeadbeef匹配),而在无效访问测试中(使用损坏指针0x800ffffa0f80000),系统正确触发了SIGSEGV信号(错误代码0x9),表明MTE的同步标签检查机制有效拦截了非法内存操作,最终测试通过(MTE PROTECTION ACTIVE),证明MTE的内存安全保护功能已激活且运行可靠。

结语:让安全成为计算的默认属性

  • 本次实验充分证明,在具备 ARMv9 架构支持的设备上,MTE 已能以极低代价实现高效、可靠的内存访问控制。其成功运行意味着我们正从传统的“被动修复漏洞”模式,转向“主动预防攻击”的新范式。

  • 正如加密已成为网络通信的标配,内存安全也应当成为所有计算平台的基础能力。MTE 的出现,正是这一愿景的技术具象化。随着 ARM 生态持续扩张,尤其是 AI PC、边缘计算、自动驾驶等新兴领域的崛起,MTE 将不再是一项“可选项”,而将成为衡量系统可信性的核心指标之一。

拓展

MTE功能开启后可能的潜在影响

MTE功能为系统带来内存安全防护等增益的同时,会占用部分系统内存资源。开启该功能后,系统会预留出特定区域的内存用于支撑功能运行,这部分约2Gi的内存将暂不对外提供通用访问能力,还请您在使用过程中留意这一内存分配变化,合理规划系统资源的使用。

  • 功能开启前的可用内存

  • 功能开启后的可用内存

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐