← All issues

[4] macOS sandbox profile symlink traversal

Severity: High | Component: WebKit auxiliary process sandbox initialization (macOS) | 69a8331

symlink traversal을 통한 sandbox profile 치환이 직접적으로 관찰 가능한 영향으로 드러나며, non-internal 빌드에서 datavault integrity check가 컴파일에서 제외된다는 점이 더해져 High로 평가되었습니다. /.nofollow prefix 추가와 USE(APPLE_INTERNAL_SDK) 게이트 제거는 diff에서 직접 확인되며, 신뢰도는 0.92입니다.

WebKit 프로세스가 sandbox profile 경로에서 symlink를 따라가 잘못된 sandbox profile을 로드할 가능성이 있었습니다. 이번 수정에서는 sandbox profile 디렉토리 경로 앞에 /.nofollow를 추가하고, datavault integrity check를 감싸고 있던 #if USE(APPLE_INTERNAL_SDK) 조건부 컴파일을 제거하였습니다.

Source/WebKit/Shared/mac/AuxiliaryProcessMac.mm

static String sandboxDirectory(WTF::AuxiliaryProcessType processType, const String& parentDirectory)
{
StringBuilder directory;
+ directory.append("/.nofollow"_s);
directory.append(parentDirectory);
switch (processType) {
...
static bool tryApplyCachedSandbox(const SandboxInfo& info)
{
-#if USE(APPLE_INTERNAL_SDK)
CString directoryPath = FileSystem::fileSystemRepresentation(info.directoryPath);
if (directoryPath.isNull())
return false;
if (rootless_check_datavault_flag(directoryPath.data(), processStorageClass(info.processType)))
return false;
-#endif
 
auto contents = fileContents(info.filePath);
if (!contents || contents->isEmpty())

이번 수정은 세 가지로 구성됩니다. 첫째, sandboxDirectory()가 sandbox profile 디렉토리 경로 앞에 /.nofollow를 추가하도록 변경되었습니다. 이를 통해 macOS 커널이 해당 경로에서 symlink 해석을 거부하도록 지시합니다. 둘째, datavault storage class 문자열을 반환하는 processStorageClass()가 더 이상 #if USE(APPLE_INTERNAL_SDK) 게이트로 제한되지 않습니다. 셋째, tryApplyCachedSandbox()rootless_check_datavault_flag() integrity check도 동일하게 게이트가 제거되어, 모든 빌드에서 datavault 검증이 실행됩니다.

Sandbox profile 경로 해석 과정에서의 symlink 추적 TOCTOU, non-internal 빌드에서 datavault integrity 검증 누락.

macOS에서 WebKit auxiliary 프로세스(WebContent, GPU, Networking)는 시작 시점에 sandbox profile을 적용합니다. 이 profile은 컴파일된 후 datavault로 보호된 디렉토리에 캐시됩니다. /.nofollow 경로 prefix는 macOS 커널 메커니즘으로, filesystem 레이어가 해당 경로에서 symlink를 해석하지 않도록 지시합니다. 경로 탐색 중 symlink가 발견되면 이를 따라가지 않고 해당 작업이 실패합니다. Datavault는 macOS SIP 관련 메커니즘으로, 디렉토리에 storage class가 태그되어 있으며 해당 com.apple.rootless.storage.<class> entitlement를 가진 프로세스만 쓰기가 가능합니다. rootless_check_datavault_flag()는 디렉토리가 기대하는 storage class에 속하는지 검증합니다.

수정 이전에는 WebKit auxiliary 프로세스가 캐시된 sandbox profile 디렉토리 경로를 해석할 때 symlink 추적을 차단하지 않았습니다. sandbox profile 디렉토리로 이어지는 경로 어딘가에 symlink를 배치할 수 있는 공격자라면, 프로세스가 다른 sandbox profile — 더 취약하거나 공격자가 직접 만든 profile — 을 로드하도록 유도할 수 있었습니다. 또한 sandbox 캐시 디렉토리를 검증하는 datavault integrity check가 #if USE(APPLE_INTERNAL_SDK) 게이트로 제한되어 있었습니다. 즉, non-internal(프로덕션) 빌드에서는 이 검증 자체가 실행되지 않아, datavault 소유권 확인 없이 임의의 캐시된 sandbox profile이 수용되는 상황이었습니다.

🔒

Explores the layered failure in sandbox profile validation and the implications of security checks that only exist in development builds

더 확인하려면 구독해 주세요

🔒

Multiple audit patterns identified for finding similar sandbox initialization gaps across WebKit platform code

더 확인하려면 구독해 주세요