MTE는 pointer와 memory의 번호표를 비교한다
allocator가 16-byte memory granule에 4-bit allocation tag를 붙이고 pointer 상위 bit에 logical tag를 넣는다. CPU가 load/store할 때 두 tag가 다르면 오류를 보고한다. 해제 후 memory tag를 바꾸면 오래된 pointer가 같은 주소를 가리켜도 tag mismatch로 잡힐 수 있다.
다른 tag granule까지 넘는 overflow를 발견할 수 있다.
free 후 retag된 memory에 옛 pointer가 접근하는 것을 잡을 수 있다.
tag가 4-bit라 우연히 같은 tag가 재사용될 가능성은 남는다.
CPU 지원만으로 application 검사가 자동 활성화되지 않는다.
주소 허용과 tag 검사는 서로 다른 제어다
| Register field | 역할 | 실무 해석 |
|---|---|---|
| TCR_EL1.TBI0 | EL0 주소 번역에서 top byte 무시 | tagged pointer를 주소로 사용할 전제다. |
| SCTLR_EL1.TCF0 | EL0 tag-check fault mode | NONE, SYNC, ASYNC, ASYMM 중 kernel이 선택한다. |
| GCR_EL1.Exclude | random tag 제외 mask | PR_MTE_TAG_MASK 정책에서 변환된다. |
| TFSRE0_EL1 | EL0 async fault pending | 정확한 fault instruction보다 발생 사실을 지연 보고한다. |
| PSTATE.TCO | tag check override | entry code와 kernel helper가 제한된 구간에서 검사를 제어한다. |
PR_SET_TAGGED_ADDR_CTRL이 process 정책을 설정한다
Userspace에서 kernel까지
prctl(PR_SET_TAGGED_ADDR_CTRL, flags)
→ arch_set_tagged_addr_ctrl(task, arg)
→ set_mte_ctrl(task, arg)
→ mode와 allowed tag mask 검증
→ task->thread.mte_ctrl 갱신
→ mte_update_sctlr_user(task)
→ SCTLR_EL1.TCF0 / GCR_EL1 반영Linux v6.18.37의 set_mte_ctrl()은 지원하지 않는 flag를 거부하고 CPU가 ASYMM을 지원하는지 확인한다.
PR_TAGGED_ADDR_ENABLE은 syscall ABI에서 tagged pointer를 허용하는 정책이고, PR_MTE_TCF_*는 tag mismatch 처리 정책이다. 둘을 같은 bit로 생각하면 안 된다.
Synchronous mode는 fault instruction을 정확히 가리킨다
tag mismatch가 발생한 load/store에서 즉시 Data Abort가 나고 ESR의 fault status가 tag check fault를 나타낸다. arm64 fault table은 do_tag_check_fault()를 선택하고 userspace에는 SIGSEGV와 SEGV_MTESERR를 전달한다.
Sync fault 경로
mismatched load/store
→ Data Abort to EL1
→ do_mem_abort
→ do_tag_check_fault
→ force_signal_inject(SIGSEGV, SEGV_MTESERR, FAR)
→ userspace signal handlerFAR가 정확하므로 디버깅에 유리하지만 모든 검사에서 즉시 exception을 처리해 비용이 커질 수 있다.
Asynchronous mode는 빠르지만 위치가 부정확하다
CPU가 mismatch를 TFSR에 기록하고 실행을 계속한 뒤 kernel entry·exit 같은 안전 지점에서 확인한다. mte_check_tfsr_el1()은 pending bit를 읽고 정리한다.
entry-common.c의 mte_check_tfsr_entry()와 mte_check_tfsr_exit()는 지연 fault가 task 경계를 넘어 유실되지 않게 확인한다. async report의 address가 실제 잘못된 instruction을 정확히 가리킨다고 가정하면 안 된다.
| Mode | Read mismatch | Write mismatch | 용도 |
|---|---|---|---|
| SYNC | 즉시 exception | 즉시 exception | 정확한 개발·디버그 |
| ASYNC | 지연 보고 | 지연 보고 | 낮은 비용의 production 탐지 |
| ASYMM | sync | async | CPU 지원 시 정확도·비용 절충 |
Task switch 때 process별 TCF0와 tag mask를 복원한다
__switch_to() 경로의 mte_thread_switch(next)는 outgoing async fault를 확인하고 incoming task의 mte_ctrl을 register에 반영한다. CPU register는 per-CPU지만 정책은 task별이므로 migration에서도 복원해야 한다.
- 이전 task의 TFSR write가 보이도록 필요한 동기화를 수행한다.
- pending async fault를 task flag로 보존한다.
- next task의 TCF0 mode를 SCTLR_EL1에 반영한다.
- allowed tag mask와 random 정책을 GCR_EL1에 반영한다.
- userspace 복귀 전에 pending signal을 전달한다.
Page에 allocation tag storage를 준비하는 경로
mte_sync_tags()는 PTE가 가리키는 page의 tag 초기화 상태를 동기화한다. tagged mapping을 만들었다고 physical page의 allocation tag가 자동으로 application 의도에 맞게 설정되는 것은 아니다.
allocator는 object를 반환할 때 logical/allocation tag를 맞추고, free할 때 retag해야 temporal bug 탐지 효과가 생긴다. kernel MTE와 userspace MTE는 fault policy와 allocator 경로가 다르므로 설정을 구분한다.
Linux v6.18.37 소스 지도
| 파일 | 심볼 | 책임 |
|---|---|---|
| arch/arm64/kernel/mte.c | set_mte_ctrl, mte_update_sctlr_user | process policy와 register 반영 |
| mte.c | mte_check_tfsr_el1, mte_thread_switch | async fault와 task switch |
| arch/arm64/mm/fault.c | do_tag_check_fault | sync fault를 SIGSEGV로 변환 |
| arch/arm64/kernel/entry-common.c | mte_check_tfsr_entry/exit | entry 경계의 지연 fault 확인 |
| arch/arm64/kernel/process.c | arch_set_tagged_addr_ctrl | prctl architecture hook |
| asm/mte.h | tag access helper | architecture별 inline operation |
Use-after-free를 직접 재현한다
검증 체크리스트
CPU: getauxval(AT_HWCAP2) & HWCAP2_MTE
Kernel: tagged address ABI와 MTE config
Process: PR_GET_TAGGED_ADDR_CTRL
Binary: allocator가 memory를 실제 retag하는지
Signal: si_code == SEGV_MTESERR 또는 SEGV_MTEAERRsync mode에서 먼저 재현해 정확한 stack을 얻고, async mode로 바꿔 성능과 탐지 지연을 비교한다. production에서 pointer나 memory 내용을 log할 때 tag와 secret 노출을 주의한다.
MTE가 보장하지 않는 것
- 같은 tag granule 내부의 작은 overflow는 tag가 같아 탐지하지 못할 수 있다.
- 4-bit tag 충돌 때문에 모든 use-after-free를 확정적으로 잡지는 않는다.
- integer로 pointer를 변형하거나 ABI 규칙을 어기면 false positive·우회가 생길 수 있다.
- MTE는 bounds checker, type safety, PAC·BTI·GCS를 대체하지 않는다.
근거 자료
- Local sourceLinux v6.18.37 commit
0c503cf3dde2 - Arm guideMemory Tagging Extension user guide
- ProtectionProviding protection for complex software
- Linux ABIMemory Tagging Extension