Skip to content

Commit 222de00

Browse files
authored
add patch for rubygem-rexml CVE-2024-35176 (#9242)
Co-authored-by: minghe <rmhsawyer>
1 parent fea7c96 commit 222de00

2 files changed

Lines changed: 196 additions & 2 deletions

File tree

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
diff -ruN a/Gemfile b/Gemfile
2+
--- a/Gemfile 2021-04-05 04:43:38.000000000 -0700
3+
+++ b/Gemfile 2024-05-29 00:06:13.851182285 -0700
4+
@@ -4,3 +4,7 @@
5+
6+
# Specify your gem's dependencies in rexml.gemspec
7+
gemspec
8+
+
9+
+group :development do
10+
+ gem "test-unit-ruby-core"
11+
+end
12+
diff -ruN a/lib/rexml/parsers/baseparser.rb b/lib/rexml/parsers/baseparser.rb
13+
--- a/lib/rexml/parsers/baseparser.rb 2021-04-05 04:43:38.000000000 -0700
14+
+++ b/lib/rexml/parsers/baseparser.rb 2024-05-28 18:53:32.656078157 -0700
15+
@@ -589,60 +589,41 @@
16+
def parse_attributes(prefixes, curr_ns)
17+
attributes = {}
18+
closed = false
19+
- match_data = @source.match(/^(.*?)(\/)?>/um, true)
20+
- if match_data.nil?
21+
- message = "Start tag isn't ended"
22+
- raise REXML::ParseException.new(message, @source)
23+
- end
24+
-
25+
- raw_attributes = match_data[1]
26+
- closed = !match_data[2].nil?
27+
- return attributes, closed if raw_attributes.nil?
28+
- return attributes, closed if raw_attributes.empty?
29+
-
30+
- scanner = StringScanner.new(raw_attributes)
31+
- until scanner.eos?
32+
- if scanner.scan(/\s+/)
33+
- break if scanner.eos?
34+
- end
35+
-
36+
- pos = scanner.pos
37+
- loop do
38+
- break if scanner.scan(ATTRIBUTE_PATTERN)
39+
- unless scanner.scan(QNAME)
40+
- message = "Invalid attribute name: <#{scanner.rest}>"
41+
- raise REXML::ParseException.new(message, @source)
42+
- end
43+
- name = scanner[0]
44+
- unless scanner.scan(/\s*=\s*/um)
45+
+ while true
46+
+ if @source.match(">", true)
47+
+ return attributes, closed
48+
+ elsif @source.match("/>", true)
49+
+ closed = true
50+
+ return attributes, closed
51+
+ elsif match = @source.match(QNAME, true)
52+
+ name = match[1]
53+
+ prefix = match[2]
54+
+ local_part = match[3]
55+
+ unless @source.match(/\s*=\s*/um, true)
56+
message = "Missing attribute equal: <#{name}>"
57+
raise REXML::ParseException.new(message, @source)
58+
end
59+
- quote = scanner.scan(/['"]/)
60+
- unless quote
61+
+ unless match = @source.match(/(['"])(.*?)\1\s*/um, true)
62+
+ if match = @source.match(/(['"])/, true)
63+
+ message =
64+
+ "Missing attribute value end quote: <#{name}>: <#{match[1]}>"
65+
+ raise REXML::ParseException.new(message, @source)
66+
+ else
67+
+ message = "Missing attribute value start quote: <#{name}>"
68+
+ raise REXML::ParseException.new(message, @source)
69+
+ end
70+
+ unless match = @source.match(/(['"])/, true)
71+
message = "Missing attribute value start quote: <#{name}>"
72+
raise REXML::ParseException.new(message, @source)
73+
end
74+
- unless scanner.scan(/.*#{Regexp.escape(quote)}/um)
75+
- match_data = @source.match(/^(.*?)(\/)?>/um, true)
76+
- if match_data
77+
- scanner << "/" if closed
78+
- scanner << ">"
79+
- scanner << match_data[1]
80+
- scanner.pos = pos
81+
- closed = !match_data[2].nil?
82+
- next
83+
- end
84+
- message =
85+
- "Missing attribute value end quote: <#{name}>: <#{quote}>"
86+
+ quote = match[1]
87+
+ value = @source.read_until(quote)
88+
+ unless value.chomp!(quote)
89+
+ message = "Missing attribute value end quote: <#{name}>: <#{quote}>"
90+
raise REXML::ParseException.new(message, @source)
91+
end
92+
- end
93+
- name = scanner[1]
94+
- prefix = scanner[2]
95+
- local_part = scanner[3]
96+
- # quote = scanner[4]
97+
- value = scanner[5]
98+
+ value = match[2]
99+
+ @source.match(/\s*/um, true)
100+
if prefix == "xmlns"
101+
if local_part == "xml"
102+
if value != "http://www.w3.org/XML/1998/namespace"
103+
diff -ruN a/lib/rexml/source.rb b/lib/rexml/source.rb
104+
--- a/lib/rexml/source.rb 2021-04-05 04:43:38.000000000 -0700
105+
+++ b/lib/rexml/source.rb 2024-05-28 17:10:36.356913505 -0700
106+
@@ -81,7 +81,11 @@
107+
rv
108+
end
109+
110+
- def read
111+
+ def read(term = nil)
112+
+ end
113+
+
114+
+ def read_until(term)
115+
+ @scanner.scan_until(Regexp.union(term)) or @scanner.rest
116+
end
117+
118+
def consume( pattern )
119+
@@ -204,11 +208,28 @@
120+
rv
121+
end
122+
123+
- def read
124+
+ def read(term = nil)
125+
begin
126+
- @buffer << readline
127+
+ @scanner << readline(term)
128+
+ true
129+
rescue Exception, NameError
130+
@source = nil
131+
+ false
132+
+ end
133+
+ end
134+
+
135+
+ def read_until(term)
136+
+ pattern = Regexp.union(term)
137+
+ data = []
138+
+ begin
139+
+ until str = @scanner.scan_until(pattern)
140+
+ @scanner << readline(term)
141+
+ end
142+
+ rescue EOFError
143+
+ @scanner.rest
144+
+ else
145+
+ read if @scanner.eos? and !@source.eof?
146+
+ str
147+
end
148+
end
149+
150+
@@ -263,8 +284,8 @@
151+
end
152+
153+
private
154+
- def readline
155+
- str = @source.readline(@line_break)
156+
+ def readline(term = nil)
157+
+ str = @source.readline(term || @line_break)
158+
if @pending_buffer
159+
if str.nil?
160+
str = @pending_buffer
161+
diff -ruN a/test/test_document.rb b/test/test_document.rb
162+
--- a/test/test_document.rb 2021-04-05 04:43:38.000000000 -0700
163+
+++ b/test/test_document.rb 2024-05-29 00:08:01.164345808 -0700
164+
@@ -1,8 +1,12 @@
165+
# -*- coding: utf-8 -*-
166+
# frozen_string_literal: false
167+
168+
+require 'core_assertions'
169+
+
170+
module REXMLTests
171+
class TestDocument < Test::Unit::TestCase
172+
+ include Test::Unit::CoreAssertions
173+
+
174+
def test_version_attributes_to_s
175+
doc = REXML::Document.new(<<-eoxml)
176+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
177+
@@ -200,6 +204,13 @@
178+
assert_equal('no', doc.stand_alone?, bug2539)
179+
end
180+
181+
+ def test_gt_linear_performance
182+
+ seq = [10000, 50000, 100000, 150000, 200000]
183+
+ assert_linear_performance(seq) do |n|
184+
+ REXML::Document.new('<test testing="' + ">" * n + '"></test>')
185+
+ end
186+
+ end
187+
+
188+
class WriteTest < Test::Unit::TestCase
189+
def setup
190+
@document = REXML::Document.new(<<-EOX)

SPECS/rubygem-rexml/rubygem-rexml.spec

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
Summary: REXML is an XML toolkit for Ruby
44
Name: rubygem-%{gem_name}
55
Version: 3.2.5
6-
Release: 1%{?dist}
6+
Release: 2%{?dist}
77
License: BSD
88
Vendor: Microsoft Corporation
99
Distribution: Mariner
1010
Group: Development/Languages
1111
URL: https://github.com/ruby/rexml
1212
Source0: https://github.com/ruby/rexml/archive/refs/tags/v%{version}.tar.gz#/%{gem_name}-%{version}.tar.gz
13+
Patch0: CVE-2024-35176.patch
1314
BuildRequires: git
1415
BuildRequires: ruby
1516
Requires: ruby(release)
@@ -20,7 +21,7 @@ REXML was inspired by the Electric XML library for Java, which features an easy-
2021
REXML supports both tree and stream document parsing. Stream parsing is faster (about 1.5 times as fast). However, with stream parsing, you don't get access to features such as XPath.
2122

2223
%prep
23-
%setup -q -n %{gem_name}-%{version}
24+
%autosetup -p1 -n %{gem_name}-%{version}
2425

2526
%build
2627
gem build %{gem_name}
@@ -34,6 +35,9 @@ gem install -V --local --force --install-dir %{buildroot}/%{gemdir} %{gem_name}-
3435
%{gemdir}
3536

3637
%changelog
38+
* Tue May 28 2024 Minghe Ren <mingheren@microsoft.com> - 3.2.5-2
39+
- Add patch for CVE-2024-35176
40+
3741
* Mon Jun 13 2022 Neha Agarwal <nehaagarwal@microsoft.com> - 3.2.5-1
3842
- License verified
3943
- Original version for CBL-Mariner

0 commit comments

Comments
 (0)