UNIX 도메인 소켓에 어떻게 낭만을 느끼지 않을 수 있을까?
요약
DEFCON 34에서 발견된 iOS 데모 충돌을 추적한 결과, UNIX 도메인 소켓의 inode 번호가 두 번째 `fstat()` 호출에서 변경되는 커널 버그를 발견했습니다. 이 문제는 전역 카운터와 0 초기화 로직 때문에 발생하며, 기존 시스템 지원을 위해 Apple 전용 우회 처리가 필요합니다.
핵심 포인트
- UNIX 도메인 소켓의 inode 번호가 두 번째 fstat() 호출에서 변경되는 커널 버그 발견
- 원인은 전역 카운터와 0 초기화 로직에 의한 지연 할당 방식 때문
- 이 문제는 Mac OS X 및 BSD 계열 시스템에서도 유사하게 존재함
- iOS 앱 내 VM 구현의 무결성 검사 실패가 문제점을 드러냄
DEFCON 34에서 발생한 iOS 데모 충돌을 추적한 결과, 같은 UNIX 도메인 소켓의 inode 번호가 두 번째 fstat()
호출에서 바뀌는 커널 버그 를 발견함
원인은 0을 미초기화 값으로 쓰면서 첫 inode에도 0을 할당 하는 로직임. 전역 카운터의 후위 증가 연산 때문에 다음 조회에서 inode를 다시 할당함
데모의 VM은 UNIX 도메인 소켓 쌍으로 사용자 공간 TTY 를 구현하고 inode로 마스터/슬레이브를 구분했으며, inode 변경으로 무결성 검사가 실패함
같은 버그가 첫 Mac OS X의 XNU 123.5 와 4.3BSD-Tahoe에도 존재하며, 관련 로직의 역사는 1985년 12월 까지 거슬러 올라감
커널에서는 증가 연산 순서를 바꾸면 되지만, 기존 iOS 버전도 지원하려면 inode가 0일 때 fstat()
을 다시 호출 하는 Apple 전용 우회 처리를 고려해야 함
DEFCON 데모에서 시작된 조사
DEFCON 34의 iOS 기술 발표 Rage Against the Sandbox 에서 데모가 시작 직후 충돌 했지만, 다시 실행하자 정상 작동함
데모에는 성공률이 36%인 1-day 로컬 권한 상승(LPE) 익스플로잇 DarkSword 가 포함됐으며, 익스플로잇 자체는 무대에서 첫 시도에 성공함
코드 공개를 앞두고 프로젝트를 마무리하면서 충돌을 조사한 결과, iOS 기기를 재부팅한 뒤 첫 실행에서만 발생하고 두 번째 실행부터는 발생하지 않았음
이 재현 패턴 때문에 ASLR 같은 무작위성이나 멀티스레드 경쟁 조건보다는 다른 원인을 추적함
iOS 앱 안의 VM과 사용자 공간 TTY
프로젝트는 iOS 애플리케이션 안에서 SSH 서버를 실행하는 VM 임
iOS는 앱의 자식 프로세스 생성을 허용하지 않으므로, VM이 프로세스 생성 함수를 재정의함
실제 프로세스 대신 같은 프로세스 안에 자원과 메모리를 복제한 스레드를 만들어 다중 프로세스 동작을 구현함
VM은 논리적 코드 서명 우회 도 구현함
데모는 작업 제어와 TTY를 위해 다중 프로세스 동작이 필요한 SSH 연결을 통해 서명되지 않은 1-day 익스플로잇을 실행함
TTY 명세는 프로세스당 제어 터미널 1개 만 허용하므로, 하나의 iOS 앱 프로세스에서 여러 SSH 세션을 지원하려면 커널 TTY 구현에 의존할 수 없음
서로 연결된 UNIX 도메인 소켓 쌍 을 만들고 양쪽으로 들어오는 데이터를 전처리해 사용자 공간에서 TTY를 구현함
예를 들어 마스터가 Ctrl+C를 보내면 슬레이브가 SIGINT를 받도록 처리함
inode 변경이 무결성 검사를 깨뜨린 과정
SSH 서버는 임베디드 환경에서 널리 쓰이는 오픈소스 구현인 dropbear 이며, VM은 운영체제 함수를 후킹해 실행 흐름을 자체 구현으로 돌림
파일 디스크립터는 dup()
으로 복제될 수 있으므로, VM은 소켓 양 끝의 원래 inode 번호 를 저장해 TTY 마스터와 슬레이브를 구분함
SSH 연결 초기화 중 서버가 마스터를 통해 터미널 속성을 변경하면서 tty_for_file_locked()
에 진입했고, VERIFY(tt->t_sfd_ino == st.st_ino)
검사 가 실패해 VM이 패닉을 일으킴
처음에는 파일 디스크립터에 연결된 inode가 바뀔 이유가 없다고 보고 VM 구현의 메모리 손상을 의심함
디버깅 결과, 같은 소켓 끝에 대한 첫 번째와 두 번째 fstat()
반환 inode가 달랐음
커널의 0 초기화와 후위 증가 연산
/bsd/kern/uipc_usrreq.c
의 uipc_sense()
는 소켓 inode를 struct stat
의 st_ino
에 넣음
unp->unp_ino == 0
이면 아직 inode를 할당하지 않은 것으로 판단하고, 첫 stat 호출 시 전역 변수에서 값을 가져오는 지연 할당 방식임
문제의 할당문은 unp->unp_ino = unp_ino++
이며, 전역 변수 unp_ino
의 초기값도 0임
시스템에서 처음 이 경로로 inode를 할당받는 소켓에는 후위 증가 연산 때문에 0이 들어감
같은 소켓을 다시 조회하면 0을 미초기화 상태로 판단해 다른 inode를 할당함
++unp_ino
를 사용하면 첫 할당값이 1이 되어 이 문제를 피할 수 있음
보안 관점에서 크게 흥미로운 버그는 아니지만, 사용자 공간 프로그램을 깨뜨리는 커널 논리 오류 임
실제로 몇 개의 프로그램이 영향을 받는지, 왜 데모가 iPhone에서 UNIX 도메인 소켓에 처음 fstat()
을 호출한 프로세스였는지는 확인되지 않음
다른 시스템 서비스가 잘못된 소켓 inode를 보관하고 있을 가능성도 있음
커널 수정과 별개로 구버전 지원을 위해 inode가 0이면 fstat()
을 재호출하는 Apple 전용 검사 를 추가하는 방안을 고려함
Mac OS X에서 BSD까지 거슬러 올라간 버그
GitHub의 가장 오래된 XNU 코드인 XNU 123.5 에도 동일한 조건문과 후위 증가 연산이 존재함
이 버전은 2001년 3월 24일 Mac OS X 10.0 과 함께 출시됨
버그는 첫 Mac OS X부터 존재했으며, 현대 macOS와 iOS 전반에 이어져 온 문제임
2001년 XNU는 Mach 2.5와 4.4BSD 기반 Rhapsody 커널 의 후속임
Mach를 핵심으로 두고 그 위에 BSD 계층을 올린 구조여서 하이브리드 커널로 불림
Apple이 1997년 NeXT를 인수하면서 가져온 NeXTSTEP 커널을 개편한 계보임
1989년 처음 출시된 NeXTSTEP 커널은 Mach와 4.3BSD 기반이지만 소스가 비공개였으므로, 당시의 4.3BSD-Tahoe 코드로 추적을 이어감
4.3BSD-Tahoe에서는 별도 uipc_sense()
함수 대신 UNIX 도메인 소켓 요청을 처리하는 큰 switch문의 PRU_SENSE
분기 에 같은 로직이 있음
XNU 123.5와 사실상 동일한 로직이어서, 버그가 NeXT에서 Apple로 이어진 시기에도 그대로 남아 있었다고 볼 수 있음
1985년의 두 차례 변경
unix-history-repo의 1985년 12월 20일 커밋 18a9fea
까지 추적하면 현재의 inode 할당 로직으로 이어지는 변경을 확인할 수 있음
그 이전 코드는 st_ino
에 곧바로 unp_ino++
를 넣어 fstat()
호출 때마다 다른 inode 를 반환했음
소켓에 inode를 저장해 재사용하도록 바뀌었지만, 첫 할당값 0을 미초기화 상태와 구별하지 못하는 문제가 남음
그보다 앞선 1985년 5월 28일 커밋 628f1f5
이전에는 st_dev
와 st_ino
를 설정하는 코드조차 없어 두 필드가 0으로 반환됐음
해당 변경의 커밋 메시지는 “fake up inode numbers and dev for the naive ”였음
당시 개발자가 정확히 무엇을 뜻했는지는 알 수 없지만, 41년 뒤 이 필드에 의존한 개발자에게도 ‘순진하다’는 말처럼 읽히는 대목임
변경 이력으로 추정하면, 1985년 5월 무렵 사용자 공간 프로그램이 UNIX 소켓의 fstat()
결과를 필요로 했고, 같은 해 12월에는 같은 소켓의 inode가 일관되게 유지되도록 요구했을 수 있음
당시 Berkeley에서 실제로 어떤 일이 있었는지는 확인할 수 없음
UNIX 도메인 소켓의 inode가 실험적으로 구현된 작은 기능으로 남아 충분히 재검토되지 않았을 가능성이 있으며, 그 코드가 Berkeley에서 Cupertino를 거쳐 최신 iPhone까지 이어짐
데모를 위한 교훈
DEFCON 메인 무대에 오르기 전에 데모를 더 철저히 검증 해야 함
댓글과 토론
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기