可复制且仅限源的tarball

使用Libntlm版本1.8的发布发布tarball可以在多个发行版上复制。我们还发布了一个由git存档与使用的格式相同大草原,Codeberg公司,GitLab公司,github和其他。测试了两种柏油球的再现性持续进行回归通过CI/CD管道在GitLab上运行。如果这还不足以让你兴奋Libntlm的Debian包现在是从可复制的最小源代码tarball构建的。生成的二进制文件是可复制的在多个架构上。

这意味着什么?你为什么要在乎?你如何能为你的项目做同样的事情?存在哪些未决问题?亲爱的读者,继续读下去…

本文描述了我对可复制发布工件的实际实验我早先的想法导致关于化石的讨论和aJanneke Nieuwenhuizen制作的补丁,使吉他柏油球可重复使用这启发了我做一些实际工作。

让我们看看维护人员如何发布一些软件,以及用户如何从源代码中重现发布的工件。Libntlm提供了一个用C编写的共享库,并使用GNU品牌,GNU自动控制,可移植的源代码,GNU库工具格努利布对于构建管理,但这些思想应适用于大多数项目和构建系统。以下说明了维护人员准备发布所需的步骤:

git克隆https://gitlab.com/gsasl/libntlm.git光盘库git校验v1.8./引导./配置进行分发检查gpg-b libntlm-1.8tar.gz

生成的文件libntlm-1.8tar.gz银行libntlm-1.8.tar.gz.sig公司发布,用户下载并使用它们。这就是如何GNU项目自20世纪80年代末以来一直在发行。这证明了这种模式是多么成功!这些tarball包含源代码和一些生成的文件,通常是autoconf生成的shell脚本、automake生成的makefile模板、以下格式的文档信息、HTML或PDF。它们很少包含二进制目标代码,但历史上确实如此。

这个XZUtils事件说明包含git存档中未包含的文件的tarball提供了伪装恶意后门的机会。早些时候写过博客如何通过使用签名的最小源代码tarball来降低此风险。

隐藏恶意软件的风险并不是发布签名的最小源代码tarball的唯一动机。使用tarball中预先生成的内容,存在以下风险GNU/Linux发行版例如Trisquel公司,吉他,Debian公司/Ubuntu公司费多拉将从tarball生成的文件发送到二进制文件*.deb(代布)*.转/分程序包文件。通常,打包上游项目的人从未意识到,一些安装的工件并不是通过典型的autoconf-fi和&/配置并进行安装序列,并且从未编写代码来重建所有内容。如果构建规则被编写但有缺陷,并且运送了旧的工件,也会发生这种情况。当发现安全问题时,这可能会导致耗时的情况,因为修补相关源代码并重新构建包可能是不够的:从tarball生成的易受攻击的对象将被发送到二进制包中,而不是重新构建的工件中。对于特定于体系结构的二进制文件,这种情况很少发生,因为目标代码通常不包含在tarballs中,尽管十多年来我在GNU图书馆释放tarball,直到我停止运输对于解释语言,尤其是生成的内容,如HTML、PDF、shell脚本,这种情况发生得比您希望的要多。

发布最小的源代码tarball可以更容易地审核项目代码,从而避免需要通读所有生成的文件以查找恶意内容。我已经使用生成了源代码的最小tarballgit存档这与GitLab、GitHub等为git标签上的自动下载链接提供的格式相同。因此,最小的源代码tarball可以作为审核GitLab和GitHub下载材料的一种方式!考虑GitLab或GitHub等托管站点是否/何时发生安全事件,导致生成的tarball包含git存储库中不存在的后门。如果人们依赖标签下载工件而没有使用验证维护者PGP签名保密性卫兵这可能会导致类似于XZUtils的后门场景,但最初是由宿主提供商而不是发布管理器创建的。这更令人担忧,因为此攻击可能针对某些选定的IP地址,而不是针对所有人,因此很难发现。

在所有这些讨论和基本原理都解决之后,让我们回到发布过程。我在这里添加了另一个步骤:

制作srcdistgpg-b库ntlm-1.8-src.tar.gz

现在发布准备就绪。我将这四个文件发布在Libntlm的Savannah下载区,但它们也可以上传到GitLab/GitHub发布区。这些是在我的计算机上构建tarball后得到的SHA256校验和Trisquel 11 aramo笔记本电脑以下为:

91de864224913b9493c7a6cec2890e6eded3610d34c3d983132823de348ec2ca libntlm-1.8-src.tar.gzce6569a47a21173ba69c990965f73eb82d9a093eb871f935ab64ee13df47fda1 libntlm-1.8tar.gz

那么你怎么能复制我的文物呢?以下是如何在Ubuntu 22.04容器中复制它们:

播客运行它--rm ubuntu:22.04更新源apt-get安装-y--无安装-推荐autoconf automake libtool生成git ca证书git克隆https://gitlab.com/gsasl/libntlm.git网站光盘libntlmgit校验v1.8./引导./配置生成dist srcdist沙256sum libntlm-*.tar.gz

您应该会看到完全相同的SHA256校验和值。万岁!

这是因为Trisquel 11和Ubuntu 22.04使用了相同版本的git、autoconf、automake和libtool。这些工具并不能保证所有版本的输出内容相同GNU通用条款不会为所有版本生成相同的二进制输出。所以仍然需要一些微妙的版本配对。

理想情况下,工件应该可以从发布工件本身复制,而不仅仅是直接从git复制。可以在AlmaLinux公司8个容器–更换almalinux:8具有rockylinux:8如果你愿意RockyLinux以下为:

podman run-it--rm almalinux:8dnf更新-ydnf安装-y make wget gccwget公司https://download.savannah.nongu.org/releases/libntlm/libntlm-1.8tar.gz焦油xfa libntlm-1.8tar.gz光盘libntlm-1.8./配置制造距离沙256sum libntlm-1.8tar.gz

可以在上重新生成仅源的最小tarballDebian 11号机组以下为:

播客运行--rm debian:11更新源apt-get安装-y--无安装-建议生成git ca证书git克隆https://gitlab.com/gsasl/libntlm.git网站光盘库git结账v1.8make-f cfg.mk srcdist沙256sum libntlm-1.8-src.tar.gz

作为Magnus Opus或chef-d'œuvre,让我们直接从Trisquel 11上的最小源代码tarball重新创建完整的tarball–replacedocker.io/kpengboy/trisquel:11.0具有乌班图:22.04如果你愿意的话。

podman-run-it-rm docker.io/kpengboy/trisquel:11.0更新源apt-get安装-y--无安装-推荐autoconf automake libtool生成wget-git ca证书wget公司https://download.savannah.nongu.org/releases/libntlm/libntlm-1.8-src.tar.gztar xfa libntlm-1.8-src.tar.gz数据库光盘libntlm-v1.8./引导./配置制造距离sha256和libntlm-1.8.tar.gz

耶!现在,您应该非常确信,发布工件与版本控制中的内容以及维护者打算发布的内容相对应。剩下的工作是审核源代码中的漏洞,包括构建中使用的依赖项的源代码。您不再需要担心审核发布工件。

我觉得有点有趣的是,Libntlm的构建基础设施现在比代码本身要好得多。Libntlm是用旧C风格编写的,有大量的字符串操作,并使用了破解的加密算法,例如MD4公司单一DES记住各位:解决供应链安全问题与您最终运行的代码类型无关。一支干净的枪仍然可以射中你的脚。

关于命名的旁注:GitLab使用路径名导出tarballlibntlm-v1.8型/(即。。,TAG项目/)我采用了相同的路径名,这意味着我的libntlm-1.8-src.tar.gz数据库tarball与GitLab的导出完全相同,您可以使用以下工具进行验证差速器GitLab命名tarballlibntlm-v1.8.tar.gz数据库(即。,项目-标签。档案文件)我发现它与libntlm-1.8tar.gz银行我们也发布了。GitHub使用相同的git存档样式,但不幸的是,它们的逻辑删除了路径名中的“v”,因此您将得到一个带有路径名的tarball伦敦银行-1.8/而不是libntlm-v1.8型/我和GitLab使用的。tarball的内容是逐位相同的,但路径名和存档不同。Codeberg(正在运行福吉乔)使用另一种方法:tarball被称为libntlm-v1.8.tar.gz数据库(在标记之后)就像GitLab一样,但归档文件中的路径名是利本特姆/,否则生成的存档将逐位相同,包括时间戳。萨凡纳的CGIT接口使用存档名称libntlm-1.8.tar.gz具有路径名伦敦银行-1.8/,否则文件内容相同。萨凡纳的GitWeb接口提供以git提交命名的快照链接(例如。,libntlm-a812c2ca.tar.gz公司具有libntlm-a812c2ca公司/)我根本找不到任何基于标记的下载链接。总的来说,我们非常接近于使SHA256校验和匹配,但在存档中的路径名上失败。我选择与GitLab兼容tarball的内容,但不兼容存档命名。从简单的角度来看,如果每个人都使用项目-标签。档案文件用于存档文件名和TAG项目/用于存档中的路径名。这方面可能需要更多讨论。

关于git存档输出的旁注:它似乎是不同版本的git存档为同一存储库生成不同的结果。Debian 11、Trisquel 11和Ubuntu 22.04中git的版本表现相同。Debian 12中的git版本、AlmaLinux/RockyLinux 8/9、Alpine、ArchLinux、macOS自制软件和即将推出的Ubuntu 24.04都有另一种表现。希望这不会经常发生变化,但这会使这些tarball在未来的再现性失效,迫使您使用旧的git发行版来重现源代码tarball。唉,GitLab和大多数其他网站似乎都在使用现代git,因此从他们那里下载的tarball与我的tarballs不匹配,即使内容会匹配。

ChangeLog上的旁注:ChangeLog文件通常是手动管理的文件,带有包的版本历史记录。近年来,一些项目开始从git历史动态生成它们(使用诸如吉特2clgitlog到changelog). 这会影响tarball的可再现性:您需要有完整的git历史记录!这个gitlog到changelog工具也输出不同的输出取决于时区这是一个可以修复的简单错误。然而,这整个方法与从最小的源tarball重建完整的tarball不兼容。看起来Libntlm的ChangeLog文件死于手术台在这里。

那么,发行版如何构建这些最小的纯源tarball呢?我碰巧在Debian中的libntlm包它历史上使用生成的tarball作为构建源代码。这意味着来自gnulib的代码将在tarball中出售。当在gnulib代码中发现安全问题时,安全团队需要修补包含该供应商代码的所有包并重新构建它们,而不仅仅是修补gnulib-包并重新生成依赖于该特定代码的所有程序包。为了改变这一点,Debian libntlm包需要Build-DependsDebian的gnulib包但有一个问题:与大多数使用gnulib的项目类似,Libntlm依赖于gnulib的特定git提交,而Debian只提供一个提交。对于要使用哪个提交,没有进行协调。已经采用了gnulib在Debian中,并添加git束*_所有.deb二进制包,以便依赖gnulib的项目可以选择他们需要的任何提交。这允许无网络GNULIB_URLGNULIB_修订运行Libntlm时的方法./引导程序安装了Debian gnulib包。否则,libntlm将获取Debian在gnulib包中碰巧拥有的任何最新版本的gnuib,而这并不是libntlm维护者想要使用的,并且随着时间的推移,可能会导致各种版本不匹配(从而导致安全问题)。Debian中的Libntlm是在Salsa上开发和测试的而且有持续集成测试感谢Salsa CI团队

关于git包的旁注:不幸的是,似乎没有可复制的方法将git存储库导出到一个或多个文件中。因此,所有这些工作的一个不幸后果是gnulib*.orig.tar.gz(原始目标.gz)Debian中的tarball不再可复制。我有已尝试使Git包可复制,但我从未使其工作-请参阅中的注释gnulib的debian/README.source在这方面。当然,源tarball再现性与二进制无关gnulib在Debian中的可再现性幸运的是,它本身。

一个悬而未决的问题是如何处理由这种方法触发的增加的构建依赖性。一些人们感到惊讶通过这种方式,但我不知道如何绕过它:如果您依赖另一个包中工具的源代码来构建您的包,那么隐藏这种依赖性是一个坏主意。很长一段时间以来,我们都是通过非最小tarball中的供应商代码来实现的。从引导的角度来看,Libntlm不是最关键的项目,因此添加git和gnulib作为构建依赖项这样可能很好。然而,考虑一下此模式是否用于其他使用gnulib的包,例如coreutils公司,gzip公司,焦油,野牛etc(都在使用gnulib),那么他们都会构建依赖项关于git和gnulib。因此,为新体系结构交叉构建这些包需要首先在该体系结构上使用git,这样可以快速循环。对gnulib的依赖是真实的,所以我不认为它会消失,而gnulab是一个架构:全部包裹。然而,对git的依赖仅仅是Debian-gnulib包如何选择使所有gnulib-git提交对项目可用的结果:通过git包。还有其他方法可以做到这一点,它不需要git工具来提取必要的文件,但我发现没有一种方法是可行的——欢迎提出想法!

最后是关于如何实现这一点的简要说明。通过gnulib实现可引导的源代码最小化tarball./引导程序通过使用GNULIB_修订机制,锁定使用的gnulib提交。我一直不喜欢git子模块,因为它们添加了额外的步骤,并且与CI/CD有复杂的交互放弃git子模块现在是因为要使用的特定提交没有记录在git存档使用git子模块时的输出。因此,必须在git存档tarball中的一些源代码中明确提到特定的gnulib提交。科林·沃森添加了GNULIB_REVISION接近./引导回到2018年,现在继续使用gnulib-git子模块已经没有意义了。一种替代方法是使用./引导具有--gnulib-srcdir公司--gnulib-refdir如果有一些实际问题GNULIB_URL朝向git捆绑包GNULIB_修订在里面引导.conf

这个srcdist生成规则很简单:

git存档--前缀=libntlm-v1.8/-o libntlm-1.8-src.tar.gz HEAD

制作制造距离生成的可复制tarball可能更复杂,但对于Libntlm来说,这足以确保所有文件的修改时间都是确定的到git存储库中最后一次提交的时间戳。有趣的是,似乎有两种不同的方法可以实现这一点,Guix不支持最小源代码tarball,但依靠.tarball时间戳tarball中的文件。保罗·艾金特解释了TZDB正在使用的内容不久前。这个我现在使用的方法我建议的一个一年多以前。如果由于tarball中的所有文件现在使用相同的修改时间而出现问题布鲁诺·海布尔的解决方案这是可以实现的。

关于git标签的旁注:有些人可能想知道为什么不验证签名的git标签,而不是验证git存档的签名tarball。目前大多数git存储库使用SHA-1作为git提交标识,但是SHA-1不是安全哈希函数。虽然可以检测和缓解当前的SHA-1攻击,但人们基本上怀疑git SHA-1提交标识唯一地引用了预期的相同内容。验证git标记永远不会提供相同的保证,因为git标记可以随时移动或重新指定。验证git提交更好,但我们需要信任SHA-1。正在迁移git至SHA-256将解决此问题,但大多数托管站点(如GitLab和GitHub)尚不支持此功能。使用签名tarball代替签名git提交或git标记还有其他优点,例如。,焦油.gz可以是一种可确定复制的持久稳定脱机存储格式,但.git(单位:吉特)子目录树或git捆绑包不要提供此属性。

对所有这些进行持续测试对于确保事情不会倒退至关重要。Libntlm的管道定义现在生成生成的libntlm-*.tar.gz数据库tarball和校验和作为构建工件。然后我添加了000可再生产性比较校验和并在不匹配时失败的作业。你可以阅读它v1.8工作中的精细输出释放。现在,我们坚持认为Trisquel 11的构建与Ubuntu 22.04相匹配,PureOS 10的构建与Debian 11的构建相匹配,AlmaLinux 8的构建与RockyLinux 8的建立相匹配,而AlmaLinux 9的构建与LockyLinux 9的建设相匹配。正如您可以在管道作业输出中看到的那样,并非所有平台都会导致相同的tarball,但希望这种状态可以随着时间的推移得到改善。还存在部分再现性,其中完整的tarball可以跨两个分布进行再现,但最小tarball不可以,反之亦然。

如果这种工作方式效果很好,我希望也能在其他项目中实施。

你怎么认为?快乐黑客!

对“可复制且仅限于源代码的tarballs”的一个答复

  1. Pingback:走向可复制的最小源代码tarball?On*-src.tar.gz–Simon Josefsson的博客

留下回复

您的电子邮件地址将不会被发布。 已标记必填字段*

*