[ARM] 메모리 태그 확장(Memory Tag Extension)
Memory Tag Extension. 이하 MTE는 Arm v9에서 새로이 도입된 보안 관련 하드웨어 수준 기능이다.
안드로이드 환경과 연관이 매우 깊다.
사실 안드로이드 환경에서만 진지하게 접근하는 것 같다. 아마 일반적인 임베디드 환경들은 저런것도 낭비라고 생각할 것이다.
안드로이드와 보안 문제
알 사람은 알겠지만, 모바일 기기에서는 전력 같은 문제 때문에 대부분 ARM 계열 프로세서를 사용한다. 대부분의 안드로이드 기기들도 퀄컴 같은 ARM 프로세서를 적용한다.
또 알 사람은 알겠지만, 안드로이드는 보안 문제가 굉장히 많은 편이 속한다.
게다가 그 문제의 상당수는 취약한 메모리 관리에 기인한다.
메모리 관련 주요 취약점의 원인은 아래 2가지가 많았다.
-
Use After Free - 해제된 메모리를 재사용
-
Buffer Overflow - 버퍼 오버플로를 통한 경계 침범
1번은 해제된 메모리를 들고 있다가, 나중에 그 메모리 위치에 다른 데이터가 들어왔을 때 조작이 가능하다는 취약점을 유도한다. 이를 시간적 안전성(Temporal safety)이 파괴된다고 말한다.
2번은 현재 점유하고 있는 메모리 위치를 넘어서서 다른 데이터를 마음대로 조작할 수 있다는 취약점을 유도한다. 이를 공간적 안전성(Spatial safety)이 파괴된다고 말한다.
이런 취약점이 사방에서 돌출된 이유는 C/C++을 그냥 그대로 사용해서 Android를 작성했기 때문도 있었다.
그래서 구글에서는 Android 자체를 Rust로 재작성하려는 시도를 계속 하고 있다. 하지만 MTE를 사용하면 하드웨어 수준 지원으로 간결하게 해결할 수 있기 때문에 눈여겨보고 있는 것 같다.
Memory Tag Extension
ARM은 이를 Tag라는 추가 데이터를 삽입해서 보안 문제를 최소화하고자 했다.
첫째로, 메모리를 할당하면 해당 메모리의 최상위 4바이트에 태그 정보를 저장한다.
태그 정보에는 해당 메모리 시퀀스의 크기가 얼마인지 정도가 들어간다. 그리고 그걸 통해서 태그 정보에 기입된 크기 이상으로 메모리 참조를 시도하면 오류를 발생시키는 것이다.
이 기법은 버퍼 오버플로를 방지한다.
둘째로, free를 통해 메모리를 해제하면 태그 정보를 초기화한다.
메모리 해제 이후에 다시 기존 포인터로 접근을 시도하면 포인터의 태그 정보와 메모리 위치의 태그 정보가 일치하지 않기 때문에 오류를 발생시킨다.
이 기법은 Use After Free 문제를 방지한다.
인스트럭션 수준 지원
MTE를 달성하기 위해 추가된 ARM 인스트럭션은 다음과 같다.
어차피 우리가 직접 어셈블리를 작성하는건 아니니까, 잘 몰라도 되긴 한다.
- IRG: 태그값을 랜덤으로 할당한다.
https://developer.arm.com/documentation/ddi0602/2024-03/Base-Instructions/IRG--Insert-Random-Tag- - STG: 할당한 태그값을 메모리로 가져온다. (store)
https://developer.arm.com/documentation/ddi0602/2024-03/Base-Instructions/STG--Store-Allocation-Tag- - LDG: 메모리에서 할당된 태그값을 가져온다. (load)
https://developer.arm.com/documentation/ddi0602/2024-03/Base-Instructions/LDG--Load-Allocation-Tag-
안드로이드 애플리케이션에 적용하기
Android 12부터 지원된다.
이건 OS 수준의 문제이긴 하지만, 각각의 앱 수준에서도 수동으로 on/off할 수 있는 기능을 제공한다.
매니페스트 파일인 AndroidManifest.xml을 수정해서 android:memtagMode라는 필드를 조정하면 명시적으로 활성화할 수 있다.
android에서 mte 모드는 크게 sync 모드와 async 모드로 제공된다. 둘다 메모리 침범이 발생하면 프로세스가 중단되는건 동일하다.
sync는 성능보다는 정확한 오류 보고에 주안점을 둔다. 디버깅이나 테스트를 할때 좋은 선택이다.
async는 오류 보고보다는 성능에 초점을 둔 모드다. 오류 보고는 잘 되지 않지만 빠르게 최적화된다. 프로덕션 빌드에는 이 옵션이 좋다.
참조
https://developer.android.com/reference/android/R.attr#memtagMode
단점
하드웨어 수준 지원이 필요하다. 그래서 하드웨어에서 MTE를 지원하지 않으면 말짱 도루묵이다.
아마 최근에 나온 퀄컴 같은 곳의 칩셋들은 지원을 할 것이다.
랜덤성이 부족할 수 있다. 무작위의 태그 정보를 넣어서 일치하지 않으면 튕겨버리는 수법인데, 태그 사이즈가 4바이트 정도밖에 되지 않는다. 제대로 노리고 조진다면 어떻게 걸릴 수도 있다.
추가 메모리와 연산이 들어가는 것이다보니, 하지 않을때보다는 미세한 성능 낭비가 존재할 수 있다. 물론 이게 크리티컬한 수준이 되기는 쉽지 않을 것이라고 본다.
참조
https://velog.io/@pensieveview/MTE-Memory-Tagging-Extension-%EB%A9%94%EB%AA%A8%EB%A6%AC%ED%83%9C%EA%B9%85
https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/enhancing-memory-safety
https://source.android.com/docs/security/test/memory-safety/arm-mte