zlib은 sgcWebSockets 안에 들어 있는 몇 안 되는 서드파티 C 코드 중 하나입니다. WebSocket permessage-deflate 확장을 구동하므로 서버가 보내거나 받는 모든 압축 프레임이 이곳을 통과하며, HTTP 콘텐츠 인코딩도 이것이 처리합니다. sgcOpenAPI는 같은 소스를 공유하므로 같은 사본을 사용합니다. 2026.8.0부터 그 사본이 zlib 1.2.12에서 zlib 1.3.1로 이동합니다.
이 변경은 API에서는 보이지 않습니다. 여러분의 코드는 손댈 필요가 전혀 없고 압축 동작도 그대로입니다. 설명할 만한 가치가 있는 부분은, 작은 C 라이브러리의 버전 갱신이 왜 파일 하나 바꿔 넣는 일 이상인지, 그리고 지원하는 모든 컴파일러에서 안전하다는 것을 확인하기 위해 무엇을 했는지입니다.
1.3.1이 무엇을 고치는지, 그리고 왜 여러분은 노출되지 않았는지
1.2.12와 1.3.1 사이의 가장 눈에 띄는 수정은 inflate()의 힙 오버리드인 CVE-2022-37434입니다. 이 문제는 호출하는 애플리케이션이 extra 필드가 버퍼를 가리키는 gz_header를 zlib에 넘길 때만 도달할 수 있습니다. 그러면 zlib은 gzip extra 필드를 그 버퍼로 복사하는데, 1.2.12에서는 그 복사에 경계 검사가 빠져 있었습니다.
sgcWebSockets는 그 조건에 해당한 적이 없습니다. inflateGetHeader를 0으로 초기화된 gz_header와 함께서만 호출하고 head.extra를 절대 할당하지 않으므로, 문제가 되는 분기에는 들어갈 수 없었습니다. 어떻게 할지 결정하기 전에 소스에서 이를 확인했고, 분명히 말씀드립니다. 이전 버전으로 빌드된 애플리케이션은 이 경로를 통해 취약하지 않았습니다.
그럼에도 업데이트했습니다. 자동화된 스캐너와 공급업체 설문지가 읽는 것은 호출 그래프가 아니라 버전 문자열이며, 의존성 스캔을 돌리는 고객이 탐지 결과를 해소하려고 저희의 논리를 재구성해야 할 이유는 없습니다. 업그레이드는 그 대화를 반복해서 나눠야 하는 대신 아예 끝내 줍니다.
zlib 업데이트가 파일 교체가 아닌 이유
zlib은 DLL로 배포되는 대신 여러분의 실행 파일 안으로 컴파일되어 들어갑니다. sgcWebSockets 애플리케이션 옆에 zlib1.dll이 없는 것은 그 때문입니다. 그 링크는 미리 컴파일된 오브젝트 파일로 이루어지는데, Delphi는 그 형식에 까다롭습니다. 따라서 zlib을 업데이트한다는 것은 그 오브젝트들을 다시 빌드한다는 뜻이고, 그 벌은 하나가 아니라 셋입니다.
| 사용 대상 | 형식 | 빌드 도구 |
|---|---|---|
| Delphi 7 ~ XE | OMF | bcc32, ZEXPORT=__fastcall |
| XE2 이상, Win32 | OMF | bcc32, ZEXPORT=__cdecl |
| XE2 이상, Win64 | COFF | MSVC cl |
두 개의 32비트 벌은 호출 규약이 다릅니다. 구형 컴파일러는 zlib을 Delphi 레지스터 규약으로 링크하는 반면 XE2 이상은 cdecl을 사용하기 때문입니다. 64비트 벌은 또 다른 오브젝트 형식입니다. 여기서 짚어 둘 점은 bcc64로는 그것을 만들 수 없다는 것입니다. bcc64는 ELF 오브젝트를 내보내는데 Delphi Win64 링커는 COFF를 원하므로, 그 벌은 마이크로소프트 컴파일러로 빌드합니다.
이 중 어느 것도 여러분에게는 보이지 않습니다. 그저 zlib 버전 갱신이 다운로드가 아니라 빌드 작업인 이유일 뿐입니다.
최신 버전뿐 아니라 모든 컴파일러에서 검증
다시 빌드한 오브젝트는 깔끔하게 컴파일되면서도 잘못되어 있을 수 있으므로, 링크 테스트만으로는 충분하지 않습니다. 지원하는 모든 컴파일러로, 버퍼를 압축하고 다시 압축을 풀어 바이트 단위로 비교한 뒤 링크된 오브젝트가 예상한 버전을 보고하는지 확인하는 프로그램을 빌드하고 실제로 실행했습니다.
uses
sgcIdCTypes, sgcIdGlobal, sgcIdZLibHeaders;
var
vPackedLen: TIdC_ULONG;
begin
vPackedLen := SizeOf(vPacked);
if compress(PIdAnsiChar(@vPacked[0]), vPackedLen,
PIdAnsiChar(@vSrc[0]), SizeOf(vSrc)) <> 0 then
raise Exception.Create('compress failed');
WriteLn('zlib ', String(AnsiString(zlibVersion))); // zlib 1.3.1
end;
이 프로그램은 Delphi 7, Delphi 2007, Delphi 2009, 그리고 RAD Studio XE6부터 13까지에서, Win32와 (플랫폼이 존재하는 경우) Win64에서 실행되었습니다. 25개 조합 모두 통과했고 1.3.1을 보고합니다.
그 과정에서 함께 고친 잠복 64비트 버그
이 매트릭스는 새 버전과는 전혀 무관한 문제를 하나 잡아냈습니다. Delphi 10 Seattle에서 64비트 빌드가 32비트 오브젝트를 선택하고 있었는데, 이는 64비트 실행 파일에 링크될 수 없어 Bad object file format 오류를 냈습니다. 원인은 Seattle 고유의 문제를 우회하려고 넣었던 오래된 조건문이었고, 그것이 그 한 조합만 잘못된 오브젝트 벌로 보내고 있었습니다. 이제 Seattle 64비트도 다른 모든 64비트 타깃과 같은 오브젝트를 사용하며 정상적으로 컴파일됩니다.
sgcOpenAPI도 동일하게 업데이트
sgcOpenAPI는 zlib을 포함해 소스를 sgcWebSockets와 공유하므로, 같은 릴리스에서 1.3.1로 이동하며 여러분이 따로 하실 일은 없습니다.
무엇을 하셔야 하나
2026.8.0을 설치하고 프로젝트를 다시 빌드하십시오. 설정할 속성도, 추가하거나 제거할 유닛도, 배포상의 변경도 없습니다. zlib은 이미 여러분의 실행 파일 안에 있었고 지금도 그렇기 때문입니다. 자체 제품용 소프트웨어 자재 명세서를 관리하고 계신다면 zlib 항목을 1.3.1로 갱신하시고, 그동안 달고 다니던 CVE-2022-37434 관련 주석은 지우셔도 됩니다.
