Dirty COW(copy-on-write) 취약점
- 경쟁 조건 취약점의 사례임
- 2007년부터 리눅스 커널에 존재했으며 2016년에 발견되어서 공격 받았음, 숨겨져 있다가...
- 공유된 자원의 문제.. -> 이런건 항상 문제의 소지가 있음 공유된거면
- 안드로이드 포함해서 모든 리눅스 기반 운영체제에 영향을 미침
결과
- /etc/passwd와 같은 보호된 파일을 수정
- 취약점을 악용하여 루트 권한 획득
Virtual Memory
- 실제 피지컬 메모리에 있는 주소랑은 별도로 생각 가능
- 리눅스에서는 파일을 이렇게 매핑할 수도 있음. (메모리에다 쓴다 생각하는데 파일에다가 쓰는), 디바이스에 매핑하기도 함
그래서 메모리에 쓰면 거기에 뭐 /etc/passwd같은게 있어서 파일에 써질 수도 있음
매핑하면 파일에도 접근 권한이 있음 이 파일을 메모리에 접근 권한에 설정해야됨. 이런거 꼬이거나 이렇게 부작용 생기는ㄱ ㅓ다 고려해서 OS 만들어야한다.
fork: 쓰기 시 복사(COW, copy on write)
fork했을 때 메모리 관리 방법이 두가지 있음(완전복사, 쓰기 시 복사)
- 완전복사: 페이지테이블 똑같이 만들어서 다 복사함
- 쓰기 시 복사: 자식 프로세스는 부모의 메모리를 공유함. 자식 프로세스가 한 페이지에 쓰기 시작하면 운영체제는 새 프레임을 할당하여 쓰기가 발생한 페이지를 복사함.
쓰기 시 복사의 장점
- 프로세스 생성 시간 절약: 부모 프로세스의 페이지 테이블만 복사해서 자식 프로세스를 만드니까 프로세스 생성이 빠르고 fork후에 xec해도 프로세스 생성 과정에서 손해가 없다
- 메모리 절약: 부모와 자식 프로세스가 둘 다 읽기만 하는 페이지는 새로운 프레임을 할당할 필요가 없으므로 메모리가 절약된다. 코드페이지 같은 것.
mmap()을 이용한 메모리 매핑
mmap
- 파일이나 장치를 메모리에 매핑하는 시스템 호출
- 기본 매핑 유형은 프로세스의 가상 메모리 영역을 파일에 매핑하는 파일 지원 매핑
- 매핑된 영역에서 읽으면 파일을 읽음
첫 번째 인수 | 매핑된 메모리의 시작 주소 |
두 번째 인수 | 매핑된 메모리의 크기 |
세 번째 인수 | 메모리를 읽거나 쓸 수 있는지 여부 |
네 번째 인수 | 매핑에 대한 업데이트가 동일한 영역을 매핑하는 다른 프로세스에 표시되고 업데이트가 기본 파일로 전달되는 경우 |
다섯 번째 인수 | 매핑해야 하는 파일 |
여섯번째 인수 | 매핑이 시작되어야 하는 파일 내부 위치를 나타내는 오프셋 |
MAP_SHARED, MAP_PRIVATE 및 COopy On Write
MAP_SHARED: 매핑된 메모리는 두 프로세스 간의 공유 메모리처럼 작동
여러 프로세스가 동일한 파일을 메모리에 매핑할 때 파일을 다른 가상 메모리 주소에 매핑할 수 있지만 파일내용이 보관되는 물리적 주소는 동일하다.
MAP_PRIVATEL 파일이 호출 프로세스 전용 메모리에 매핑
- 메모리에 대한 변경 사항은 다른 프로세스에서 볼 수 없음
- 원래 메모리의 내용을 개인 메모리에 복사해야 함
- 프로세스가 메모리에 쓰기를 시도하면 OS는 물리적 메모리의 새로운 블록을 할당하고 마스터 복사본의 내용을 새 메모리로 복사
- 매핑된 가상 메모리는 이제 새로운 물리적 메모리를 가리킴
Copy On Write
서로 다른 프로세스의 가상 메모리가 동일한 내용을 가지고 있는 경우 동일한 물리적 메모리 페이지에 매핑할 수 있도록 하는 기술
fork() 시스템 호출을 상요하여 자식 프로세스를 만들 때
- OS는 페이지 항목이 동일한 물리적 메모리를 가리키도록 하여 자식 프로세스가 부모 프로세스의 메모리를 공유하도록 함
- 메모리를 읽기만 하는 경우 메모리 복사가 필요 없음
- 누군가가 메모리에 쓰려고 하면 예외가 발생하고 OS는 자식 프로세스에 새로운 물리적 메모리를 할당하고, 부모 프로세스에서 내용을 복사하고 각 프로세스의 페이지 테이블을 변경하여 자신의 개인 복사본을 가리키도록 함
복사된 메모리 폐기하기
madvise()
- addr에서 addr+length까지의 메모리에 대해 커널에 조언(advice) 또는 지시(direction)을 제공
- advice(3번째 인수): MADV_DONOTNEED: 더 이상 주소의 요청된 부분이 필요하지 않다고 커널에 알림, 커널은 요청된 주소의 자원을 해제하고 프로세스의 페이지 테이블은 원래 물리적 메모리를 다시 가리킴
읽기 전용 파일 매핑하기
일반적으로 읽기 전용 메모리에는 쓰기가 불가능
근데 파일이 MAP_PRIVATE를 사용해서 매핑된 경우 운영체제는 예외를 만들고 매핑된 메모리에 쓸 수 있도록 허용 (memcpy()와 같은 메모리 작업을 직접 사용하는 대신 다른 경로로 사용해야 함, write()시스템 호출로 쓸 수 있음)
Dirty COW 취약점
Copy-On-Write의 경우 세 가지 중요한 단계가 수행
- 매핑된 메모리의 복사본 만들기
- 가상 메모리가 새로 생성된 물리적 메모리를 가리키도록 페이지 테이블을 업데이트
- 메모리에 작성
이 단계들은 atomic하지 않음, 한번에 일어나는게 아니라서 중간에 이상한 액션이 들어갈 수 있다.
Dirty COW 취약점으로 이어지는 잠재적 경쟁 조건을 생서하는 다른스레드에 의해 중단이 가능해짐
예를들어 복사본 만든거에 쓰게 해야되는데 다른 테이블로 바꾼다거나 해서 카피해온 페이지가 아니라 엉뚱한데에다 쓰게 할 수도 있음. 이 과정에서 madvise로 변경하게 할 수도 있는것.(읽기 전용 파일이 수정될 수가 있다)