Occasionally, important security vulnerabilities are discovered in software
packages and must be patched. Guix developers try hard to keep track of
known vulnerabilities and to apply fixes as soon as possible in the
master branch of Guix (we do not yet provide a “stable” branch
containing only security updates). The
guix lint tool helps
developers find out about vulnerable versions of software packages in the
$ guix lint -c cve gnu/packages/base.scm:652:2: email@example.com: probably vulnerable to CVE-2015-1781, CVE-2015-7547 gnu/packages/gcc.scm:334:2: firstname.lastname@example.org: probably vulnerable to CVE-2015-5276 gnu/packages/image.scm:312:2: email@example.com: probably vulnerable to CVE-2016-1923, CVE-2016-1924 …
See Invoking guix lint, for more information.
Guix follows a functional package management discipline (see Introduction), which implies that, when a package is changed, every package that depends on it must be rebuilt. This can significantly slow down the deployment of fixes in core packages such as libc or Bash, since basically the whole distribution would need to be rebuilt. Using pre-built binaries helps (see Substitutes), but deployment may still take more time than desired.
To address this, Guix implements grafts, a mechanism that allows for fast deployment of critical updates without the costs associated with a whole-distribution rebuild. The idea is to rebuild only the package that needs to be patched, and then to “graft” it onto packages explicitly installed by the user and that were previously referring to the original package. The cost of grafting is typically very low, and order of magnitudes lower than a full rebuild of the dependency chain.
For instance, suppose a security update needs to be applied to Bash.
Guix developers will provide a package definition for the “fixed”
bash-fixed, in the usual way (see Defining Packages). Then, the original package definition is augmented with a
replacement field pointing to the package containing the bug fix:
(define bash (package (name "bash") ;; … (replacement bash-fixed)))
From there on, any package depending directly or indirectly on Bash—as
guix gc --requisites (see Invoking guix gc)—that is installed is automatically “rewritten” to refer to
bash-fixed instead of
bash. This grafting process takes
time proportional to the size of the package, usually less than a
minute for an “average” package on a recent machine. Grafting is
recursive: when an indirect dependency requires grafting, then grafting
“propagates” up to the package that the user is installing.
Currently, the length of the name and version of the graft and that of
the package it replaces (
bash in the example
above) must be equal. This restriction mostly comes from the fact that
grafting works by patching files, including binary files, directly.
Other restrictions may apply: for instance, when adding a graft to a
package providing a shared library, the original shared library and its
replacement must have the same
SONAME and be binary-compatible.
The --no-grafts command-line option allows you to forcefully avoid grafting (see --no-grafts). Thus, the command:
guix build bash --no-grafts
returns the store file name of the original Bash, whereas:
guix build bash
returns the store file name of the “fixed”, replacement Bash. This allows you to distinguish between the two variants of Bash.
To verify which Bash your whole profile refers to, you can run (see Invoking guix gc):
guix gc -R $(readlink -f ~/.guix-profile) | grep bash
… and compare the store file names that you get with those above. Likewise for a complete Guix system generation:
guix gc -R $(guix system build my-config.scm) | grep bash
Lastly, to check which Bash running processes are using, you can use the
lsof | grep /gnu/store/.*bash