Documents finally get their own IP address space
Component: WebCore Loader / Local Network Access | 1b00bc4
Local Network Access는 document 자신의 address space와 fetch 대상의 address space를 비교합니다. 그래서 document가 어떻게 분류되는지가 모든 LNA 판단에서 입력의 절반을 차지하게 됩니다. PolicyContainer는 document 단위의 security state를 묶어 놓은 구조로, CSP와 referrer policy에 더해 이번부터 address space까지 포함합니다. 이 값들은 navigation 시점에 정확하게 도출되어야 하고, IPC를 거쳐 WebContent/Network process 경계를 넘어 전달되어야 합니다.
이번 commit은 그 도출 과정이 실제로 동작하도록 만듭니다. 먼저 FrameLoader::didBeginDocument가 response를 기준으로 Document::setIPAddressSpace()를 설정하도록 변경되었습니다. javascript:와 about: document의 경우에는 DocumentWriter::begin이 owner document의 값을 복사해 옵니다. blob: document는 DocumentLoader::responseReceived에서 PolicyContainer를 거쳐 initiator의 address space를 상속합니다. 한편 PolicyContainer::ipAddressSpace는 그동안 WebCoreArgumentCoders.serialization.in에서 빠져 있었는데, 이번에 IPC를 통해 subframe까지 전달되도록 수정되었습니다. 또한 soup 전용 classifier인 resolvedIPAddressSpace가 새로 추가되어, address space가 아예 없던 GTK와 WPE의 response에도 값이 부여됩니다. 테스트용으로는 internals.documentIPAddressSpace()가 추가되었습니다.
Significance
패치 이전에는 실제로 어디에서 제공된 문서인지와 무관하게, 모든 document가 신뢰 수준이 가장 낮은 분류인 Public으로 기본 설정되었습니다. 그래서 loopback이나 local network에서 제공되는 페이지가 잘못 분류되었습니다. check 자체가 우회되거나 비활성화된 것은 아니지만, LNA의 비교가 틀린 결과를 내놓는 상태였습니다.
더 눈여겨볼 쪽은 IPC 계층에서의 실패입니다. PolicyContainer::ipAddressSpace는 struct에 선언되어 있었지만 값이 한 번도 대입되지 않았고, serialization descriptor에서도 별도로 누락되어 있었습니다. 문제는 struct padding이 우연히 기대 크기와 맞아떨어졌다는 점입니다. 바로 이런 누락을 잡아내려고 자동 생성되는 size assertion이 있었는데도, 결국 걸리지 않았습니다.
Audit directions
Narrow: address space 상속이 아직 적용되지 않은 나머지 document 생성 경로를 점검할 필요가 있습니다. javascript:, about:, blob: 외에도 srcdoc이나 sandboxed iframe처럼 합성되는 document 타입이 남아 있습니다. 초기값 설정이 빠진 경로는 Public으로 되돌아가고, 그만큼 LNA가 허용하는 범위가 조용히 넓어집니다. 찾을 때의 단서는 주변에 setIPAddressSpace() 호출이 없는 Document 생성 지점입니다. Wider: padding에 가려진 size assertion이 다른 곳에도 그대로 적용되는 교훈입니다. struct 끝에 padding이 있는 .serialization.in descriptor라면, 필드 하나가 빠져도 자동 생성된 검사에 걸리지 않을 수 있습니다. 그래서 넓게 볼 때의 탐색 대상은 헤더에는 존재하지만 serialization descriptor에는 빠져 있는, PolicyContainer 주변의 보안 관련 필드입니다. 리뷰 단계에서의 단서는 한 commit에서 .h에 struct 멤버가 추가되었는데 짝이 되는 .serialization.in에는 대응하는 줄이 없는 경우입니다. Widest: 필드가 선언되어 있고 컴파일도 되지만 값이 한 번도 대입되지 않는 패턴은 IPC에만 국한되지 않습니다. 어떤 보안 비교가 default initializer 말고는 아무도 쓰지 않는 멤버를 읽고 있다면, 그 비교는 겉모습만 비교일 뿐 사실상 상수를 확인하는 것과 같습니다.