From: Mark Wooding Date: Thu, 18 Jun 2020 15:44:07 +0000 (+0100) Subject: awful debugging hacking X-Git-Url: https://git.distorted.org.uk/~mdw/dpkg/commitdiff_plain/refs/heads/mdw/debugging awful debugging hacking --- diff --git a/dpkg-deb/extract.c b/dpkg-deb/extract.c index f91d18a..f58e991 100644 --- a/dpkg-deb/extract.c +++ b/dpkg-deb/extract.c @@ -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); diff --git a/lib/dpkg/buffer.c b/lib/dpkg/buffer.c index 5fda05f..d458917 100644 --- a/lib/dpkg/buffer.c +++ b/lib/dpkg/buffer.c @@ -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) diff --git a/lib/dpkg/fdio.c b/lib/dpkg/fdio.c index 8e61b5d..afe239b 100644 --- a/lib/dpkg/fdio.c +++ b/lib/dpkg/fdio.c @@ -21,12 +21,106 @@ #include #include +#include #include +#include #include #include #include +#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; diff --git a/lib/dpkg/fdio.h b/lib/dpkg/fdio.h index d714dbd..e80a848 100644 --- a/lib/dpkg/fdio.h +++ b/lib/dpkg/fdio.h @@ -27,6 +27,12 @@ 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 diff --git a/lib/dpkg/tarfn.c b/lib/dpkg/tarfn.c index 27952f9..ec77fc6 100644 --- a/lib/dpkg/tarfn.c +++ b/lib/dpkg/tarfn.c @@ -24,11 +24,13 @@ #include +#include #include #include #include #include #include +#include #include #include #include @@ -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. */ diff --git a/src/unpack.c b/src/unpack.c index 45d3ff6..c705df6 100644 --- a/src/unpack.c +++ b/src/unpack.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -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);