awful debugging hacking mdw/debugging
authorMark Wooding <mdw@distorted.org.uk>
Thu, 18 Jun 2020 15:44:07 +0000 (16:44 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 18 Jun 2020 15:44:07 +0000 (16:44 +0100)
dpkg-deb/extract.c
lib/dpkg/buffer.c
lib/dpkg/fdio.c
lib/dpkg/fdio.h
lib/dpkg/tarfn.c
src/unpack.c

index f91d18a..f58e991 100644 (file)
@@ -122,6 +122,8 @@ extracthalf(const char *debar, const char *dir,
   enum compressor_type decompressor = COMPRESSOR_TYPE_GZIP;
 
   ar = dpkg_ar_open(debar);
+if (taroption == DPKG_TAR_PASSTHROUGH && !admininfo)
+ open_shadow(ar->fd, "deb-extract-ar");
 
   r = read_line(ar->fd, versionbuf, strlen(DPKG_AR_MAGIC), sizeof(versionbuf) - 1);
   if (r < 0)
@@ -276,6 +278,8 @@ extracthalf(const char *debar, const char *dir,
   c1 = subproc_fork();
   if (!c1) {
     close(p1[0]);
+if (taroption == DPKG_TAR_PASSTHROUGH && !admininfo)
+  open_shadow(p1[1], "deb-extract-compressed-out");
     if (fd_fd_copy(ar->fd, p1[1], memberlen, &err) < 0)
       ohshit(_("cannot copy archive member from '%s' to decompressor pipe: %s"),
              ar->name, err.str);
@@ -284,6 +288,7 @@ extracthalf(const char *debar, const char *dir,
     exit(0);
   }
   close(p1[1]);
+close_shadow(ar->fd);
 
   if (taroption) {
     m_pipe(p2);
@@ -296,6 +301,10 @@ extracthalf(const char *debar, const char *dir,
   if (!c2) {
     if (taroption)
       close(p2[0]);
+if (taroption == DPKG_TAR_PASSTHROUGH && !admininfo) {
+  open_shadow(p1[0], "deb-extract-compressed-in");
+  open_shadow(p2_out, "deb-extract-decompressed-out");
+}
     decompress_filter(decompressor, p1[0], p2_out,
                       _("decompressing archive member"));
     exit(0);
index 5fda05f..d458917 100644 (file)
@@ -265,6 +265,7 @@ buffer_skip(struct buffer_data *input, off_t limit, struct dpkg_error *err)
 
        switch (input->type) {
        case BUFFER_READ_FD:
+if (shadowed_fd_p(input->arg.i)) break;
                if (lseek(input->arg.i, limit, SEEK_CUR) != -1)
                        return limit;
                if (errno != ESPIPE)
index 8e61b5d..afe239b 100644 (file)
 #include <config.h>
 #include <compat.h>
 
+#include <assert.h>
 #include <errno.h>
+#include <stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
 
 #include <dpkg/fdio.h>
 
+#define MAXSHADOW 16
+static struct shadow {
+  int fd, shadow;
+  dev_t dev; ino_t ino;
+} shadowtab[MAXSHADOW];
+static size_t nshadow;
+
+static struct shadow *find_shadow(int fd)
+{
+  size_t i, j;
+  int rc;
+  struct stat st;
+
+  rc = fstat(fd, &st); assert(!rc);
+
+  for (i = j = 0; i < nshadow; i++) {
+    if (shadowtab[i].fd == fd) {
+      if (st.st_dev != shadowtab[i].dev || st.st_ino != shadowtab[i].ino)
+       { close(shadowtab[i].shadow); continue; }
+      return (&shadowtab[i]);
+    }
+    if (i != j) shadowtab[j] = shadowtab[i];
+    j++;
+  }
+  nshadow = j;
+  return (0);
+}
+
+int shadowed_fd_p(int fd) { return (!!find_shadow(fd)); }
+
+static void write_to_shadow(int fd, const void *p, size_t sz)
+{
+  const struct shadow *shadow = find_shadow(fd);
+  ssize_t n;
+
+  if (shadow) { n = write(shadow->shadow, p, sz); assert((size_t)n == sz); }
+}
+
+void save_copy(const char *path, const char *label, const char *ext)
+{
+  char buf[256];
+  int err = errno;
+  int i = 0;
+
+  for (;;) {
+    sprintf(buf, "/tmp/mdw/%s#%d.%s", label, i, ext);
+    if (!link(path, buf)) break;
+    assert(errno == EEXIST);
+    i++;
+  }
+  fprintf(stderr, ";; save `%s' as `%s'\n", path, buf);
+  errno = err;
+}
+
+void save_shadow(const char *label, const char *ext)
+{
+  char buf[256];
+
+  sprintf(buf, "/tmp/mdw/t.shadow-%s", label);
+  save_copy(buf, label, ext);
+}
+
+void open_shadow(int fd, const char *label)
+{
+  struct shadow *shadow;
+  struct stat st;
+  int rc;
+  char buf[256];
+
+  assert(!find_shadow(fd));
+  assert(nshadow < MAXSHADOW); shadow = &shadowtab[nshadow++];
+  sprintf(buf, "/tmp/mdw/t.shadow-%s", label);
+  unlink(buf);
+  shadow->fd = fd;
+  shadow->shadow = open(buf, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+  assert(shadow->shadow >= 0);
+  rc = fstat(fd, &st); assert(!rc);
+  shadow->dev = st.st_dev;
+  shadow->ino = st.st_ino;
+}
+
+void close_shadow(int fd)
+{
+  int rc;
+  struct shadow *shadow;
+
+  shadow = find_shadow(fd); if (!shadow) return;
+  rc = close(shadow->shadow); assert(!rc);
+  assert(nshadow); nshadow--;
+  if (shadow != &shadowtab[nshadow]) *shadow = shadowtab[nshadow];
+}
+
 ssize_t
 fd_read(int fd, void *buf, size_t len)
 {
@@ -44,6 +138,7 @@ fd_read(int fd, void *buf, size_t len)
                }
                if (n == 0)
                        break;
+write_to_shadow(fd, ptr + total, n);
 
                total += n;
                len -= n;
@@ -69,6 +164,7 @@ fd_write(int fd, const void *buf, size_t len)
                }
                if (n == 0)
                        break;
+write_to_shadow(fd, buf, n);
 
                total += n;
                len -= n;
index d714dbd..e80a848 100644 (file)
 
 DPKG_BEGIN_DECLS
 
+int shadowed_fd_p(int fd);
+void save_copy(const char *path, const char *label, const char *ext);
+void save_shadow(const char *label, const char *ext);
+void open_shadow(int fd, const char *label);
+void close_shadow(int fd);
+
 /**
  * @defgroup fdio File descriptor I/O
  * @ingroup dpkg-internal
index 27952f9..ec77fc6 100644 (file)
 
 #include <sys/stat.h>
 
+#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <pwd.h>
 #include <grp.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -271,9 +273,10 @@ tar_header_checksum(struct tar_header *h)
 static int
 tar_header_decode(struct tar_header *h, struct tar_entry *d)
 {
-       long checksum;
+       long checksum, calc_checksum;
 
        errno = 0;
+if (errno) fprintf(stderr, ";; checkpoint #0: %s\n", strerror(errno));
 
        if (memcmp(h->magic, TAR_MAGIC_GNU, 6) == 0)
                d->format = TAR_FORMAT_GNU;
@@ -281,47 +284,76 @@ tar_header_decode(struct tar_header *h, struct tar_entry *d)
                d->format = TAR_FORMAT_USTAR;
        else
                d->format = TAR_FORMAT_OLD;
+//if (errno) fprintf(stderr, ";; checkpoint #1: %s\n", strerror(errno));
 
        d->type = (enum tar_filetype)h->linkflag;
        if (d->type == TAR_FILETYPE_FILE0)
                d->type = TAR_FILETYPE_FILE;
+if (errno) fprintf(stderr, ";; checkpoint #2: %s\n", strerror(errno));
 
        /* Concatenate prefix and name to support ustar style long names. */
-       if (d->format == TAR_FORMAT_USTAR && h->prefix[0] != '\0')
+       if (d->format == TAR_FORMAT_USTAR && h->prefix[0] != '\0') {
                d->name = tar_header_get_prefix_name(h);
-       else
+if (errno) fprintf(stderr, ";; checkpoint #3a: %s\n", strerror(errno));
+       } else {
                d->name = m_strndup(h->name, sizeof(h->name));
+if (errno) fprintf(stderr, ";; checkpoint #3b: %s\n", strerror(errno));
+       }
        d->linkname = m_strndup(h->linkname, sizeof(h->linkname));
        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. */
        d->size = TAR_ATOUL(h->size, off_t);
        d->mtime = TAR_ATOSL(h->mtime, time_t);
+if (errno) fprintf(stderr, ";; checkpoint #4: %s\n", strerror(errno));
 
        if (d->type == TAR_FILETYPE_CHARDEV || d->type == TAR_FILETYPE_BLOCKDEV)
                d->dev = makedev(TAR_ATOUL(h->devmajor, dev_t),
                                 TAR_ATOUL(h->devminor, dev_t));
        else
                d->dev = makedev(0, 0);
+//if (errno) fprintf(stderr, ";; checkpoint #5: %s\n", strerror(errno));
 
        if (*h->user)
                d->stat.uname = m_strndup(h->user, sizeof(h->user));
        else
                d->stat.uname = NULL;
        d->stat.uid = TAR_ATOUL(h->uid, uid_t);
+//if (errno) fprintf(stderr, ";; checkpoint #6: %s\n", strerror(errno));
 
        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);
+//if (errno) fprintf(stderr, ";; checkpoint #7: %s\n", strerror(errno));
 
        checksum = tar_atol8(h->checksum, sizeof(h->checksum));
+//if (errno) fprintf(stderr, ";; checkpoint #8: %s\n", strerror(errno));
 
        /* Check for parse errors. */
-       if (errno)
-               return 0;
-       return tar_header_checksum(h) == checksum;
+       if (errno) {
+fprintf(stderr, ";; header parse failed: %s\n", strerror(errno));
+               goto bad;
+       }
+       calc_checksum = tar_header_checksum(h);
+if (checksum != calc_checksum) {
+  fprintf(stderr, ";; header checksum %ld /= %ld\n", checksum, calc_checksum);
+  goto bad;
+}
+       return 1;
+
+
+bad: {
+  if (h->name[0]) {
+    int fd;
+    ssize_t n;
+    fd = open("/tmp/mdw/badhdr", O_CREAT | O_TRUNC | O_WRONLY, 0666); assert(fd >= 0);
+    n = write(fd, h, 512); assert(n == 512);
+    close(fd);
+  }
+  return (0);
+}
 }
 
 /**
@@ -445,15 +477,18 @@ tar_extractor(void *ctx, const struct tar_operations *ops)
        while ((status = ops->read(ctx, buffer, TARBLKSZ)) == TARBLKSZ) {
                int name_len;
 
+//fprintf(stderr, ";; ops->read -> %d\n", status);
                if (!tar_header_decode((struct tar_header *)buffer, &h)) {
                        if (h.name[0] == '\0') {
                                /* End of tape. */
                                status = 0;
+fprintf(stderr, ";;   End of tape.\n");
                        } else {
                                /* Indicates broken tarfile:
                                 * “Header checksum error”. */
                                errno = 0;
                                status = -1;
+fprintf(stderr, ";;   `Header checksum error'.\n");
                        }
                        tar_entry_destroy(&h);
                        break;
@@ -474,6 +509,7 @@ tar_extractor(void *ctx, const struct tar_operations *ops)
                        /* Indicates broken tarfile: “Bad header data”. */
                        errno = 0;
                        status = -1;
+fprintf(stderr, ";;   `Bad header data'.\n");
                        tar_entry_destroy(&h);
                        break;
                }
@@ -485,6 +521,7 @@ tar_extractor(void *ctx, const struct tar_operations *ops)
                        /* Compatibility with pre-ANSI ustar. */
                        if (h.name[name_len - 1] != '/') {
                                status = ops->extract_file(ctx, &h);
+if (status) fprintf(stderr, ";;   extract_file(%s) failed: %s\n", h.name, strerror(errno));
                                break;
                        }
                        /* Else, fall through. */
@@ -493,9 +530,11 @@ tar_extractor(void *ctx, const struct tar_operations *ops)
                                h.name[name_len - 1] = '\0';
                        }
                        status = ops->mkdir(ctx, &h);
+if (status) fprintf(stderr, ";;   mkdir(%s) failed: %s\n", h.name, strerror(errno));
                        break;
                case TAR_FILETYPE_HARDLINK:
                        status = ops->link(ctx, &h);
+if (status) fprintf(stderr, ";;   link(%s) failed: %s\n", h.name, strerror(errno));
                        break;
                case TAR_FILETYPE_SYMLINK:
                        symlink_node = m_malloc(sizeof(*symlink_node));
@@ -513,28 +552,36 @@ tar_extractor(void *ctx, const struct tar_operations *ops)
                case TAR_FILETYPE_BLOCKDEV:
                case TAR_FILETYPE_FIFO:
                        status = ops->mknod(ctx, &h);
+if (status) fprintf(stderr, ";;   mknod(%s) failed: %s\n", h.name, strerror(errno));
                        break;
                case TAR_FILETYPE_GNU_LONGLINK:
                        status = tar_gnu_long(ctx, ops, &h, &next_long_link);
+if (status) fprintf(stderr, ";;   long-link(%s) failed: %s\n", h.name, strerror(errno));
                        break;
                case TAR_FILETYPE_GNU_LONGNAME:
                        status = tar_gnu_long(ctx, ops, &h, &next_long_name);
+if (status) fprintf(stderr, ";;   long-name(%s) failed: %s\n", h.name, strerror(errno));
                        break;
                default:
                        /* Indicates broken tarfile: “Bad header field”. */
                        errno = 0;
                        status = -1;
+fprintf(stderr, ";;   `Bad header field'.\n");
                }
                tar_entry_destroy(&h);
-               if (status != 0)
+               if (status != 0) {
                        /* Pass on status from coroutine. */
+fprintf(stderr, ";;   bailing due to error\n");
                        break;
+               }
        }
 
        while (symlink_head) {
                symlink_node = symlink_head->next;
-               if (status == 0)
+               if (status == 0) {
                        status = ops->symlink(ctx, &symlink_head->h);
+if (status) fprintf(stderr, ";;   symlink(%s) failed: %s\n", symlink_head->h.name, strerror(errno));
+               }
                tar_entry_destroy(&symlink_head->h);
                free(symlink_head);
                symlink_head = symlink_node;
@@ -547,6 +594,7 @@ tar_extractor(void *ctx, const struct tar_operations *ops)
        if (status > 0) {
                /* Indicates broken tarfile: “Read partial header record”. */
                errno = 0;
+fprintf(stderr, ";; `Read partial header record'.\n");
                return -1;
        } else {
                /* Return whatever I/O function returned. */
index 45d3ff6..c705df6 100644 (file)
@@ -47,6 +47,7 @@
 #include <dpkg/pkg.h>
 #include <dpkg/pkg-queue.h>
 #include <dpkg/path.h>
+#include <dpkg/fdio.h>
 #include <dpkg/buffer.h>
 #include <dpkg/subproc.h>
 #include <dpkg/dir.h>
@@ -1409,6 +1410,7 @@ void process_archive(const char *filename) {
   }
   close(p1[1]);
   p1[1] = -1;
+open_shadow(p1[0], "deb-extract-decompressed-in");
 
   newfiles_queue.head = NULL;
   newfiles_queue.tail = &newfiles_queue.head;
@@ -1420,6 +1422,11 @@ void process_archive(const char *filename) {
 
   rc = tar_extractor(&tc, &tf);
   if (rc) {
+save_shadow("deb-extract-ar", "a");
+save_shadow("deb-extract-compressed-out", "tar.xz");
+save_shadow("deb-extract-compressed-in", "tar.xz");
+save_shadow("deb-extract-decompressed-out", "tar");
+save_shadow("deb-extract-decompressed-in", "tar");
     if (errno) {
       ohshite(_("error reading dpkg-deb tar output"));
     } else {
@@ -1428,6 +1435,7 @@ void process_archive(const char *filename) {
   }
   if (fd_skip(p1[0], -1, &err) < 0)
     ohshit(_("cannot zap possible trailing zeros from dpkg-deb: %s"), err.str);
+close_shadow(p1[0]);
   close(p1[0]);
   p1[0] = -1;
   subproc_reap(pid, BACKEND " --fsys-tarfile", SUBPROC_NOPIPE);