aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2020-12-02 04:26:15 -0500
committerJesse Luehrs <doy@tozt.net>2020-12-02 04:26:15 -0500
commit1ea84bebeaafd4bd22fe021ebef94e7eeb424804 (patch)
treea50186d1c2e02194090d89ab90435284e4eaaa0e
parent3348abc383480539fa04a81a53a0e2beaa59d245 (diff)
downloadrbw-1ea84bebeaafd4bd22fe021ebef94e7eeb424804.tar.gz
rbw-1ea84bebeaafd4bd22fe021ebef94e7eeb424804.zip
fix glibc linkage on debian again
-rw-r--r--CHANGELOG.md7
-rw-r--r--Makefile4
-rwxr-xr-xbin/remove-glibc-2.29-use118
-rwxr-xr-xbuild/fix-glibc-function-versions147
4 files changed, 157 insertions, 119 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f2cf5cf..451465d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## [Unreleased]
+
+### Fixed
+
+* `rbw` should once again be usable on systems with glibc-2.28 (such as Debian
+ stable).
+
## [0.5.1] - 2020-12-02
### Fixed
diff --git a/Makefile b/Makefile
index 937b1ab..fc783c9 100644
--- a/Makefile
+++ b/Makefile
@@ -12,8 +12,10 @@ build:
release:
@cargo build --release --all-targets
- @./bin/remove-glibc-2.29-use ./target/release/rbw
+ @./build/fix-glibc-function-versions ./target/release/rbw
+ @./build/fix-glibc-function-versions ./target/release/rbw-agent
@mv ./target/release/rbw.new ./target/release/rbw
+ @mv ./target/release/rbw-agent.new ./target/release/rbw-agent
.PHONY: release
test:
diff --git a/bin/remove-glibc-2.29-use b/bin/remove-glibc-2.29-use
deleted file mode 100755
index c23b7a6..0000000
--- a/bin/remove-glibc-2.29-use
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/env perl
-use strict;
-use warnings;
-use 5.020;
-use experimental 'signatures';
-no warnings 'experimental::signatures';
-
-# see http://www.lightofdawn.org/wiki/wiki.cgi/NewAppsOnOldGlibc for details
-
-# as of currently, only `log2` is being used from GLIBC_2.29, and a
-# corresponding version from GLIBC_2.2.5 does exist, so we can just swap it
-# out.
-
-my $bin = $ARGV[0];
-
-system("readelf -s $bin | grep -q GLIBC_2.29");
-if ($?) {
- die "no symbols from GLIBC_2.29 found, skipping\n";
-}
-
-my %readelf_v = parse_readelf_v($bin);
-my %readelf_s = parse_readelf_s($bin);
-
-if ($readelf_s{'log2@GLIBC_2.29'}{ver} != $readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.29'}{ver}) {
- die "log2 doesn't appear to use the symbol version from GLIBC_2.29\n";
-}
-
-my $bin_contents = do {
- local $/;
- open my $bin_fh, '<', $bin or die "couldn't open $bin: $!";
- <$bin_fh>
-};
-
-my $gnu_version_r_offset = $readelf_v{'.gnu.version_r'}{offset};
-my $glibc_229_offset = $gnu_version_r_offset + $readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.29'}{offset};
-my $glibc_225_offset = $gnu_version_r_offset + $readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.2.5'}{offset};
-
-# we could just make the GLIBC_2.29 symbol weak (as described in the above
-# page), but that causes a warning to be printed every time you run the binary,
-# which is obnoxious
-
-# use constant VER_FLG_WEAK => 0x02;
-# my $prev_glibc_229_flags = substr $bin_contents, $glibc_229_offset + 0x04, 2, pack('s', VER_FLG_WEAK);
-# if (unpack('s', $prev_glibc_229_flags) != 0) {
-# die "GLIBC_2.29 did not have flags set to 0\n";
-# }
-
-# instead, we overwrite vna_hash, vna_flags, vna_other, vna_name with the 2.2.5
-# versions (but leave vna_next the same) - this causes there to be two entries
-# describing GLIBC_2.2.5, but this appears to be harmless
-substr($bin_contents, $glibc_229_offset + 0x00, 12, substr($bin_contents, $glibc_225_offset + 0x00, 12));
-
-my $gnu_version_offset = $readelf_v{'.gnu.version'}{offset};
-my $log2_offset = $gnu_version_offset + 2 * $readelf_s{'log2@GLIBC_2.29'}{num};
-
-my $prev_log2_version = substr $bin_contents, $log2_offset, 2, pack('s', $readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.2.5'}{ver});
-if (unpack('s', $prev_log2_version) != $readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.29'}{ver}) {
- die "log2 doesn't appear to use the symbol version from GLIBC_2.29\n";
-}
-
-open my $fh, '>', "$bin.new" or die "couldn't open $bin.new: $!";
-print $fh $bin_contents;
-chmod 0755, "$bin.new";
-
-my $remaining = `readelf -s $bin.new | grep GLIBC_2.29`;
-if (!$?) {
- die "additional symbols from GLIBC_2.29 found:\n$remaining\n";
-}
-
-sub parse_readelf_s($bin) {
- my $readelf = `readelf -s $bin`;
-
- my %ret;
- for my $line (split "\n", $readelf) {
- if ($line =~ /^ *[0-9]+:/) {
- my ($num, $value, $size, $type, $bind, $vis, $ndx, $name, $ver) = split ' ', $line;
- if (defined $ver) {
- ($ver) = $ver =~ /\((.*)\)/;
- }
- if (defined $num) {
- ($num) = $num =~ /(.*):/;
- }
- $ret{$name} = {
- num => $num,
- ver => $ver,
- }
- }
- }
-
- %ret
-}
-
-sub parse_readelf_v($bin) {
- my $readelf = `readelf -V $bin`;
-
- my $section;
- my $file;
- my %ret;
- for my $line (split "\n", $readelf) {
- if ($line =~ /^Version (?:symbols|needs) section '([^']+)'/) {
- $section = $1;
- }
- if ($line =~ /^ Addr: (?:[^ ]+) Offset: ([^ ]+)/) {
- $ret{$section}{offset} = hex($1);
- }
- if ($line =~ /^ [^:]+: Version: [^ ]+ File: ([^ ]+)/) {
- $file = $1;
- }
- if ($line =~ /^ ([^:]+): Name: ([^ ]+) Flags: (?:[^ ]+) Version: (.*)/) {
- $ret{$section}{$file}{$2} = {
- offset => hex($1),
- ver => $3,
- };
- }
- }
-
- %ret
-}
diff --git a/build/fix-glibc-function-versions b/build/fix-glibc-function-versions
new file mode 100755
index 0000000..213687a
--- /dev/null
+++ b/build/fix-glibc-function-versions
@@ -0,0 +1,147 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use 5.020;
+use experimental 'signatures';
+no warnings 'experimental::signatures';
+
+# see http://www.lightofdawn.org/wiki/wiki.cgi/NewAppsOnOldGlibc for details
+
+# as of currently, only `log2` is being used from GLIBC_2.29 and
+# `pthread_sigmask` and `pthread_getattr_np` is being used from GLIBC_2.32, and
+# corresponding versions from GLIBC_2.2.5 do exist, so we can just swap them
+# out.
+
+my $bin = $ARGV[0];
+
+system("readelf -sW $bin | grep -q 'GLIBC_2.\\(29\\|32\\)'");
+if ($?) {
+ warn "no symbols from GLIBC_2.29 or GLIBC_2.32 found, skipping\n";
+ exit(0)
+}
+
+my %readelf_v = parse_readelf_v($bin);
+my %readelf_s = parse_readelf_s($bin);
+
+my $bin_contents = do {
+ local $/;
+ open my $bin_fh, '<', $bin or die "couldn't open $bin: $!";
+ <$bin_fh>
+};
+
+# we could just make the GLIBC_2.29 symbol weak (as described in the above
+# page), but that causes a warning to be printed every time you run the binary,
+# which is obnoxious
+
+# use constant VER_FLG_WEAK => 0x02;
+# my $prev_glibc_229_flags = substr $bin_contents, $glibc_229_offset + 0x04, 2, pack('s', VER_FLG_WEAK);
+# if (unpack('s', $prev_glibc_229_flags) != 0) {
+# die "GLIBC_2.29 did not have flags set to 0\n";
+# }
+
+# instead, we overwrite vna_hash, vna_flags, vna_other, vna_name with the 2.2.5
+# versions (but leave vna_next the same) - this causes there to be multiple
+# entries describing GLIBC_2.2.5, but this appears to be harmless
+my $gnu_version_r_offset = $readelf_v{'.gnu.version_r'}{offset};
+my $fix_libc = defined($readelf_v{'.gnu.version_r'}{'libc.so.6'}{'GLIBC_2.32'}{offset});
+my $fix_libm = defined($readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.29'}{offset});
+
+if ($fix_libc) {
+ my $glibc_232_libc_offset = $gnu_version_r_offset + $readelf_v{'.gnu.version_r'}{'libc.so.6'}{'GLIBC_2.32'}{offset};
+ my $glibc_225_libc_offset = $gnu_version_r_offset + $readelf_v{'.gnu.version_r'}{'libc.so.6'}{'GLIBC_2.2.5'}{offset};
+ substr($bin_contents, $glibc_232_libc_offset + 0x00, 12, substr($bin_contents, $glibc_225_libc_offset + 0x00, 12));
+}
+
+if ($fix_libm) {
+ my $glibc_229_libm_offset = $gnu_version_r_offset + $readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.29'}{offset};
+ my $glibc_225_libm_offset = $gnu_version_r_offset + $readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.2.5'}{offset};
+ substr($bin_contents, $glibc_229_libm_offset + 0x00, 12, substr($bin_contents, $glibc_225_libm_offset + 0x00, 12));
+}
+
+my $gnu_version_offset = $readelf_v{'.gnu.version'}{offset};
+my $fix_log2 = defined($readelf_s{'log2@GLIBC_2.29'}{ver}) && $readelf_s{'log2@GLIBC_2.29'}{ver} == $readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.29'}{ver};
+my $fix_pthread_sigmask = defined($readelf_s{'pthread_sigmask@GLIBC_2.32'}{ver}) && $readelf_s{'pthread_sigmask@GLIBC_2.32'}{ver} == $readelf_v{'.gnu.version_r'}{'libc.so.6'}{'GLIBC_2.32'}{ver};
+my $fix_pthread_getattr_np = defined($readelf_s{'pthread_getattr_np@GLIBC_2.32'}{ver}) && $readelf_s{'pthread_getattr_np@GLIBC_2.32'}{ver} == $readelf_v{'.gnu.version_r'}{'libc.so.6'}{'GLIBC_2.32'}{ver};
+
+if ($fix_log2) {
+ my $log2_offset = $gnu_version_offset + 2 * $readelf_s{'log2@GLIBC_2.29'}{num};
+ my $prev_log2_version = substr $bin_contents, $log2_offset, 2, pack('s', $readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.2.5'}{ver});
+ if (unpack('s', $prev_log2_version) != $readelf_v{'.gnu.version_r'}{'libm.so.6'}{'GLIBC_2.29'}{ver}) {
+ die "log2 doesn't appear to use the symbol version from GLIBC_2.29\n";
+ }
+}
+
+if ($fix_pthread_sigmask) {
+ my $pthread_sigmask_offset = $gnu_version_offset + 2 * $readelf_s{'pthread_sigmask@GLIBC_2.32'}{num};
+ my $prev_pthread_sigmask_version = substr $bin_contents, $pthread_sigmask_offset, 2, pack('s', $readelf_v{'.gnu.version_r'}{'libc.so.6'}{'GLIBC_2.2.5'}{ver});
+ if (unpack('s', $prev_pthread_sigmask_version) != $readelf_v{'.gnu.version_r'}{'libc.so.6'}{'GLIBC_2.32'}{ver}) {
+ die "pthread_sigmask doesn't appear to use the symbol version from GLIBC_2.32\n";
+ }
+}
+
+if ($fix_pthread_getattr_np) {
+ my $pthread_getattr_np_offset = $gnu_version_offset + 2 * $readelf_s{'pthread_getattr_np@GLIBC_2.32'}{num};
+ my $prev_pthread_getattr_np_version = substr $bin_contents, $pthread_getattr_np_offset, 2, pack('s', $readelf_v{'.gnu.version_r'}{'libc.so.6'}{'GLIBC_2.2.5'}{ver});
+ if (unpack('s', $prev_pthread_getattr_np_version) != $readelf_v{'.gnu.version_r'}{'libc.so.6'}{'GLIBC_2.32'}{ver}) {
+ die "pthread_getattr_np doesn't appear to use the symbol version from GLIBC_2.32\n";
+ }
+}
+
+open my $fh, '>', "$bin.new" or die "couldn't open $bin.new: $!";
+print $fh $bin_contents;
+chmod 0755, "$bin.new";
+
+my $remaining = `readelf -sW $bin.new | grep 'GLIBC_2.\\(29\\|32\\)'`;
+if (!$?) {
+ die "additional symbols from GLIBC_2.29 or GLIBC_2.32 found:\n$remaining\n";
+}
+
+sub parse_readelf_s($bin) {
+ my $readelf = `readelf -sW $bin`;
+
+ my %ret;
+ for my $line (split "\n", $readelf) {
+ if ($line =~ /^ *[0-9]+:/) {
+ my ($num, $value, $size, $type, $bind, $vis, $ndx, $name, $ver) = split ' ', $line;
+ if (defined $ver) {
+ ($ver) = $ver =~ /\((.*)\)/;
+ }
+ if (defined $num) {
+ ($num) = $num =~ /(.*):/;
+ }
+ $ret{$name} = {
+ num => $num,
+ ver => $ver,
+ }
+ }
+ }
+
+ %ret
+}
+
+sub parse_readelf_v($bin) {
+ my $readelf = `readelf -V $bin`;
+
+ my $section;
+ my $file;
+ my %ret;
+ for my $line (split "\n", $readelf) {
+ if ($line =~ /^Version (?:symbols|needs) section '([^']+)'/) {
+ $section = $1;
+ }
+ if ($line =~ /^ Addr: (?:[^ ]+) Offset: ([^ ]+)/) {
+ $ret{$section}{offset} = hex($1);
+ }
+ if ($line =~ /^ [^:]+: Version: [^ ]+ File: ([^ ]+)/) {
+ $file = $1;
+ }
+ if ($line =~ /^ ([^:]+): Name: ([^ ]+) Flags: (?:[^ ]+) Version: (.*)/) {
+ $ret{$section}{$file}{$2} = {
+ offset => hex($1),
+ ver => $3,
+ };
+ }
+ }
+
+ %ret
+}