diff --git a/libexec/package.rb b/libexec/package.rb index 94d5184..0d6538b 100755 --- a/libexec/package.rb +++ b/libexec/package.rb @@ -409,6 +409,25 @@ def apply_source_patches(source) # is declared inline without static, which C99 inline semantics (the default since # GCC 5) turn into an undefined reference at link time. inreplace(File.join(source, "lex.c"), "struct kwtable *\nrb_reserved_word", "static struct kwtable *\nrb_reserved_word") + when "init_only_exports" + # Old openssl extensions define stand-ins for functions their OpenSSL lacks + # (X509_STORE_set_ex_data, SSL_SESSION_cmp, ...), and 1.8's digest/sha2 has its own + # SHA256_Transform, all exported. When a system libcrypto.so.3 is already loaded + # (pg gem required first), calls to them bind to OpenSSL 3's functions, which crash + # on the old structs. Nothing links against these extensions, so they export only + # their Init function. The flag stays in their Makefiles, not rbconfig. + %w[openssl digest/md5 digest/sha1 digest/sha2 digest/rmd160].each do |name| + ext = File.join(source, "ext", name) + next unless File.exist?(File.join(ext, "extconf.rb")) + + File.write(File.join(ext, "exports.map"), "{\n global: Init_*;\n local: *;\n};\n") + extconf = File.join(ext, "extconf.rb") + content = File.read(extconf) + raise PackageError, "#{extconf}: create_makefile not found" unless content.match?(/^\s*create_makefile\(/) + File.write(extconf, content.sub(/^(\s*)create_makefile\(/) do + "#{$1}$DLDFLAGS << \" -Wl,--version-script=\#{File.expand_path(\"exports.map\", $srcdir)}\"\n#{$1}create_makefile(" + end) + end else raise PackageError, "unknown source patch: #{name}" end @@ -1063,12 +1082,25 @@ def check_abi!(root) end end - # See ruby_build_env: an exported OpenSSL symbol lets a system libpq bind to it. + # An exported symbol that the system OpenSSL also defines gets bound to it (or it to + # them) when both are loaded: see ruby_build_env and the init_only_exports patch. The + # bundled OpenSSL must be hidden everywhere, and the extensions that wrap or stand in + # for it may export nothing but their Init function. def check_openssl_hidden!(root) - exporters = Dir.glob(File.join(root, "**", "*.so")).select do |path| - capture("nm", "-D", "--defined-only", path, allow_failure: true).match?(/ (SSL_new|CRYPTO_malloc)$/) + offenders = Dir.glob(File.join(root, "**", "*.so")).filter_map do |path| + symbols = capture("nm", "-D", "--defined-only", path, allow_failure: true).lines.map { |line| line.split.last } + symbols = if init_only_exports? && path.match?(%r{/(openssl|digest/(md5|sha1|sha2|rmd160))\.so\z}) + symbols.grep_v(/\A(Init_\w+|_init|_fini|_edata|_end|__bss_start)\z/) + else + symbols.grep(/\A(SSL_new|CRYPTO_malloc)\z/) + end + "#{path}: #{symbols.first(5).join(", ")}" if symbols.any? end - raise PackageError, "OpenSSL symbols exported by:\n #{exporters.join("\n ")}" unless exporters.empty? + raise PackageError, "OpenSSL symbols exported by:\n #{offenders.join("\n ")}" unless offenders.empty? + end + + def init_only_exports? + Array(@series["patches"]).include?("init_only_exports") end def package! diff --git a/recipes/rubies.yml b/recipes/rubies.yml index 5e8dee4..f0cc08e 100644 --- a/recipes/rubies.yml +++ b/recipes/rubies.yml @@ -40,18 +40,110 @@ rubies: series: '2.6' url: https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.10.tar.bz2 sha256: 399e1f13e7fedc3c6ae2ff541bbf26c44dfb63b07b6c186fdd15b4e526e27e9c + 2.7.0: + series: '2.7' + url: https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.0.tar.gz + sha256: 8c99aa93b5e2f1bc8437d1bbbefd27b13e7694025331f77245d0c068ef1f8cbe + 2.7.1: + series: '2.7' + url: https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.1.tar.gz + sha256: d418483bdd0000576c1370571121a6eb24582116db0b7bb2005e90e250eae418 + 2.7.2: + series: '2.7' + url: https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.2.tar.gz + sha256: 6e5706d0d4ee4e1e2f883db9d768586b4d06567debea353c796ec45e8321c3d4 + 2.7.3: + series: '2.7' + url: https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.3.tar.gz + sha256: 8925a95e31d8f2c81749025a52a544ea1d05dad18794e6828709268b92e55338 + 2.7.4: + series: '2.7' + url: https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.4.tar.gz + sha256: 3043099089608859fc8cce7f9fdccaa1f53a462457e3838ec3b25a7d609fbc5b + 2.7.5: + series: '2.7' + url: https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.5.tar.gz + sha256: 2755b900a21235b443bb16dadd9032f784d4a88f143d852bc5d154f22b8781f1 + 2.7.6: + series: '2.7' + url: https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.6.tar.gz + sha256: e7203b0cc09442ed2c08936d483f8ac140ec1c72e37bb5c401646b7866cb5d10 + 2.7.7: + series: '2.7' + url: https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.7.tar.gz + sha256: e10127db691d7ff36402cfe88f418c8d025a3f1eea92044b162dd72f0b8c7b90 2.7.8: series: '2.7' url: https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.8.tar.gz sha256: c2dab63cbc8f2a05526108ad419efa63a67ed4074dbbcf9fc2b1ca664cb45ba0 + 3.0.0: + series: '3.0' + url: https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0.tar.gz + sha256: a13ed141a1c18eb967aac1e33f4d6ad5f21be1ac543c344e0d6feeee54af8e28 + 3.0.1: + series: '3.0' + url: https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.1.tar.gz + sha256: 369825db2199f6aeef16b408df6a04ebaddb664fb9af0ec8c686b0ce7ab77727 + 3.0.2: + series: '3.0' + url: https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.2.tar.gz + sha256: 5085dee0ad9f06996a8acec7ebea4a8735e6fac22f22e2d98c3f2bc3bef7e6f1 + 3.0.3: + series: '3.0' + url: https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.3.tar.gz + sha256: 3586861cb2df56970287f0fd83f274bd92058872d830d15570b36def7f1a92ac + 3.0.4: + series: '3.0' + url: https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.4.tar.gz + sha256: 70b47c207af04bce9acea262308fb42893d3e244f39a4abc586920a1c723722b + 3.0.5: + series: '3.0' + url: https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.5.tar.gz + sha256: 9afc6380a027a4fe1ae1a3e2eccb6b497b9c5ac0631c12ca56f9b7beb4848776 + 3.0.6: + series: '3.0' + url: https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.6.tar.gz + sha256: 6e6cbd490030d7910c0ff20edefab4294dfcd1046f0f8f47f78b597987ac683e 3.0.7: series: '3.0' url: https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.7.tar.gz sha256: 2a3411977f2850431136b0fab8ad53af09fb74df2ee2f4fb7f11b378fe034388 + 3.1.0: + series: '3.1' + url: https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.0.tar.gz + sha256: 50a0504c6edcb4d61ce6b8cfdbddaa95707195fab0ecd7b5e92654b2a9412854 + 3.1.1: + series: '3.1' + url: https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.1.tar.gz + sha256: fe6e4782de97443978ddba8ba4be38d222aa24dc3e3f02a6a8e7701c0eeb619d + 3.1.2: + series: '3.1' + url: https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.2.tar.gz + sha256: 61843112389f02b735428b53bb64cf988ad9fb81858b8248e22e57336f24a83e + 3.1.3: + series: '3.1' + url: https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.3.tar.gz + sha256: 5ea498a35f4cd15875200a52dde42b6eb179e1264e17d78732c3a57cd1c6ab9e + 3.1.4: + series: '3.1' + url: https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.4.tar.gz + sha256: a3d55879a0dfab1d7141fdf10d22a07dbf8e5cdc4415da1bde06127d5cc3c7b6 + 3.1.5: + series: '3.1' + url: https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.5.tar.gz + sha256: 3685c51eeee1352c31ea039706d71976f53d00ab6d77312de6aa1abaf5cda2c5 + 3.1.6: + series: '3.1' + url: https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.6.tar.gz + sha256: 0d0dafb859e76763432571a3109d1537d976266be3083445651dc68deed25c22 3.1.7: series: '3.1' url: https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.7.tar.gz sha256: 0556acd69f141ddace03fa5dd8d76e7ea0d8f5232edf012429579bcdaab30e7b + 3.2.0: + series: '3.2' + url: https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0.tar.gz + sha256: daaa78e1360b2783f98deeceb677ad900f3a36c0ffa6e2b6b19090be77abc272 3.2.1: series: '3.2' url: https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.1.tar.xz diff --git a/recipes/series.yml b/recipes/series.yml index 9b74979..dc1955e 100644 --- a/recipes/series.yml +++ b/recipes/series.yml @@ -36,7 +36,9 @@ series: # because their openssl extensions predate OpenSSL 3; -fno-strict-overflow because # their fixnum overflow checks rely on signed overflow wrapping, which GCC exploits from # -O2 up (a 1.8.7 built without it evaluates 2**64 to 0); readline through a bundled - # libedit; no bundled msgpack/bootsnap; a version-appropriate native gem as the test. + # libedit; no bundled msgpack/bootsnap; a version-appropriate native gem as the test; + # init_only_exports so their openssl and digest extensions can't collide with a system + # OpenSSL 3 that the pg gem loads into the same process. "1.8": openssl: openssl1.0 baseruby: none @@ -45,7 +47,7 @@ series: install_doc: false install_target: install-nodoc # 1.8 has no --disable-install-doc cflags: "-O3 -fno-strict-overflow" - patches: [lex_c99] + patches: [lex_c99, init_only_exports] freshen_config_guess: true extra_out_ext: [tk, tcltklib, gdbm, dbm] # removed from the tree: 1.8 has no --with-out-ext rubygems: rubygems1.8 @@ -56,6 +58,7 @@ series: test_native_gem: { name: json, version: 1.8.6 } "1.9": openssl: openssl1.0 + patches: [init_only_exports] baseruby: none use_libedit: true install_doc: false @@ -70,6 +73,7 @@ series: test_native_gem: { name: json, version: 1.8.6 } "2.0": openssl: openssl1.0 + patches: [init_only_exports] baseruby: none use_libedit: true install_doc: false @@ -83,6 +87,7 @@ series: test_native_gem: { name: json, version: 1.8.6 } "2.1": openssl: openssl1.0 + patches: [init_only_exports] baseruby: none use_libedit: true install_doc: false @@ -95,6 +100,7 @@ series: test_native_gem: { name: json, version: 1.8.6 } "2.2": openssl: openssl1.0 + patches: [init_only_exports] baseruby: none use_libedit: true install_doc: false @@ -107,6 +113,7 @@ series: test_native_gem: { name: json, version: 1.8.6 } "2.3": openssl: openssl1.0 + patches: [init_only_exports] baseruby: none use_libedit: true install_doc: false @@ -119,6 +126,7 @@ series: test_native_gem: { name: json, version: 1.8.6 } "2.4": openssl: openssl1.1 + patches: [init_only_exports] baseruby: none # 2.4's configure rejects --with-baseruby=no use_libedit: true install_doc: false @@ -131,6 +139,7 @@ series: test_native_gem: { name: msgpack, version: 1.4.2 } "2.5": openssl: openssl1.1 + patches: [init_only_exports] baseruby: "no" use_libedit: true install_doc: false @@ -143,6 +152,7 @@ series: test_native_gem: { name: msgpack, version: 1.4.2 } "2.6": openssl: openssl1.1 + patches: [init_only_exports] baseruby: "no" use_libedit: true install_doc: false @@ -156,6 +166,7 @@ series: test_native_gem: { name: msgpack, version: 1.4.2 } "2.7": openssl: openssl1.1 + patches: [init_only_exports] baseruby: "no" readline_ext: false # readline.rb falls back to reline from 2.7 install_doc: false @@ -169,6 +180,7 @@ series: test_native_gem: { name: msgpack, version: 1.4.2 } "3.0": openssl: openssl1.1 # 3.0's openssl extension predates OpenSSL 3 + patches: [init_only_exports] readline_ext: false install_doc: false extra_out_ext: [gdbm, dbm] @@ -179,6 +191,7 @@ series: test_native_gem: { name: msgpack, version: 1.4.2 } "3.1": openssl: openssl1.1 # OpenSSL 3 is supported but this keeps 2.4–3.1 uniform + patches: [init_only_exports] readline_ext: false install_doc: false extra_out_ext: [gdbm, dbm]