[PATCH 1/2] deb: guard the empty control member case in GetContent

Nexory <[email protected]>
Newsgroups gmane.linux.debian.apt.devel
Message-ID <OS6P279MB1180186318B39D64DACD6DC3CBD12@OS6P279MB1180.NORP279.PROD.OUTLOOK.COM>
debDebPkgFileIndex::GetContent() trims trailing newlines from the extracted
control member and then does a forward isspace_ascii(Control[0]) skip and a
`content << Control` insertion, both of which assume Control is a NUL
terminated C string. MemControlExtract only guarantees a buffer of Itm.Size+2
whose last two bytes are '\n' (so pkgTagSection::Scan sees a blank line); it
does not append a NUL. For an empty control member Size is 0, the backward
trim loop stops immediately, and Control points at a 2-byte buffer of two '\n'
with no terminator: the forward whitespace skip walks both bytes and then
reads one past the allocation, and `content << Control` keeps reading adjacent
heap until it happens to hit a NUL.

Terminate the degenerate empty-control case explicitly so the value is a valid
empty C string; the member is then rejected as usual with "Encountered a
section with no Package: header".

DoS only (heap-buffer-overflow read on a malformed local .deb parsed by
apt-cache show / apt-get install ./x.deb). Confirmed with an ASan build
against a crafted .deb whose control.tar holds a zero-length ./control member;
the read is reported in GetContent and disappears with this guard.
---
 apt-pkg/deb/debindexfile.cc | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc
index 0616c90..d88d8e2 100644
--- a/apt-pkg/deb/debindexfile.cc
+++ b/apt-pkg/deb/debindexfile.cc
@@ -188,6 +188,12 @@ bool debDebPkgFileIndex::GetContent(std::ostream &content, std::string const &de
    while (extractor.Length > 0 && extractor.Control[extractor.Length] == '\n')
       extractor.Control[extractor.Length--] = '\0';
    const char *Control = extractor.Control;
+   // An empty or all-newline control member leaves Control[0] pointing at the
+   // buffer with no NUL terminator (the trim loop above stops at Length 0),
+   // so both this whitespace skip and the stream insertion below would read
+   // past the 2-byte allocation. Terminate the degenerate case explicitly.
+   if (extractor.Length == 0)
+      extractor.Control[0] = 0;
    while (isspace_ascii(Control[0]))
       Control++;
 
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.