Skip to content

Instantly share code, notes, and snippets.

@stigtsp
Created September 24, 2026 14:58
Show Gist options
  • Select an option

  • Save stigtsp/ee8f0b93ebffd7f5514dc100b4611c1c to your computer and use it in GitHub Desktop.

Select an option

Save stigtsp/ee8f0b93ebffd7f5514dc100b4611c1c to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
set -euo pipefail
umask 077
usage() {
printf 'Usage: %s ARCHIVE.tar[.gz|.bz2|.xz|.zst] [DESTINATION]\n' "${0##*/}" >&2
exit 2
}
die() { printf 'error: %s\n' "$*" >&2; exit 1; }
[[ $# -ge 1 && $# -le 2 ]] || usage
for tool in bwrap tar timeout realpath find; do
command -v "$tool" >/dev/null || die "missing $tool"
done
archive=$(realpath -e -- "$1") || die 'archive does not exist'
[[ -f $archive && -r $archive ]] || die 'archive must be a readable regular file'
case ${1,,} in
*.tar.gz|*.tgz) compressor=(--gzip) ;;
*.tar.bz2|*.tbz2) compressor=(--bzip2) ;;
*.tar.xz|*.txz) compressor=(--xz) ;;
*.tar.zst) compressor=(--zstd) ;;
*.tar) compressor=() ;;
*) die 'unsupported archive suffix' ;;
esac
if [[ $# -eq 2 ]]; then
dest=$2
else
name=${1##*/}
dest=./${name}-extracted
fi
[[ ! -L $dest ]] || die 'destination must not be a symlink'
if [[ ! -e $dest ]]; then
mkdir -m 700 -- "$dest" || die 'cannot create destination'
fi
[[ -d $dest && -w $dest ]] || die 'destination must be a writable directory'
dest=$(realpath -e -- "$dest")
[[ $archive != "$dest/"* ]] || die 'archive is inside destination'
[[ -z $(find "$dest" -mindepth 1 -maxdepth 1 -print -quit) ]] || die 'destination must be empty'
# GNU tar uses external decompressors for compressed archives.
mounts=()
for dir in /usr /bin /lib /lib64; do
[[ ! -d $dir ]] || mounts+=(--ro-bind "$dir" "$dir")
done
# Keep host resources and files outside /out unavailable to the extractor.
# A separate filesystem quota is still needed to cap total output bytes.
if env -i PATH=/usr/bin:/bin LC_ALL=C timeout --signal=TERM --kill-after=5s 60s \
bwrap --unshare-all --die-with-parent --new-session \
"${mounts[@]}" \
--ro-bind "$archive" /archive \
--bind "$dest" /out \
--tmpfs /tmp \
--chdir /out \
/usr/bin/tar --extract "${compressor[@]}" --file=/archive \
--no-same-owner --no-same-permissions \
--no-acls --no-xattrs --no-selinux \
--keep-old-files --no-overwrite-dir --delay-directory-restore; then
printf 'Extracted to: %s\n' "$dest"
else
die "extraction failed; inspect or remove the partial output at $dest"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment