Skip to content

Commit 7f1633f

Browse files
authored
shellgen: update store paths when patching glibc (#1818)
This addresses an issue where scripts (and other text files) could still refer to the unpatched version of a program after enabling `patch_glibc`. This is one of the reasons why Ruby would still segfault in issue #1772. For example, if you look at `bundler` (installed by default with `ruby`) it's a wrapper script with the shebang: #!/nix/store/vs52hm8jbwgx19plicg02dzz2vmvbyy5-ruby-2.7.8/bin/ruby This means that commands like `bundler exec rails` would still run using the unpatched version of ruby. I suspect this was also happening with Python or other packages that rely on wrapper scripts. The fix updates glibc-patch.bash to grep for the old store path and replace it using sed. It relies on ripgrep's ability to ignore binary files so that we only modify text files.
1 parent 50fd63b commit 7f1633f

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

internal/shellgen/tmpl/glibc-patch.bash

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,30 @@ declare -r glibc # new glibc that we're patching in
77
declare -r out # nix output path that will contain the patched package
88

99
# Paths to this script's dependencies set by nix.
10-
declare -r coreutils file findutils patchelf ripgrep
10+
declare -r coreutils file findutils gnused patchelf ripgrep
1111

1212
# Explicitly declare the specific commands that this script depends on.
1313
hash -p "$coreutils/bin/cp" cp
1414
hash -p "$coreutils/bin/chmod" chmod
15-
hash -p "$coreutils/bin/cut" cut
15+
hash -p "$coreutils/bin/dirname" dirname
1616
hash -p "$coreutils/bin/echo" echo
1717
hash -p "$coreutils/bin/head" head
18-
hash -p "$coreutils/bin/mktemp" mktemp
19-
hash -p "$coreutils/bin/rm" rm
2018
hash -p "$coreutils/bin/stat" stat
2119
hash -p "$coreutils/bin/wc" wc
2220
hash -p "$file/bin/file" file
2321
hash -p "$findutils/bin/find" find
24-
hash -p "$findutils/bin/xargs" xargs
22+
hash -p "$gnused/bin/sed" sed
2523
hash -p "$patchelf/bin/patchelf" patchelf
2624
hash -p "$ripgrep/bin/rg" rg
2725

2826
# Copy the contents of the original package so we can patch them.
2927
cp -R "$pkg" "$out"
3028

29+
# Because we copied an existing store path, our new $out directory might be
30+
# read-only. This might've caused issues with some versions of Nix, so make it
31+
# writable again just to be safe.
32+
chmod u+rwx "$out"
33+
3134
# Find the new linker that we'll patch into all of the package's executables as
3235
# the interpreter.
3336
interp="$(find "$glibc/lib" -type f -maxdepth 1 -executable -name 'ld-linux-*.so*' | head -n1)"
@@ -76,3 +79,30 @@ echo "patching elf binaries count=$count"
7679
for binary in $elves; do
7780
patch "$binary" exe
7881
done
82+
83+
patch_store_path() {
84+
declare -r path="$1"
85+
declare -r perm=$(stat -c "%a" "$path")
86+
87+
# sed creates a temporary sibling file for in-place edits, so we need to
88+
# ensure that the file's directory is writeable.
89+
declare -r dir="$(dirname "$path")"
90+
declare -r dperm=$(stat -c "%a" "$dir")
91+
92+
echo "running sed file=$path file_perm=$perm dir=$dir dir_perm=$dperm"
93+
chmod u+w "$path" "$dir"
94+
sed -i -e "$sedexpr" "$path"
95+
chmod "$perm" "$path"
96+
chmod "$dperm" "$dir"
97+
}
98+
99+
# -uu search ignored and hidden files
100+
# -l list filenames
101+
# -F exact substring search (faster, no escaping needed)
102+
files="$(rg -uu -l -F "$pkg" "$out")"
103+
count="$(echo "$files" | wc -l)"
104+
sedexpr="s|$pkg|$out|g"
105+
echo "patching files with old store path references count=$count sed=$sedexpr"
106+
for f in $files; do
107+
patch_store_path "$f"
108+
done

internal/shellgen/tmpl/glibc-patch.nix.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
inherit pkg;
3838

3939
# Programs needed by glibc-patch.bash.
40-
inherit (nixpkgs-glibc.legacyPackages."${system}") bash coreutils file findutils glibc patchelf ripgrep;
40+
inherit (nixpkgs-glibc.legacyPackages."${system}") bash coreutils file findutils glibc gnused patchelf ripgrep;
4141

4242
builder = "${bash}/bin/bash";
4343
args = [ ./glibc-patch.bash ];

0 commit comments

Comments
 (0)