python / python/cpython

lzma: unbounded dictionary-size allocation is a memory DoS (zipfile, tarfile, lzma.decompress)

Aperta
#155,649 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

extension-modules type-security
Lingua principale
Python
Stelle
77.2k
Fork
35.9k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

Bug: LZMA decompression accepts an attacker-controlled dictionary size with no bound, and liblzma allocates the full dictionary up front when a decompressor is created. A few bytes of input can therefore force a multi-gigabyte allocation (memory denial of service).

Attack surfaces (both reported by OSS-Fuzz, both public):

  • zipfile with an LZMA-compressed member: the 5-byte LZMA properties header in the member data declares the dictionary. A 1088-byte zip whose member declares a ~2 GiB dictionary OOMs the process. https://issues.oss-fuzz.com/issues/495472861
  • tarfile's compression-detection loop: a 13-byte input whose first byte is a valid LZMA-alone properties byte (0x66) and whose remaining bytes encode a ~4 GiB dictionary is tried as LZMA; liblzma allocates 4 GiB before failing. https://issues.oss-fuzz.com/issues/482161128

Also reachable directly: lzma.decompress() / LZMADecompressor(format=FORMAT_AUTO) on untrusted bytes, and LZMADecompressor(FORMAT_RAW, filters=[{"dict_size": ...}]).

Root cause: two gaps:

  1. parse_filter_spec_lzma() accepts any dict_size (up to UINT32_MAX) for raw LZMA1/LZMA2 filter chains; liblzma allocates that dictionary at decompressor creation.
  2. LZMADecompressor defaults memlimit to UINT64_MAX, so the FORMAT_ALONE/FORMAT_AUTO paths (where the header is parsed inside liblzma) are also unbounded.

Proposed fix (PR to follow):

  • Reject dict_size > LZMA_DICT_SIZE_MAX (1.5 GiB, liblzma's own maximum) in parse_filter_spec_lzma() with LZMAError.
  • Default the decompressor memlimit to LZMA_DICT_SIZE_MAX instead of UINT64_MAX (callers may still pass an explicit memlimit).

No legitimate streams are affected: liblzma presets cap at 64 MiB dictionaries, and 1.5 GiB is liblzma's own maximum supported dictionary size.

Reported by OSS-Fuzz (ClusterFuzz). Reproducers attached to the issues above.

Linked PRs
  • gh-155650

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia con parse_filter_spec_lzma() e LZMADecompressor, quindi esamina i percorsi zipfile e tarfile descritti nell’issue. Usa i riproduttori OSS-Fuzz collegati per verificare che i dizionari sovradimensionati non causino più un’allocazione non vincolata, mentre i normali stream LZMA e il comportamento esplicito di memlimit rimangono invariati.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
python
Ambito
security
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Specificata chiaramente
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.