I noticed there’s a common anti-pattern in some PKGBUILDs, the short scripts that are used to build Arch Linux packages. Specifically we’re looking at the part that references the source code used when building a package:

source=("git+https://github.com/alacritty/alacritty.git#tag=v${pkgver}?signed")
validpgpkeys=('4DAA67A9EA8B91FCC15B699C85CDAE3C164BA7B4'
              'A56EF308A9F1256C25ACA3807EA8F8B94622A6A9')
sha256sums=('SKIP')

This does:

  • authentication: verify the git tag was signed by one of the two trusted keys.
  • pinning: the source code is not pinned and git tags are not immutable, upstream could create a new signed git tag with an identical name and arbitrarily change the source code without the PKGBUILD noticing.

In contrast consider this PKGBUILD:

source=($pkgname-$pkgver.tar.gz::https://github.com/alacritty/alacritty/archive/refs/tags/v$pkgver.tar.gz)
sha256sums=('e48d4b10762c2707bb17fd8f89bd98f0dcccc450d223cade706fdd9cfaefb308')
  • authentication: there’s no signature, so this PKGBUILD doesn’t cryptographically verify authorship.
  • pinning: the source code is cryptographically pinned, it’s addressing the source code by it’s content. There’s nothing upstream can do to silently change the code used by this PKGBUILD.

Personally - if I had to decide between these two - I’d prefer the later because I can always try to authenticate the pinned tarball later on, but it’s impossible to know for sure which source code has been used if all I know is “something that had a valid signature on it”. This set could be infinitely large for all we know!

But is there a way to get both? Consider this PKGBUILD:

makedepends=('auth-tarball-from-git')
source=($pkgname-$pkgver.tar.gz::https://github.com/alacritty/alacritty/archive/refs/tags/v$pkgver.tar.gz
        chrisduerr.pgp
        kchibisov.pgp)
sha256sums=('e48d4b10762c2707bb17fd8f89bd98f0dcccc450d223cade706fdd9cfaefb308'
            '19573dc0ba7a2f003377dc49986867f749235ecb45fe15eb923a74b2ab421d74'
            '5b866e6cb791c58cba2e7fc60f647588699b08abc2ad6b18ba82470f0fd3db3b')

prepare() {
  cd "$pkgname-$pkgver"

  auth-tarball-from-git --keyring ../chrisduerr.pgp --keyring ../kchibisov.pgp \
    --tag v$pkgver --prefix $pkgname-$pkgver \
    https://github.com/alacritty/alacritty.git ../$pkgname-$pkgver.tar.gz
}
  • authentication: auth-tarball-from-git verifies the signed git tag and then verifies the tarball has been built from the commit the tag is pointing to.
  • pinning: the source code and the files containing the public keys are cryptographically pinned.

In this case sha256sums= is the primary line of defense against tampering with build inputs and the git tag is “only” used to document authorship.

For more infos on how this works you can have a look at the auth-tarball-from-git repo, there’s also a section about attacks on signed git tags that you should probably know about.

Thanks

This work is currently crowd-funded on github sponsors. I’d like to thank @SantiagoTorres, @repi and @rgacogne for their support in particular. ♥️