Timely delivery of security updates
Yesterday, a new version of OpenSSL was released, addressing several serious vulnerabilities, some of which are nicknamed "DROWN". Like all free software distributions, we were waiting to deploy the fixes as soon as possible. This time though, we are happy to report that we were able to deploy it to users faster than before: an hour or so after disclosure. This was made possible by fixing our fast update deployment mechanism, which is based on grafts.
Updates in a functional package management framework
GNU Guix implements the functional package management discipline. What this means is that the the package graph in Guix is an immutable, persistent data structure—similar to a singly-linked list in a functional programming language, or to the object graph in the Git version control system.
A common difficulty with persistent data structures is the algorithmic complexity of updates—the computational cost of updating an arbitrary element of the data structure. For instance, to update the nth element of a singly-linked list, you first need to traverse and copy the n ? 1 elements at the head of the list, then insert the new element and make it point to the tail of the list.
With the functional package management paradigm, the cost of updating a package is simple to understand: you need to rebuild the package itself, and all the packages that depend on it. This is nice in many ways: all packages must build from source, there is no way we can be using binaries that cannot be rebuilt from their Corresponding Source, breakage due to incompatible application binary interfaces (ABIs) is foreign to our users, we have a precise trail of the tools that produced binaries—that is, builds are “referentially transparent”, and as a bonus, we get features such as transactional upgrades and rollbacks, peaceful coexistence of different variants of the same package, and more.
But obviously, this update cost is very high when all you want is to deliver an important security update in a core package. Regarding yesterday’s update, guix refresh -l openssl shows that 2,115 packages depend on OpenSSL. On top of that, Guix supports 4 architectures, so needless to say, rebuilding everything that depends on OpenSSL would take time. Sure, users do not have to wait for pre-built binaries and can instead build just what they need locally; in practice, they’d better have a powerful machine, though.
Grafting important updates
A solution to this problem has been floating around for some time: the idea is to graft important package updates onto packages that depend on it. That way, we would rebuild OpenSSL, but all we need to do for packages that depend on OpenSSL is to substitute the reference to the “broken” OpenSSL with a reference to the security update, with the understanding that this substitution process is orders of magnitude cheaper than rebuilding packages, and faster than redownloading rebuilt packages.
Shea Levy had implemented a form of grafting in Nixpkgs in 2013, and Guix itself has provided the infrastructure for grafted updates since version 0.8 in 2014. With Guix, package developers simply have to define a replacement in the object representing the package that needs an update and the tools automatically pick the replacement and graft it onto packages as needed.
The problem is that these implementations had a severe limitation, described in this bug report: grafting was not recursive. When we provided a patched OpenSSL to be grafted, any package that directly depended on OpenSSL, would be appropriately grafted to refer to the new OpenSSL. However, if a package depended on libfoo, which in turn depended on OpenSSL, then that package would keep referring to the old libfoo, which refered to the old OpenSSL. That made grafts useless in most situations.
This bug was finally addressed, just in time for yesterday’s OpenSSL update. We have identified things to improve, but overall, it has worked pretty well. It has worked so well that we even experienced our first ABI break like all realdistros!
From now on, we have confidence that we can deliver important updates quickly using grafts, and happily rebuild the world in the background, whenever is convenient. This is an important improvement for functional package management to keep our users happy and safe.
About GNU Guix
GNU Guix is a functional package manager for the GNU system. The Guix System Distribution or GuixSD is an advanced distribution of the GNU system that relies on GNU Guix and respects the user's freedom.
In addition to standard package management features, Guix supports transactional upgrades and roll-backs, unprivileged package management, per-user profiles, and garbage collection. Guix uses low-level mechanisms from the Nix package manager, except that packages are defined as native Guile modules, using extensions to the Scheme language. GuixSD offers a declarative approach to operating system configuration management, and is highly customizable and hackable.
GuixSD can be used on an i686 or x86_64 machine. It is also possible to use Guix on top of an already installed GNU/Linux system, including on mips64el and armv7.
Похожие темы:Functional programming Security
Unless otherwise stated, blog posts on this site are copyrighted by their respective authors and published under the terms of the CC-BY-SA 4.0 license and those of the GNU Free Documentation License (version 1.3 or later, with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts).