From 07c08054b0c72279834184ce3a4f042fd8c4278e Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Thu, 18 Jun 2020 18:35:01 +0100 Subject: [PATCH] lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'. This fixes a curious failure unpacking `gnome-icon-theme' under qemu. What appears to be happening here is that `m_strndup' (or, more likely, `malloc' behind it) is setting `errno' to `ENOMEM' while it tries various approaches to allocating memory. This then confuses the `if (errno)' check at the end into thinking that the header decoding has failed when in fact everything is fine. POSIX appears to allow `malloc', and derived functions, to set `errno' spuriously in this manner (even though ISO C rules wouldn't given the POSIX definition of `malloc'), so this is properly a bug in `dpkg'. This bug is fixed (by accident, apparently) in buster, but the proper change is hard to backport, so we have this kludge instead. --- debian/changelog | 7 +++++++ lib/dpkg/tarfn.c | 15 +++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index d5d124b..ab2c09d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +dpkg (1.18.25mdw1) unstable; urgency=medium + + [Mark Wooding] + * Kludge `tar_header_decode' to handle spurious `errno' setting better. + + -- Mark Wooding Thu, 18 Jun 2020 18:34:29 +0100 + dpkg (1.18.25) stretch; urgency=medium [ Guillem Jover ] diff --git a/lib/dpkg/tarfn.c b/lib/dpkg/tarfn.c index 27952f9..66590bf 100644 --- a/lib/dpkg/tarfn.c +++ b/lib/dpkg/tarfn.c @@ -273,8 +273,6 @@ tar_header_decode(struct tar_header *h, struct tar_entry *d) { long checksum; - errno = 0; - if (memcmp(h->magic, TAR_MAGIC_GNU, 6) == 0) d->format = TAR_FORMAT_GNU; else if (memcmp(h->magic, TAR_MAGIC_USTAR, 6) == 0) @@ -292,6 +290,8 @@ tar_header_decode(struct tar_header *h, struct tar_entry *d) else d->name = m_strndup(h->name, sizeof(h->name)); d->linkname = m_strndup(h->linkname, sizeof(h->linkname)); + errno = 0; + d->stat.mode = tar_header_get_unix_mode(h); /* Even though off_t is signed, we use an unsigned parser here because * negative offsets are not allowed. */ @@ -303,24 +303,27 @@ tar_header_decode(struct tar_header *h, struct tar_entry *d) TAR_ATOUL(h->devminor, dev_t)); else d->dev = makedev(0, 0); + if (errno) return 0; if (*h->user) d->stat.uname = m_strndup(h->user, sizeof(h->user)); else d->stat.uname = NULL; + errno = 0; + d->stat.uid = TAR_ATOUL(h->uid, uid_t); + if (errno) return 0; if (*h->group) d->stat.gname = m_strndup(h->group, sizeof(h->group)); else d->stat.gname = NULL; - d->stat.gid = TAR_ATOUL(h->gid, gid_t); + errno = 0; + d->stat.gid = TAR_ATOUL(h->gid, gid_t); checksum = tar_atol8(h->checksum, sizeof(h->checksum)); + if (errno) return 0; - /* Check for parse errors. */ - if (errno) - return 0; return tar_header_checksum(h) == checksum; } -- 2.11.0