I'm sharing here for future reference why protected hardlinks alone did not mitigate the recent LPE security advisory, pre-patch:
"The reasons why are lines 2633 and 2637 of nix/libstore/build.cc:
When a package fails to build and the keep failed flag is set (-K/--keep-failed), it runs a recursive chown on the build directory (which is writable following guixbuilder01 changing the permissions to 777). It starts at the top level and chowns downwards.
The first important thing to notice here is that at any point (even pre-chown) the build user has been compromised. The build user can write a SUID /bin/sh to the build path, and because a normal user can traverse into the directory before and during the chown, they can run a SUID shell (allowing them to become guixbuilder01 even after the build user processes are terminated). Becoming the build user allows multiple paths to privilege escalation, but in this scenario we have faster ways of becoming root.
Moving on to getting root, we're choosing not to use a hardlink
to show why it isn't necessary. Instead, we create a directory
under the build directory with thousands of sequentially named
files, the final entry being "passwd" or "shadow". Then we
terminate the build and watch for the first entry to be chowned
to our user ID (possibly with the inotify API). This way, we
have opened a lengthy window of time where it is enumerating
over a list of file paths in our chosen directory and chowning
each of them. Now we can execute our TOCTOU race condition
At the time of check (TOC), the guix-daemon has a list of file paths to chown under what it assumes is a regular directory (because it ran S_ISDIR on the directory). But we can swap out the directory from under it with a symlink to /etc (most efficiently with renameat2() and using the RENAME_EXCHANGE flag to atomically exchange the paths). At the time of use (TOU) lchown() only checks if the file itself that is being chowned is a symlink, not if the path components are, as can be demonstrated with Python:
$ mkdir td;touch td/tf;python3 -c 'import os;os.lchown("/home/example/td/tf", 1000, 4)';ls -lahtrd td td/tf -rw-rw-r-- 1 example adm 0 Mar 19 19:20 td/tf drwxrwxr-x 2 example example 4.0K Mar 19 19:20 td $ rm -rf td $ mkdir td; ln -s td td2;touch td2/tf;python3 -c 'import os;os.lchown("/home/example/td2/tf", 1000, 4)';ls -lahtrd td2 td2/tf lrwxrwxrwx 1 example example 2 Mar 19 19:21 td2 -> td -rw-rw-r-- 1 example adm 0 Mar 19 19:21 td2/tf
So lchown can blindly chown /etc/passwd to our user by
following the directory symlink and subsequently verifying that
passwd itself is not a symlink. I hope this explains the TOCTOU
race condition and why protected hardlinks help (forcing an
attacker to get root using this race condition), but they are
not a solution to the problem (alone)."