From 902bc55c4d2bc152ce0529b1df81bf51da2c9fd3 Mon Sep 17 00:00:00 2001 From: Johannes Schauer Marin Rodrigues Date: Wed, 31 Aug 2022 05:35:40 +0200 Subject: [PATCH] tarfilter --idshift now provides taridshift --- coverage.py | 1 - coverage.txt | 2 +- tarfilter | 20 +++++- taridshift | 67 ------------------- .../{taridshift-utility => tarfilter-idshift} | 12 ++-- 5 files changed, 26 insertions(+), 76 deletions(-) delete mode 100755 taridshift rename tests/{taridshift-utility => tarfilter-idshift} (84%) diff --git a/coverage.py b/coverage.py index 8403694..81ed03e 100755 --- a/coverage.py +++ b/coverage.py @@ -96,7 +96,6 @@ def main(): # copy over files from git or as distributed for (git, dist, target) in [ ("./mmdebstrap", "/usr/bin/mmdebstrap", "mmdebstrap"), - ("./taridshift", "/usr/bin/mmtaridshift", "taridshift"), ("./tarfilter", "/usr/bin/mmtarfilter", "tarfilter"), ( "./proxysolver", diff --git a/coverage.txt b/coverage.txt index 88ac992..5aceec4 100644 --- a/coverage.txt +++ b/coverage.txt @@ -52,7 +52,7 @@ Skip-If: fmt == "squashfs" and dist == "oldstable" # squashfs-tools-ng is not available fmt == "ext2" and dist == "oldstable" # genext2fs does not support SOURCE_DATE_EPOCH -Test: taridshift-utility +Test: tarfilter-idshift Needs-QEMU: true Skip-If: dist == "oldstable" # python3 tarfile module does not preserve xattrs diff --git a/tarfilter b/tarfilter index f6ebf38..4614026 100755 --- a/tarfilter +++ b/tarfilter @@ -68,7 +68,10 @@ Both types of options use Unix shell-style wildcards: Thirdly, strip leading directory components off of tar members. Just as with GNU tar --strip-components, tar members that have less or equal components in their path are not passed through. -""" + +Lastly, shift user id and group id of each entry by the value given by the +--idshift argument. The resulting uid or gid must not be negative. +""", ) parser.add_argument( "--path-exclude", @@ -100,6 +103,12 @@ their path are not passed through. type=int, help="Strip NUMBER leading components from file names", ) + parser.add_argument( + "--idshift", + metavar="NUM", + type=int, + help="Integer value by which to shift the uid and gid of each entry", + ) args = parser.parse_args() if ( not hasattr(args, "pathfilter") @@ -165,6 +174,15 @@ their path are not passed through. for k, v in member.pax_headers.items() if not pax_filter_should_skip(k) } + if args.idshift: + if args.idshift < 0 and -args.idshift > member.uid: + print("uid cannot be negative", file=sys.stderr) + exit(1) + if args.idshift < 0 and -args.idshift > member.gid: + print("gid cannot be negative", file=sys.stderr) + exit(1) + member.uid += args.idshift + member.gid += args.idshift if member.isfile(): with in_tar.extractfile(member) as file: out_tar.addfile(member, file) diff --git a/taridshift b/taridshift deleted file mode 100755 index bfcd665..0000000 --- a/taridshift +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python3 -# -# This script is in the public domain -# -# Author: Johannes Schauer Marin Rodrigues -# -# This script accepts a tarball on standard input and prints a tarball on -# standard output with the same contents but all uid and gid ownership -# information shifted by the value given as first command line argument. -# -# A tool like this should be written in C but libarchive has issues: -# https://github.com/libarchive/libarchive/issues/587 -# https://github.com/libarchive/libarchive/pull/1288/ (needs 3.4.1) -# Should these issues get fixed, then a good template is tarfilter.c in the -# examples directory of libarchive. -# -# We are not using Perl either, because Archive::Tar slurps the whole tarball -# into memory. -# -# We could also use Go but meh... -# https://stackoverflow.com/a/59542307/784669 - -import tarfile -import sys -import argparse - - -def main(): - parser = argparse.ArgumentParser( - description="""\ -Accepts a tarball on standard input and prints a tarball on standard output -with the same contents but all uid and gid ownership information shifted by the -value given as first command line argument. -""" - ) - parser.add_argument( - "idshift", - metavar="NUM", - type=int, - help="Integer value by which to shift the uid and gid of each entry", - ) - args = parser.parse_args() - - # starting with Python 3.8, the default format became PAX_FORMAT, so this - # is only for compatibility with older versions of Python 3 - with tarfile.open(fileobj=sys.stdin.buffer, mode="r|*") as in_tar, tarfile.open( - fileobj=sys.stdout.buffer, mode="w|", format=tarfile.PAX_FORMAT - ) as out_tar: - for member in in_tar: - if args.idshift < 0 and -args.idshift > member.uid: - print("uid cannot be negative", file=sys.stderr) - exit(1) - if args.idshift < 0 and -args.idshift > member.gid: - print("gid cannot be negative", file=sys.stderr) - exit(1) - - member.uid += args.idshift - member.gid += args.idshift - if member.isfile(): - with in_tar.extractfile(member) as file: - out_tar.addfile(member, file) - else: - out_tar.addfile(member) - - -if __name__ == "__main__": - main() diff --git a/tests/taridshift-utility b/tests/tarfilter-idshift similarity index 84% rename from tests/taridshift-utility rename to tests/tarfilter-idshift index a945d6a..303b093 100644 --- a/tests/taridshift-utility +++ b/tests/tarfilter-idshift @@ -10,12 +10,12 @@ adduser --gecos user --disabled-password user echo user:100000:65536 | cmp /etc/subuid - echo user:100000:65536 | cmp /etc/subgid - sysctl -w kernel.unprivileged_userns_clone=1 -# include iputils-ping so that we can verify that taridshift does not remove +# include iputils-ping so that we can verify that tarfilter does not remove # extended attributes # run through tarshift no-op to create a tarball that should be bit-by-bit -# identical to a round trip through "taridshift X" and "taridshift -X" +# identical to a round trip through "tarfilter --idshift X" and "tarfilter --idshift -X" runuser -u user -- {{ CMD }} --mode=unshare --variant=apt --include=iputils-ping {{ DIST }} - {{ MIRROR }} \ - | ./taridshift 0 > /tmp/debian-chroot.tar + | ./tarfilter --idshift 0 > /tmp/debian-chroot.tar # make sure that xattrs are set in the original tarball mkdir /tmp/debian-chroot tar --xattrs --xattrs-include='*' --directory /tmp/debian-chroot -xf /tmp/debian-chroot.tar ./bin/ping @@ -25,9 +25,9 @@ rm /tmp/debian-chroot/bin/ping rmdir /tmp/debian-chroot/bin rmdir /tmp/debian-chroot # shift the uid/gid forward by 100000 and backward by 100000 -./taridshift 100000 < /tmp/debian-chroot.tar > /tmp/debian-chroot-shifted.tar -./taridshift -100000 < /tmp/debian-chroot-shifted.tar > /tmp/debian-chroot-shiftedback.tar -# the tarball before and after the roundtrip through taridshift should be bit +./tarfilter --idshift 100000 < /tmp/debian-chroot.tar > /tmp/debian-chroot-shifted.tar +./tarfilter --idshift -100000 < /tmp/debian-chroot-shifted.tar > /tmp/debian-chroot-shiftedback.tar +# the tarball before and after the roundtrip through tarfilter should be bit # by bit identical cmp /tmp/debian-chroot.tar /tmp/debian-chroot-shiftedback.tar # manually adjust uid/gid and compare "tar -t" output