zlib 1.3.1 in sgcWebSockets e sgcOpenAPI | Blog eSeGeCe

zlib 1.3.1 in sgcWebSockets e sgcOpenAPI

· Componenti

zlib è uno dei pochi frammenti di codice C di terze parti presenti in sgcWebSockets. Alimenta l'estensione WebSocket permessage-deflate, quindi ogni frame compresso che il vostro server invia o riceve passa attraverso di esso, e gestisce la codifica dei contenuti HTTP. sgcOpenAPI condivide gli stessi sorgenti, perciò usa la stessa copia. A partire dalla 2026.8.0 quella copia passa da zlib 1.2.12 a zlib 1.3.1.

Il cambiamento è invisibile a livello di API. Nulla nel vostro codice deve essere modificato e il comportamento della compressione resta invariato. Vale invece la pena spiegare perché l'aggiornamento di versione di una piccola libreria C è qualcosa di più di una semplice sostituzione di file, e che cosa abbiamo fatto per essere certi che sia sicuro su ogni compilatore che supportiamo.

Che cosa corregge la 1.3.1, e perché non eravate esposti

La correzione principale tra la 1.2.12 e la 1.3.1 è CVE-2022-37434, una lettura oltre i limiti dell'heap in inflate(). È raggiungibile solo quando l'applicazione chiamante passa a zlib un gz_header il cui campo extra punta a un buffer. zlib copia allora al suo interno il campo extra del gzip, e nella 1.2.12 quella copia era priva di un controllo dei limiti.

sgcWebSockets non ha mai soddisfatto quella condizione. Chiama inflateGetHeader solo con un gz_header inizializzato a zero e non assegna mai head.extra, quindi il ramo interessato non poteva essere raggiunto. Lo abbiamo verificato nei sorgenti prima di decidere il da farsi, e lo affermiamo chiaramente: le applicazioni compilate con le versioni precedenti non erano vulnerabili attraverso questo percorso.

Abbiamo comunque effettuato l'aggiornamento. Quello che gli scanner automatici e i questionari dei fornitori leggono sono le stringhe di versione, non i grafi delle chiamate, e un cliente che esegue una scansione delle dipendenze non dovrebbe essere costretto a ricostruire il nostro ragionamento per chiudere una segnalazione. Aggiornare chiude la discussione, invece di doverla ripetere ogni volta.

Perché aggiornare zlib non è una semplice sostituzione di file

zlib viene compilato dentro il vostro eseguibile anziché essere distribuito come DLL, ed è per questo che un'applicazione sgcWebSockets non ha alcuna zlib1.dll accanto a sé. Quel collegamento avviene tramite object file precompilati, e Delphi è esigente riguardo al loro formato. Aggiornare zlib significa quindi ricompilare quegli object file, e non ne esiste un solo insieme, bensì tre.

Usato daFormatoCompilato con
Da Delphi 7 a XEOMFbcc32, ZEXPORT=__fastcall
XE2 e successivi, Win32OMFbcc32, ZEXPORT=__cdecl
XE2 e successivi, Win64COFFMSVC cl

I due insiemi a 32 bit differiscono nella convenzione di chiamata, perché i compilatori più vecchi collegano zlib con la convenzione register di Delphi mentre XE2 e successivi usano cdecl. L'insieme a 64 bit è invece in un formato di object file completamente diverso. Vale la pena notare che bcc64 non è in grado di produrlo, perché genera object file ELF mentre il linker Win64 di Delphi richiede COFF, quindi quell'insieme viene compilato con il compilatore Microsoft.

Nulla di tutto ciò è visibile per voi. È semplicemente la ragione per cui un aggiornamento di zlib è un esercizio di build e non un download.

Verificato su ogni compilatore, non solo sul più recente

Gli object file ricompilati possono compilare senza errori ed essere comunque sbagliati, quindi un test di linking non basta di per sé. Ogni compilatore supportato è stato usato per compilare e poi eseguire un programma che comprime un buffer, lo decomprime, lo confronta byte per byte e verifica che gli object file collegati riportino la versione attesa.

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;

Il test è stato eseguito su Delphi 7, Delphi 2007, Delphi 2009 e RAD Studio da XE6 a 13, su Win32 e su Win64 dove la piattaforma esiste. Tutte e 25 le combinazioni passano e riportano 1.3.1.

Un bug latente a 64 bit corretto lungo il percorso

La matrice ha individuato qualcosa che non aveva nulla a che vedere con la nuova versione. Su Delphi 10 Seattle le build a 64 bit selezionavano gli object file a 32 bit, che non possono essere collegati in un eseguibile a 64 bit e producevano un errore Bad object file format. La causa era una vecchia condizionale pensata per aggirare un problema specifico di Seattle, che indirizzava quell'unica combinazione all'insieme di object file sbagliato. Seattle a 64 bit ora usa gli stessi object file di ogni altro target a 64 bit, e compila.

sgcOpenAPI riceve lo stesso aggiornamento

sgcOpenAPI condivide i sorgenti con sgcWebSockets, zlib inclusa, quindi passa alla 1.3.1 nella stessa release senza alcuna azione separata da parte vostra.

Che cosa dovete fare

Installate la 2026.8.0 e ricompilate i vostri progetti. Non c'è alcuna proprietà da impostare, nessuna unit da aggiungere o rimuovere e nessuna modifica al deployment, perché zlib era già dentro il vostro eseguibile e continua a esserlo. Se mantenete una distinta base del software per il vostro prodotto, aggiornate la voce zlib a 1.3.1 e potete eliminare qualsiasi nota su CVE-2022-37434 che vi stavate portando dietro.