memzero_explicit() 함수
메모리 영역을 명시적으로 0으로 초기화하는 함수로 민감한 데이터를 메모리에서 완전히 제거해야 할 때 사용한다.
보통 C/C++ ㅇ언어에서 보안 관련 프로그래밍을 할 때 사용한다. 암호화를 위한 키나 패스워드와 같은 민감한 정보를 메모리에서 확실하게 제거하기 위해서 사용된다.
일반적으로 memset()으로 메모리를 0으로 초기화하는 것이 가능하지만 컴파일러에 의한 최적화 과정에서 memset() 호출 코드를 제거할 수 있다. 이 경우에 제로화가 동작하지 않는다.
memset 대신 memzero_explicit() 함수를 사용하면 컴파일러에 의해 코드가 삭제 되지 않는다.
함수 원형
static inline void memzero_explicit(void *s, size_t count);
memzero_explicit 함수 사용 예시
- 커널 또는 사용자 공간의 암호화 라이브러리
- 로그인 시스템에서 비밀번호 처리 후
- TLS 세션 키 삭제 시
- 파일 암호화/복호화 작업 후
memzero_explicit() 함수는 Linux 커널의 include/linux/string.h 헤더 파일에 정의되어 있다.
함수는 static inline으로 정의되어 있어 컴파일 시점에 인라인으로 확장되어 함수 호출 오버헤드를 줄이고 최적화 방지 효과를 유지한다.
초기에는 memzero_explicit() 함수가 lib/string.c 파일에 정의되어 있었다. 그러나 이후 커널 버전에서 include/linux/string.h 헤더 파일로 이동되어 static inline 함수로 정의되었다.
static inline void memzero_explicit(void *s, size_t count)
{
memset(s, 0, count);
barrier_data(s);
}
barrier_data(s); 코드로 인해 컴파일러가 memset() 함수 호출을 최적화하여 제거하지 않도록 하는 역할을 한다.
barrir_data 는 매크로 함수로 정의되어 있으며, 코드는 다음과 같이 구현되어 있다.
#define barrier_data(ptr) \
__asm__ __volatile__ ("" : : "r"(ptr) : "memory")
해당 매크로는 아무런 연산을 하지 않는 빈 인라인 어셈블리로 보이지만 매우 중요한 역할을 수행한다.
- __asm__+ __volatile__
- __asm__은 인라인 어셈블리를 의미한다.
- __volatile__은 컴파일러가 이 코드를 절대로 제거하거나 재배치하지 않도록 강제한다.
- "r"(ptr)
- ptr을 레지스터에 넣으라고 명시한다. 이로 인해 컴파일러는 ptr이 실제로 참조되었음을 인식한다.
- "memory"
- 이는 메모리 클로버(memory clobber)라고 부르며, 컴파일러에게 이 어셈블리 코드는 메모리에 영향을 줄 수 있다고 알린다.
- 따라서 컴파일러는 memset() 이후에 메모리 상태가 바뀔수 있다고 간주하게 되어 memset() 호출을 제거하거나 무시하지 못한다.