Skip to content

Commit 8565709

Browse files
[AUTO-CHERRYPICK] Patch ruby CVE-2025-27219, CVE-2025-27220, CVE-2025-27221 [Medium] - branch main (#12951)
Co-authored-by: Kanishk Bansal <103916909+Kanishk-Bansal@users.noreply.github.com>
1 parent 4a9ab9d commit 8565709

4 files changed

Lines changed: 185 additions & 1 deletion

File tree

SPECS/ruby/CVE-2025-27219.patch

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
From 9907b76dad0777ee300de236dad4b559e07596ab Mon Sep 17 00:00:00 2001
2+
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
3+
Date: Fri, 21 Feb 2025 16:01:17 +0900
4+
Subject: [PATCH] Use String#concat instead of String#+ for reducing cpu usage
5+
6+
Upstream Reference : https://github.com/ruby/cgi/commit/9907b76dad0777ee300de236dad4b559e07596ab
7+
8+
Co-authored-by: "Yusuke Endoh" <mame@ruby-lang.org>
9+
---
10+
lib/cgi/cookie.rb | 5 +++--
11+
1 file changed, 3 insertions(+), 2 deletions(-)
12+
13+
diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb
14+
index 9498e2f..1c4ef6a 100644
15+
--- a/lib/cgi/cookie.rb
16+
+++ b/lib/cgi/cookie.rb
17+
@@ -190,9 +190,10 @@ def self.parse(raw_cookie)
18+
values ||= ""
19+
values = values.split('&').collect{|v| CGI.unescape(v,@@accept_charset) }
20+
if cookies.has_key?(name)
21+
- values = cookies[name].value + values
22+
+ cookies[name].concat(values)
23+
+ else
24+
+ cookies[name] = Cookie.new(name, *values)
25+
end
26+
- cookies[name] = Cookie.new(name, *values)
27+
end
28+
29+
cookies

SPECS/ruby/CVE-2025-27220.patch

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
From cd1eb08076c8b8e310d4d553d427763f2577a1b6 Mon Sep 17 00:00:00 2001
2+
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
3+
Date: Fri, 21 Feb 2025 15:53:31 +0900
4+
Subject: [PATCH] Escape/unescape unclosed tags as well
5+
Upstream Reference : https://github.com/ruby/cgi/commit/cd1eb08076c8b8e310d4d553d427763f2577a1b6
6+
7+
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
8+
---
9+
lib/cgi/util.rb | 4 ++--
10+
test/cgi/test_cgi_util.rb | 18 ++++++++++++++++++
11+
2 files changed, 20 insertions(+), 2 deletions(-)
12+
13+
diff --git a/lib/cgi/util.rb b/lib/cgi/util.rb
14+
index 4986e54..5f12eae 100644
15+
--- a/lib/cgi/util.rb
16+
+++ b/lib/cgi/util.rb
17+
@@ -184,7 +184,7 @@ def unescapeHTML(string)
18+
def escapeElement(string, *elements)
19+
elements = elements[0] if elements[0].kind_of?(Array)
20+
unless elements.empty?
21+
- string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/i) do
22+
+ string.gsub(/<\/?(?:#{elements.join("|")})\b[^<>]*+>?/im) do
23+
CGI.escapeHTML($&)
24+
end
25+
else
26+
@@ -204,7 +204,7 @@ def escapeElement(string, *elements)
27+
def unescapeElement(string, *elements)
28+
elements = elements[0] if elements[0].kind_of?(Array)
29+
unless elements.empty?
30+
- string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/i) do
31+
+ string.gsub(/&lt;\/?(?:#{elements.join("|")})\b(?>[^&]+|&(?![gl]t;)\w+;)*(?:&gt;)?/im) do
32+
unescapeHTML($&)
33+
end
34+
else
35+
diff --git a/test/cgi/test_cgi_util.rb b/test/cgi/test_cgi_util.rb
36+
index b0612fc..bff77f7 100644
37+
--- a/test/cgi/test_cgi_util.rb
38+
+++ b/test/cgi/test_cgi_util.rb
39+
@@ -269,6 +269,14 @@ def test_cgi_escapeElement
40+
assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"]))
41+
assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<BR><A HREF="url"></A>', "A", "IMG"))
42+
assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<BR><A HREF="url"></A>', ["A", "IMG"]))
43+
+
44+
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<A <A HREF="url"></A>', "A", "IMG"))
45+
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<A <A HREF="url"></A>', ["A", "IMG"]))
46+
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<A <A HREF="url"></A>', "A", "IMG"))
47+
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<A <A HREF="url"></A>', ["A", "IMG"]))
48+
+
49+
+ assert_equal("&lt;A &lt;A ", escapeElement('<A <A ', "A", "IMG"))
50+
+ assert_equal("&lt;A &lt;A ", escapeElement('<A <A ', ["A", "IMG"]))
51+
end
52+
53+
54+
@@ -277,6 +285,16 @@ def test_cgi_unescapeElement
55+
assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescapeElement(escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"]))
56+
assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescape_element(escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG"))
57+
assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescape_element(escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"]))
58+
+
59+
+ assert_equal('<A <A HREF="url"></A>', unescapeElement(escapeHTML('<A <A HREF="url"></A>'), "A", "IMG"))
60+
+ assert_equal('<A <A HREF="url"></A>', unescapeElement(escapeHTML('<A <A HREF="url"></A>'), ["A", "IMG"]))
61+
+ assert_equal('<A <A HREF="url"></A>', unescape_element(escapeHTML('<A <A HREF="url"></A>'), "A", "IMG"))
62+
+ assert_equal('<A <A HREF="url"></A>', unescape_element(escapeHTML('<A <A HREF="url"></A>'), ["A", "IMG"]))
63+
+
64+
+ assert_equal('<A <A ', unescapeElement(escapeHTML('<A <A '), "A", "IMG"))
65+
+ assert_equal('<A <A ', unescapeElement(escapeHTML('<A <A '), ["A", "IMG"]))
66+
+ assert_equal('<A <A ', unescape_element(escapeHTML('<A <A '), "A", "IMG"))
67+
+ assert_equal('<A <A ', unescape_element(escapeHTML('<A <A '), ["A", "IMG"]))
68+
end
69+
end
70+

SPECS/ruby/CVE-2025-27221.patch

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
From b810324045d68969f1a7fb2113a0eeba6bcb5e34 Mon Sep 17 00:00:00 2001
2+
From: Kanishk-Bansal <kbkanishk975@gmail.com>
3+
Date: Mon, 10 Mar 2025 05:51:28 +0000
4+
Subject: [PATCH] CVE-2025-27221
5+
6+
Upstream Reference : https://github.com/ruby/uri/pull/155
7+
---
8+
lib/uri/generic.rb | 15 +++++++--------
9+
test/uri/test_generic.rb | 18 ++++++++++++++++++
10+
2 files changed, 25 insertions(+), 8 deletions(-)
11+
12+
diff --git a/lib/uri/generic.rb b/lib/uri/generic.rb
13+
index f3540a2..2c0a88d 100644
14+
--- a/lib/uri/generic.rb
15+
+++ b/lib/uri/generic.rb
16+
@@ -1133,17 +1133,16 @@ module URI
17+
base.fragment=(nil)
18+
19+
# RFC2396, Section 5.2, 4)
20+
- if !authority
21+
- base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path
22+
- else
23+
- # RFC2396, Section 5.2, 4)
24+
- base.set_path(rel.path) if rel.path
25+
+ if authority
26+
+ base.set_userinfo(rel.userinfo)
27+
+ base.set_host(rel.host)
28+
+ base.set_port(rel.port || base.default_port)
29+
+ base.set_path(rel.path)
30+
+ elsif base.path && rel.path
31+
+ base.set_path(merge_path(base.path, rel.path))
32+
end
33+
34+
# RFC2396, Section 5.2, 7)
35+
- base.set_userinfo(rel.userinfo) if rel.userinfo
36+
- base.set_host(rel.host) if rel.host
37+
- base.set_port(rel.port) if rel.port
38+
base.query = rel.query if rel.query
39+
base.fragment=(rel.fragment) if rel.fragment
40+
41+
diff --git a/test/uri/test_generic.rb b/test/uri/test_generic.rb
42+
index e661937..1a70dd4 100644
43+
--- a/test/uri/test_generic.rb
44+
+++ b/test/uri/test_generic.rb
45+
@@ -164,6 +164,17 @@ class URI::TestGeneric < Test::Unit::TestCase
46+
# must be empty string to identify as path-abempty, not path-absolute
47+
assert_equal('', url.host)
48+
assert_equal('http:////example.com', url.to_s)
49+
+
50+
+ # sec-2957667
51+
+ url = URI.parse('http://user:pass@example.com').merge('//example.net')
52+
+ assert_equal('http://example.net', url.to_s)
53+
+ assert_nil(url.userinfo)
54+
+ url = URI.join('http://user:pass@example.com', '//example.net')
55+
+ assert_equal('http://example.net', url.to_s)
56+
+ assert_nil(url.userinfo)
57+
+ url = URI.parse('http://user:pass@example.com') + '//example.net'
58+
+ assert_equal('http://example.net', url.to_s)
59+
+ assert_nil(url.userinfo)
60+
end
61+
62+
def test_parse_scheme_with_symbols
63+
@@ -256,6 +267,13 @@ class URI::TestGeneric < Test::Unit::TestCase
64+
assert_equal(u0, u1)
65+
end
66+
67+
+ def test_merge_authority
68+
+ u = URI.parse('http://user:pass@example.com:8080')
69+
+ u0 = URI.parse('http://new.example.org/path')
70+
+ u1 = u.merge('//new.example.org/path')
71+
+ assert_equal(u0, u1)
72+
+ end
73+
+
74+
def test_route
75+
url = URI.parse('http://hoge/a.html').route_to('http://hoge/b.html')
76+
assert_equal('b.html', url.to_s)
77+
--
78+
2.45.2
79+

SPECS/ruby/ruby.spec

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ Name: ruby
8383
# provides should be versioned according to the ruby version.
8484
# More info: https://stdgems.org/
8585
Version: 3.1.4
86-
Release: 8%{?dist}
86+
Release: 9%{?dist}
8787
License: (Ruby OR BSD) AND Public Domain AND MIT AND CC0 AND zlib AND UCD
8888
Vendor: Microsoft Corporation
8989
Distribution: Mariner
@@ -108,6 +108,9 @@ Patch4: CVE-2024-35176.patch
108108
Patch5: CVE-2024-41946.patch
109109
# Patch no longer needed if REXML gem is 3.3.9 or later. Now is 3.2.5
110110
Patch6: CVE-2024-49761.patch
111+
Patch7: CVE-2025-27219.patch
112+
Patch8: CVE-2025-27220.patch
113+
Patch9: CVE-2025-27221.patch
111114
BuildRequires: openssl-devel
112115
BuildRequires: readline
113116
BuildRequires: readline-devel
@@ -410,6 +413,9 @@ sudo -u test make test TESTS="-v"
410413
%{_rpmconfigdir}/rubygems.con
411414

412415
%changelog
416+
* Mon Mar 10 2025 Kanishk Bansal <kanbansal@microsoft.com> - 3.1.4-9
417+
- Patch CVE-2025-27219, CVE-2025-27220, CVE-2025-27221
418+
413419
* Mon Nov 04 2024 Saul Paredes <saulparedes@microsoft.com> - 3.1.4-8
414420
- Patch CVE-2024-49761
415421

0 commit comments

Comments
 (0)