[Nix-dev] CVE-2015-7547 stdenv-changing fix merged on master and 15.09

Kosyrev Serge _deepfire at feelingofgreen.ru
Fri Feb 19 18:30:53 CET 2016


Russell, thank you for this detailed explanation!

If you ask me, it is very much worth a blog post.

roconnor at theorem.ca writes:
> On Tue, 16 Feb 2016, Kosyrev Serge wrote:
>> For those of us who aren't that fluent in Nix idioms -- could you
>> provide a quick summary of how you manage to achieve the seemingly
>> impossible?
>>
>> Normally, one would expect that updating glibc would cause a full system
>> rebuild, but in your case it's obviously not the case.
>
> I'll try my best to explain.  If you are familiar with how you update a tree
> structure in functional programming, the techinque is similar to that.  To update
> a leaf in a tree you trace a path from the root of the tree to the leaf, call this
> path a spine.  You can build a new copy of the tree by updating all the nodes
> along this spine including replacing the leaf with your updated leaf. The result
> is a root of a new tree where unchanged branches are shared with the old tree.
>
> In this case the root is what is built by nixos-rebuild and the tree is the tree
> of dependencies, and glibc is a leaf that needs to be replaced.
>
> Step 1) is to build the orginial unpatch derivation for the system. Usually this
> is the currently running system, so no work needs to be done, but in principle if
> you are making other changes to your configuraiton.nix the unpatched system needs
> to be built.

This need for the unpatched version isn't very clear to me here..

> Step 2) Build the patched glibc.  This is done the normal way.
>
> Step 3) List all the packages that are run-time dependecies of the unpatched
> system and pick out all those packages that either depend, directly or indirectly
> on the unpatched glibc.
>
> Step 4) for each of those packages make a new derivation whose source is the
> output of the deriviation, and which runs a command that finds all the hashes that
> are in that list generated by Step 3 and replaced them with new hashes that are
> being generated in by Step 4.

Is it basically amounting to (for every package depending on glibc):

  1) getting the binary from the old derivation
  2) using patchelf to update a subset of paths hard-coded into it:
     - the fixed glibc
     - the subset of the derivation's direct dependencies that depend on glibc

> (Clearly this step is preformed recursively
> starting at those packaged who directly depend on glibc and then working up to
> those packages that depended on packages that depend on glibc, etc.)
>
> Step 5) Return the new derivation that is has replaced the hashes in the unpatched
> root.
>
> Things to note:
>
> (1) There is nothing impure going on.  The existing store values are never
> mutated.
>
> (2) This only updates packages that have a runtime depenency on glibc. Anything
> that statically links glibc (ie. only has a build-time depenency on glibc) are not
> updated.

Thank you again!

-- 
с уважениeм / respectfully,
Косырев Сергей


More information about the nix-dev mailing list