A tar file created by toybox tar with values large enough to need
base-256 rather than ASCII octal caused a tar reader to crash, and
caused GNU tar to complain.

I note from the docs at
https://github.com/libarchive/libarchive/blob/master/libarchive/tar.5#L326
that they imply that only the top *bit* should be set to indicate this
format, not the whole top byte, to give a 95-bit or 63-bit field. But I
don't think we can hit that in practice?

Bug: http://b/181683612
---
 tests/tar.test   |  5 +++++
 toys/posix/tar.c | 17 ++++++++++++-----
 2 files changed, 17 insertions(+), 5 deletions(-)
From ba28a4450e306fa16678a2703960b582671528ed Mon Sep 17 00:00:00 2001
From: Elliott Hughes <[email protected]>
Date: Mon, 8 Mar 2021 09:47:54 -0800
Subject: [PATCH] tar: fix base-256 output.

A tar file created by toybox tar with values large enough to need
base-256 rather than ASCII octal caused a tar reader to crash, and
caused GNU tar to complain.

I note from the docs at
https://github.com/libarchive/libarchive/blob/master/libarchive/tar.5#L326
that they imply that only the top *bit* should be set to indicate this
format, not the whole top byte, to give a 95-bit or 63-bit field. But I
don't think we can hit that in practice?

Bug: http://b/181683612
---
 tests/tar.test   |  5 +++++
 toys/posix/tar.c | 17 ++++++++++++-----
 2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/tests/tar.test b/tests/tar.test
index 4b2f2120..70668c9c 100644
--- a/tests/tar.test
+++ b/tests/tar.test
@@ -59,6 +59,11 @@ skipnot id nobody >/dev/null
 testing "pass group" "tar c --owner root --group nobody --mtime @0 file | LST" \
   "-rw-rw-r-- root/nobody 0 1970-01-01 00:00 file\n" "" ""
 
+# Historically we output a "base 256" format that _we_ could decode but that
+# GNU tar choked on, so check the exact bytes with SUM, not a LST round trip.
+testing "huge values" "tar c --owner 9999999 --group 8888888 --mtime @0 file | SUM 3" \
+  "396b07fd2f80eeb312462e3bfb7dc1325dc6bcfb\n" "" ""
+
 touch -t 198701231234.56 file
 testing "pass mtime" \
   "tar c --owner root --group root file | LST --full-time" \
diff --git a/toys/posix/tar.c b/toys/posix/tar.c
index f31640c5..25dfc167 100644
--- a/toys/posix/tar.c
+++ b/toys/posix/tar.c
@@ -85,14 +85,19 @@ struct tar_hdr {
        prefix[155], padd[12];
 };
 
+// Tar uses ASCII octal when it fits, base-256 otherwise.
+#define ASCII_FITS(val, len) (!(val>>(3*(len-1))))
 // convert from int to octal (or base-256)
 static void itoo(char *str, int len, unsigned long long val)
 {
-  // Do we need binary encoding?
-  if (!(val>>(3*(len-1)))) sprintf(str, "%0*llo", len-1, val);
+  if (ASCII_FITS(val, len)) sprintf(str, "%0*llo", len-1, val);
   else {
+    str += len;
+    while (len--) {
+      *--str = val;
+      val >>= 8;
+    }
     *str = 128;
-    while (--len) *++str = val>>(3*len);
   }
 }
 #define ITOO(x, y) itoo(x, sizeof(x), y)
@@ -288,9 +293,11 @@ static int add_to_tar(struct dirtree *node)
   if (strlen(hname) > sizeof(hdr.name)) write_longname(hname, 'L');
 
   if (!FLAG(numeric_owner)) {
-    if (TT.owner || (pw = bufgetpwuid(st->st_uid)))
+    if ((TT.owner || (pw = bufgetpwuid(st->st_uid))) &&
+        ASCII_FITS(st->st_uid, sizeof(hdr.uid)))
       strncpy(hdr.uname, TT.owner ? TT.owner : pw->pw_name, sizeof(hdr.uname));
-    if (TT.group || (gr = bufgetgrgid(st->st_gid)))
+    if ((TT.group || (gr = bufgetgrgid(st->st_gid))) &&
+        ASCII_FITS(st->st_gid, sizeof(hdr.gid)))
       strncpy(hdr.gname, TT.group ? TT.group : gr->gr_name, sizeof(hdr.gname));
   }
 
-- 
2.30.1.766.gb4fecdf3b7-goog

_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to