aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stuge <peter@stuge.se>2020-11-10 20:01:44 +0100
committerFabian Groffen <grobian@gentoo.org>2020-11-14 17:44:47 +0100
commit77a0017b2ea736670eba1f3923201dc1c2858feb (patch)
tree40b3c84cc4afa3030c63297f0e50e1a9294c84d1
parentbuildsys: regen (diff)
downloadportage-utils-77a0017b2ea736670eba1f3923201dc1c2858feb.tar.gz
portage-utils-77a0017b2ea736670eba1f3923201dc1c2858feb.tar.bz2
portage-utils-77a0017b2ea736670eba1f3923201dc1c2858feb.zip
qmerge: copy tbz2 archive into decompressor/tar pipe ourselves
We have nothing to do while tar is running so let's copy the tbz2 archive part into a popen():ed tar pipe ourselves, rather than depend on an external program. Doing so also fixes a possible shell injection vulnerability and improves performance. Fixes: 7171479f ("qmerge: unpack tbz2 file without splitting it first", 2020-05-17) Signed-off-by: Peter Stuge <peter@stuge.se> Signed-off-by: Fabian Groffen <grobian@gentoo.org>
-rw-r--r--qmerge.c52
1 files changed, 49 insertions, 3 deletions
diff --git a/qmerge.c b/qmerge.c
index 36d3596..6d98329 100644
--- a/qmerge.c
+++ b/qmerge.c
@@ -1231,13 +1231,59 @@ pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
* Since some tools (e.g. zstd) complain about the .bz2
* extension, we feed the tool by input redirection. */
snprintf(buf, sizeof(buf),
- BUSYBOX " sh -c 'dd status=none if=%s bs=1 count=%d %s%s | "
+ BUSYBOX " sh -c '%s%s"
"tar -x%sf - -C image/'",
- tbz2, tbz2size, compr[0] == '\0' ? "" : "| ", compr,
+ compr, compr[0] == '\0' ? "" : " | ",
((verbose > 1) ? "v" : ""));
+ /* start the tar pipe and copy tbz2size binpkg bytes into it
+ * "manually" rather than depending on dd or head */
+ {
+ FILE *tarpipe, *tbz2f;
+ unsigned char iobuf[8192];
+ int piped = 0;
+ size_t n, rd, wr;
+
+ tarpipe = popen(buf, "w");
+ if (NULL == tarpipe)
+ errp("popen(%s)", buf);
+
+ tbz2f = fopen(tbz2, "r");
+ if (NULL == tbz2f)
+ errp("fopen(%s)", tbz2);
+
+ for (piped = wr = 0; piped < tbz2size; piped += wr) {
+ n = MIN(tbz2size - piped, (ssize_t)sizeof iobuf);
+ rd = fread(iobuf, 1, n, tbz2f);
+ if (0 == rd) {
+ errno = ferror(tbz2f);
+ if (errno)
+ errp("fread(%s)", tbz2);
+
+ if (feof(tbz2f))
+ err("%s: unexpected EOF; corrupted binpkg", tbz2);
+ }
+
+ for (wr = n = 0; wr < rd; wr += n) {
+ n = fwrite(iobuf + wr, 1, rd - wr, tarpipe);
+ if (n != rd - wr) {
+ errno = ferror(tarpipe);
+ if (errno)
+ errp("fwrite(%s)", buf);
+
+ if (feof(tarpipe))
+ err("%s pipe: unexpected EOF", buf);
+ }
+ }
+ }
+
+ fclose(tbz2f);
+
+ if (-1 == pclose(tarpipe))
+ errp("pclose(%s)", buf);
+ }
+
free(tbz2);
- xsystem(buf);
fflush(stdout);
eat_file("vdb/DEFINED_PHASES", &phases, &phases_len);