[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