已合并
fix CVE-2026-82455 #348
tong_1001创建于 10 天前
fix CVE-2026-82455 #348
已合并
tong_1001创建于 10 天前
3 个文件变更+194-1
@@ -0,0 +1,78 @@
1+From 643e0235fd7ea2bcb464c97eb2336a81d31b81b4 Mon Sep 17 00:00:00 2001
2+From: thesmartshadow <firaswq12@gmail.com>
3+Date: Sun, 19 Apr 2026 02:20:37 +0300
4+Subject: [PATCH] Prevent symlink-based escape during gem extraction
5+ 
6+Reference:https://github.com/ruby/rubygems/commit/643e0235fd7ea2bcb464c97eb2336a81d31b81b4
7+Conflict:(1) delete `omit "Symlinks not supported or not enabled" unless symlink_supported?` in testcase
8+(2) Define `destination_dir` at the start of the function, as seen in commits
9+https://github.com/ruby/rubygems/commit/58173ff2eaae7dbc50da1b3ac66a604637b90ec9
10+and https://github.com/ruby/rubygems/commit/ac3b85bd5e90d003aa2d9296aec0bc48b5728f1
11+---
12+ lib/rubygems/package.rb | 7 +++++++
13+ test/rubygems/test_gem_package.rb | 24 ++++++++++++++++++++++++
14+ 2 files changed, 31 insertions(+)
15+ 
16+diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb
17+index 4672866985f8..2591a349f947 100644
18+--- a/lib/rubygems/package.rb
19++++ b/lib/rubygems/package.rb
20+@@ -408,6 +408,8 @@ EOM
21+ # extracted.
22+
23+ def extract_tar_gz(io, destination_dir, pattern = "*") # :nodoc:
24++ destination_dir = File.realpath(destination_dir)
25++
26+ directories = []
27+ symlinks = []
28+
29+@@ -444,6 +446,11 @@ EOM
30+ directories << mkdir
31+ end
32+
33++ real_mkdir = File.realpath(mkdir)
34++ unless real_mkdir == destination_dir || normalize_path(real_mkdir).start_with?(normalize_path(destination_dir + "/"))
35++ raise Gem::Package::PathError.new(real_mkdir, destination_dir)
36++ end
37++
38+ if entry.file?
39+ File.open(destination, "wb") {|out| out.write entry.read }
40+ FileUtils.chmod file_mode(entry.header.mode), destination
41+diff --git a/test/rubygems/test_gem_package.rb b/test/rubygems/test_gem_package.rb
42+index 9d6215838d63..b228a6170537 100644
43+--- a/test/rubygems/test_gem_package.rb
44++++ b/test/rubygems/test_gem_package.rb
45+@@ -542,6 +542,30 @@ class TestGemPackage < Gem::Package::TarTestCase
46+ "#{@destination} is not allowed", e.message)
47+ end
48+
49++ def test_extract_tar_gz_rejects_preexisting_symlink_escape
50++ package = Gem::Package.new @gem
51++
52++ tgz_io = util_tar_gz do |tar|
53++ tar.add_file "lib/owned.txt", 0o644 do |io|
54++ io.write "poc-content"
55++ end
56++ end
57++
58++ escape_dir = File.join(@tempdir, "escape")
59++ FileUtils.mkdir_p escape_dir
60++
61++ FileUtils.rm_rf File.join(@destination, "lib")
62++ File.symlink escape_dir, File.join(@destination, "lib")
63++
64++ escaped = File.join(escape_dir, "owned.txt")
65++
66++ assert_raise Gem::Package::PathError do
67++ package.extract_tar_gz tgz_io, @destination
68++ end
69++
70++ refute File.exist?(escaped), "must not write outside extraction root via symlink"
71++ end
72++
73+ def test_extract_tar_gz_symlink_relative_path
74+ package = Gem::Package.new @gem
75+ package.verify
76+--
77+2.43.0
78+ 
@@ -0,0 +1,107 @@
1+From 20e729f9a5d52aaa5a01aa4712ebfeb3ed6c2db0 Mon Sep 17 00:00:00 2001
2+From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
3+Date: Mon, 3 Aug 2026 11:38:39 +0900
4+Subject: [PATCH] Check the resolved parent directory before extracting old
5+ format gems
6+ 
7+Gem::Package::Old#extract_files only validated entry paths by string
8+expansion, so a preexisting symlink in the extraction directory redirected
9+writes outside of it. Gem::Package#extract_tar_gz already re-resolves the
10+parent directory with File.realpath, so extract the shared check into
11+verify_extraction_dir and call it from both.
12+ 
13+Reference:https://github.com/ruby/rubygems/commit/20e729f9a5d52aaa5a01aa4712ebfeb3ed6c2db0
14+Conflict:delete `omit "Symlinks not supported or not enabled" unless symlink_supported?` in testcase
15+ 
16+Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
17+---
18+ lib/rubygems/package.rb | 19 +++++++++++++++----
19+ lib/rubygems/package/old.rb | 6 ++++--
20+ test/rubygems/test_gem_package_old.rb | 15 +++++++++++++++
21+ 3 files changed, 34 insertions(+), 6 deletions(-)
22+ 
23+diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb
24+index cb78a7d15c9d..1cc550a431c8 100644
25+--- a/lib/rubygems/package.rb
26++++ b/lib/rubygems/package.rb
27+@@ -444,10 +444,7 @@ EOM
28+ directories << mkdir
29+ end
30+
31+- real_mkdir = File.realpath(mkdir)
32+- unless real_mkdir == destination_dir || normalize_path(real_mkdir).start_with?(normalize_path(destination_dir + "/"))
33+- raise Gem::Package::PathError.new(real_mkdir, destination_dir)
34+- end
35++ verify_extraction_dir mkdir, destination_dir
36+
37+ if entry.file?
38+ File.open(destination, "wb") {|out| out.write entry.read }
39+@@ -635,6 +632,20 @@ EOM
40+ raise Gem::Package::FormatError.new e.message, @gem
41+ end
42+
43++ ##
44++ # Raises an exception unless +dir+, with symlinks resolved, is
45++ # +destination_dir+ or a directory inside it. +destination_dir+ must
46++ # already be resolved with File.realpath by the caller.
47++
48++ def verify_extraction_dir(dir, destination_dir) # :nodoc:
49++ real_dir = File.realpath(dir)
50++
51++ return if real_dir == destination_dir ||
52++ normalize_path(real_dir).start_with?(normalize_path(destination_dir + "/"))
53++
54++ raise Gem::Package::PathError.new(real_dir, destination_dir)
55++ end
56++
57+ ##
58+ # Verifies the +checksums+ against the +digests+. This check is not
59+ # cryptographically secure. Missing checksums are ignored.
60+diff --git a/lib/rubygems/package/old.rb b/lib/rubygems/package/old.rb
61+index 09a02d3ecd62..0b0b3b643199 100644
62+--- a/lib/rubygems/package/old.rb
63++++ b/lib/rubygems/package/old.rb
64+@@ -75,10 +75,12 @@ class Gem::Package::Old < Gem::Package
65+ raise Gem::Package::FormatError, "#{full_name} in #{@gem} is corrupt" if
66+ file_data.length != entry["size"].to_i
67+
68+- FileUtils.rm_rf destination
69+-
70+ FileUtils.mkdir_p File.dirname(destination), :mode => dir_mode && 0755
71+
72++ verify_extraction_dir File.dirname(destination), destination_dir
73++
74++ FileUtils.rm_rf destination
75++
76+ File.open destination, "wb", file_mode(entry["mode"]) do |out|
77+ out.write file_data
78+ end
79+diff --git a/test/rubygems/test_gem_package_old.rb b/test/rubygems/test_gem_package_old.rb
80+index d65d1edad65a..b232f9712f99 100644
81+--- a/test/rubygems/test_gem_package_old.rb
82++++ b/test/rubygems/test_gem_package_old.rb
83+@@ -43,6 +43,21 @@ unless Gem.java_platform? # jruby can't require the simple_gem file
84+ assert_equal mask, File.stat(extracted).mode unless win_platform?
85+ end
86+
87++ def test_extract_files_rejects_preexisting_symlink_escape
88++
89++ escape_dir = File.join @tempdir, "escape"
90++ FileUtils.mkdir_p escape_dir
91++
92++ File.symlink escape_dir, File.join(@destination, "lib")
93++
94++ assert_raise Gem::Package::PathError do
95++ @package.extract_files @destination
96++ end
97++
98++ assert_path_not_exist File.join(escape_dir, "foo.rb"),
99++ "must not write outside extraction root via symlink"
100++ end
101++
102+ def test_extract_files_security_policy
103+ pend "openssl is missing" unless Gem::HAVE_OPENSSL
104+
105+--
106+2.43.0
107+ 
@@ -38,7 +38,7 @@
38 38 
39Name: ruby39Name: ruby
40Version: %{ruby_version}40Version: %{ruby_version}
41-Release: 16241+Release: 163
42Summary: Object-oriented scripting language interpreter42Summary: Object-oriented scripting language interpreter
43License: (Ruby OR BSD-2-Clause) AND (Ruby OR BSD-2-Clause OR GPL-1.0-or-later) AND BSD-3-Clause AND (GPL-3.0-or-later WITH Bison-exception-2.2) AND ISC AND Public Domain AND MIT AND CC0 AND zlib AND Unicode-DFS-201543License: (Ruby OR BSD-2-Clause) AND (Ruby OR BSD-2-Clause OR GPL-1.0-or-later) AND BSD-3-Clause AND (GPL-3.0-or-later WITH Bison-exception-2.2) AND ISC AND Public Domain AND MIT AND CC0 AND zlib AND Unicode-DFS-2015
44URL: https://www.ruby-lang.org/en/44URL: https://www.ruby-lang.org/en/
@@ -153,6 +153,8 @@ Patch6062: backport-0001-CVE-2026-47242-Refactor-RawText-add-improve-test-covera
153Patch6063: backport-0002-CVE-2026-47242-Validate-QuotedString-contains-only-valid-bytes.patch153Patch6063: backport-0002-CVE-2026-47242-Validate-QuotedString-contains-only-valid-bytes.patch
154Patch6064: backport-CVE-2026-80212.patch154Patch6064: backport-CVE-2026-80212.patch
155Patch6065: backport-CVE-2026-80213.patch155Patch6065: backport-CVE-2026-80213.patch
156+Patch6066: backport-CVE-2026-82455.patch
157+Patch6067: backport-Check-the-resolved-parent-directory-before-extractin.patch
156 158 
157Patch9000: fix-dynamic-constant-assignment-SyntaxError.patch159Patch9000: fix-dynamic-constant-assignment-SyntaxError.patch
158 160 
@@ -964,6 +966,12 @@ make runruby TESTRUN_SCRIPT=%{SOURCE13}
964%{gem_dir}/specifications/matrix-%{matrix_version}.gemspec966%{gem_dir}/specifications/matrix-%{matrix_version}.gemspec
965 967 
966%changelog968%changelog
969+* Mon Aug 31 2026 shixuantong <sxt1001@qq.com> - 3.2.8-163
970+- Type:CVE
971+- CVE:CVE-2026-82455
972+- SUG:NA
973+- DESC:fix CVE-2026-82455
974+ 
967* Sat Aug 29 2026 shixuantong <sxt1001@qq.com> - 3.2.8-162975* Sat Aug 29 2026 shixuantong <sxt1001@qq.com> - 3.2.8-162
968- Type:CVE976- Type:CVE
969- CVE:CVE-2026-80212 CVE-2026-80213977- CVE:CVE-2026-80212 CVE-2026-80213