설명
사용자 메모리 값을 검증한 뒤 같은 위치에서 다시 읽어 사용하면 검증과 사용 사이에 값이 바뀔 수 있습니다.
잠재적 영향
- 커널 또는 네이티브 경계에서 검증 우회, 버퍼 오버플로, 정보 노출이 발생할 수 있습니다.
해결 방법
검증에 쓰는 사용자 메모리의 필드를 신뢰 경계 내부 로컬 변수에 한 번만 복사하고, 같은 로컬 값을 검증하고 사용하세요. 여러 필드의 일관성이 필요하면 요청 전체를 안전하게 복사한 뒤 상호 관계도 검증하세요.
예시
변경 전
c
ProbeForRead(req, sizeof(*req), 1);
if (req->len > MAX) { return; }
RtlCopyMemory(dst, req->buf, req->len);
변경 후
c
ProbeForRead(req, sizeof(*req), 1);
size_t len = req->len;
if (len > MAX) { return; }
RtlCopyMemory(dst, req->buf, len);
설명:
- 변경 전: 검증한 필드를 복사 시점에 다시 읽습니다.
- 변경 후: 길이의 검증과 사용이 같은 로컬 복사본을 사용합니다.
이는 길이 필드의 재읽기만 제거한 발췌입니다. MAX는 목적지 크기를 넘지 않아야 하며, req->buf의 포인터와 실제 메모리 접근은 별도로 검증해야 합니다. Windows 드라이버에서는 ProbeForRead와 이후 사용자 메모리 접근을 예외 처리로 감싸세요. ProbeForRead는 메모리를 고정하거나 다른 스레드의 변경을 막지 않습니다.