lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'. mdw/enomem-fix 1.18.25mdw1
authorMark Wooding <mdw@distorted.org.uk>
Thu, 18 Jun 2020 17:35:01 +0000 (18:35 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 18 Jun 2020 17:36:34 +0000 (18:36 +0100)
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
lib/dpkg/tarfn.c

index d5d124b..ab2c09d 100644 (file)
@@ -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 <mdw@distorted.org.uk>  Thu, 18 Jun 2020 18:34:29 +0100
+
 dpkg (1.18.25) stretch; urgency=medium
 
   [ Guillem Jover ]
index 27952f9..66590bf 100644 (file)
@@ -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;
 }