CVE-2026-49337: free orphaned slice header when no active image unit
authorDebian Multimedia Maintainers <debian-multimedia@lists.debian.org>
Sun, 30 Aug 2026 20:56:35 +0000 (22:56 +0200)
committerMoritz Mühlenhoff <jmm@debian.org>
Sun, 30 Aug 2026 20:56:35 +0000 (22:56 +0200)
Origin: upstream, https://github.com/strukturag/libde265/commit/683cb9fa603e35840642f98765ab95cdb71cadf9
Bug: https://github.com/strukturag/libde265/security/advisories/GHSA-g5hj-rf9f-7vxm
Bug-Debian: https://bugs.debian.org/1140431
Applied-Upstream: 1.1.0
Comment: Backport: on 1.0.15 the pre-existing unconditional add_slice_segment_header() call must be removed (upstream moves it into the guarded block); keeping both would double-free every slice header.

Slice headers attached to finished pictures without an active image unit
were retained forever; a crafted NAL sequence can grow memory without
bound during continuous streaming.

Gbp-Pq: Name CVE-2026-49337.patch

libde265/decctx.cc

index ed8709d855d905d4efa69500445ffac6a2dca0d7..8383dd2bc4c338a862450a4dededfcdc22bdfcdc 100644 (file)
@@ -928,8 +928,6 @@ de265_error decoder_context::read_slice_NAL(bitreader& reader, NAL_unit* nal, na
       return err;
     }
 
-  this->img->add_slice_segment_header(shdr);
-
   skip_bits(&reader,1); // TODO: why?
   prepare_for_CABAC(&reader);
 
@@ -957,6 +955,13 @@ de265_error decoder_context::read_slice_NAL(bitreader& reader, NAL_unit* nal, na
 
   if ( ! image_units.empty() ) {
 
+    // Hand the slice header to the picture (which takes ownership and frees it
+    // on release). Only do this when there is an active image unit to decode
+    // the slice; otherwise the header would be retained on img->slices forever,
+    // which a crafted stream of non-first slice NALs can exploit to grow memory
+    // without bound.
+    this->img->add_slice_segment_header(shdr);
+
     slice_unit* sliceunit = new slice_unit(this);
     sliceunit->nal = nal;
     sliceunit->shdr = shdr;
@@ -967,6 +972,10 @@ de265_error decoder_context::read_slice_NAL(bitreader& reader, NAL_unit* nal, na
 
     image_units.back()->slice_units.push_back(sliceunit);
   }
+  else {
+    nal_parser.free_NAL_unit(nal);
+    delete shdr;
+  }
 
   bool did_work;
   err = decode_some(&did_work);