diff options
-rw-r--r-- | meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0001.patch | 212 | ||||
-rw-r--r-- | meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0002.patch | 130 | ||||
-rw-r--r-- | meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0003.patch (renamed from meta/recipes-devtools/ruby/ruby/CVE-2024-43398.patch) | 23 | ||||
-rw-r--r-- | meta/recipes-devtools/ruby/ruby_3.1.3.bb | 4 |
4 files changed, 355 insertions, 14 deletions
diff --git a/meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0001.patch b/meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0001.patch new file mode 100644 index 0000000000..6c4869bc8c --- /dev/null +++ b/meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0001.patch | |||
@@ -0,0 +1,212 @@ | |||
1 | From 0496940d5998ccbc50d16fb734993ab50fc60c2d Mon Sep 17 00:00:00 2001 | ||
2 | From: NAITOH Jun <naitoh@gmail.com> | ||
3 | Date: Mon, 18 Mar 2024 23:30:47 +0900 | ||
4 | Subject: [PATCH] Optimize the parse_attributes method to use `Source#match` | ||
5 | to parse XML. (#119) | ||
6 | |||
7 | ## Why? | ||
8 | |||
9 | Improve maintainability by consolidating processing into `Source#match`. | ||
10 | |||
11 | ## Benchmark | ||
12 | ``` | ||
13 | RUBYLIB= BUNDLER_ORIG_RUBYLIB= /Users/naitoh/.rbenv/versions/3.3.0/bin/ruby -v -S benchmark-driver /Users/naitoh/ghq/github.com/naitoh/rexml/benchmark/parse.yaml | ||
14 | ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin22] | ||
15 | Calculating ------------------------------------- | ||
16 | before after before(YJIT) after(YJIT) | ||
17 | dom 10.891 10.622 16.356 17.403 i/s - 100.000 times in 9.182130s 9.414177s 6.113806s 5.746133s | ||
18 | sax 30.335 29.845 49.749 54.877 i/s - 100.000 times in 3.296483s 3.350595s 2.010071s 1.822259s | ||
19 | pull 35.514 34.801 61.123 66.908 i/s - 100.000 times in 2.815793s 2.873484s 1.636041s 1.494591s | ||
20 | stream 35.141 34.475 52.110 56.836 i/s - 100.000 times in 2.845646s 2.900638s 1.919017s 1.759456s | ||
21 | |||
22 | Comparison: | ||
23 | dom | ||
24 | after(YJIT): 17.4 i/s | ||
25 | before(YJIT): 16.4 i/s - 1.06x slower | ||
26 | before: 10.9 i/s - 1.60x slower | ||
27 | after: 10.6 i/s - 1.64x slower | ||
28 | |||
29 | sax | ||
30 | after(YJIT): 54.9 i/s | ||
31 | before(YJIT): 49.7 i/s - 1.10x slower | ||
32 | before: 30.3 i/s - 1.81x slower | ||
33 | after: 29.8 i/s - 1.84x slower | ||
34 | |||
35 | pull | ||
36 | after(YJIT): 66.9 i/s | ||
37 | before(YJIT): 61.1 i/s - 1.09x slower | ||
38 | before: 35.5 i/s - 1.88x slower | ||
39 | after: 34.8 i/s - 1.92x slower | ||
40 | |||
41 | stream | ||
42 | after(YJIT): 56.8 i/s | ||
43 | before(YJIT): 52.1 i/s - 1.09x slower | ||
44 | before: 35.1 i/s - 1.62x slower | ||
45 | after: 34.5 i/s - 1.65x slower | ||
46 | |||
47 | ``` | ||
48 | |||
49 | - YJIT=ON : 1.06x - 1.10x faster | ||
50 | - YJIT=OFF : 0.97x - 0.98x faster | ||
51 | |||
52 | CVE: CVE-2024-43398 | ||
53 | |||
54 | Upstream-Status: Backport [https://github.com/ruby/rexml/commit/0496940d5998ccbc50d16fb734993ab50fc60c2d] | ||
55 | |||
56 | Signed-off-by: Rob Woolley <rob.woolley@windriver.com> | ||
57 | --- | ||
58 | lib/rexml/parsers/baseparser.rb | 116 ++++++++++++-------------------- | ||
59 | test/parse/test_element.rb | 4 +- | ||
60 | test/test_core.rb | 20 +++++- | ||
61 | 3 files changed, 64 insertions(+), 76 deletions(-) | ||
62 | |||
63 | Index: ruby-3.1.3/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb | ||
64 | =================================================================== | ||
65 | --- ruby-3.1.3.orig/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb | ||
66 | +++ ruby-3.1.3/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb | ||
67 | @@ -114,7 +114,7 @@ module REXML | ||
68 | |||
69 | module Private | ||
70 | INSTRUCTION_END = /#{NAME}(\s+.*?)?\?>/um | ||
71 | - TAG_PATTERN = /((?>#{QNAME_STR}))/um | ||
72 | + TAG_PATTERN = /((?>#{QNAME_STR}))\s*/um | ||
73 | CLOSE_PATTERN = /(#{QNAME_STR})\s*>/um | ||
74 | ATTLISTDECL_END = /\s+#{NAME}(?:#{ATTDEF})*\s*>/um | ||
75 | NAME_PATTERN = /\s*#{NAME}/um | ||
76 | @@ -136,7 +136,6 @@ module REXML | ||
77 | self.stream = source | ||
78 | @listeners = [] | ||
79 | @entity_expansion_count = 0 | ||
80 | - @attributes_scanner = StringScanner.new('') | ||
81 | end | ||
82 | |||
83 | def add_listener( listener ) | ||
84 | @@ -635,86 +634,60 @@ module REXML | ||
85 | def parse_attributes(prefixes, curr_ns) | ||
86 | attributes = {} | ||
87 | closed = false | ||
88 | - match_data = @source.match(/^(.*?)(\/)?>/um, true) | ||
89 | - if match_data.nil? | ||
90 | - message = "Start tag isn't ended" | ||
91 | - raise REXML::ParseException.new(message, @source) | ||
92 | - end | ||
93 | + while true | ||
94 | + if @source.match(">", true) | ||
95 | + return attributes, closed | ||
96 | + elsif @source.match("/>", true) | ||
97 | + closed = true | ||
98 | + return attributes, closed | ||
99 | + elsif match = @source.match(QNAME, true) | ||
100 | + name = match[1] | ||
101 | + prefix = match[2] | ||
102 | + local_part = match[3] | ||
103 | |||
104 | - raw_attributes = match_data[1] | ||
105 | - closed = !match_data[2].nil? | ||
106 | - return attributes, closed if raw_attributes.nil? | ||
107 | - return attributes, closed if raw_attributes.empty? | ||
108 | - | ||
109 | - @attributes_scanner.string = raw_attributes | ||
110 | - scanner = @attributes_scanner | ||
111 | - until scanner.eos? | ||
112 | - if scanner.scan(/\s+/) | ||
113 | - break if scanner.eos? | ||
114 | - end | ||
115 | - | ||
116 | - pos = scanner.pos | ||
117 | - while true | ||
118 | - break if scanner.scan(ATTRIBUTE_PATTERN) | ||
119 | - unless scanner.scan(QNAME) | ||
120 | - message = "Invalid attribute name: <#{scanner.rest}>" | ||
121 | - raise REXML::ParseException.new(message, @source) | ||
122 | - end | ||
123 | - name = scanner[0] | ||
124 | - unless scanner.scan(/\s*=\s*/um) | ||
125 | + unless @source.match(/\s*=\s*/um, true) | ||
126 | message = "Missing attribute equal: <#{name}>" | ||
127 | raise REXML::ParseException.new(message, @source) | ||
128 | end | ||
129 | - quote = scanner.scan(/['"]/) | ||
130 | - unless quote | ||
131 | - message = "Missing attribute value start quote: <#{name}>" | ||
132 | - raise REXML::ParseException.new(message, @source) | ||
133 | - end | ||
134 | - unless scanner.scan(/.*#{Regexp.escape(quote)}/um) | ||
135 | - match_data = @source.match(/^(.*?)(\/)?>/um, true) | ||
136 | - if match_data | ||
137 | - scanner << "/" if closed | ||
138 | - scanner << ">" | ||
139 | - scanner << match_data[1] | ||
140 | - scanner.pos = pos | ||
141 | - closed = !match_data[2].nil? | ||
142 | - next | ||
143 | + unless match = @source.match(/(['"])(.*?)\1\s*/um, true) | ||
144 | + if match = @source.match(/(['"])/, true) | ||
145 | + message = | ||
146 | + "Missing attribute value end quote: <#{name}>: <#{match[1]}>" | ||
147 | + raise REXML::ParseException.new(message, @source) | ||
148 | + else | ||
149 | + message = "Missing attribute value start quote: <#{name}>" | ||
150 | + raise REXML::ParseException.new(message, @source) | ||
151 | end | ||
152 | - message = | ||
153 | - "Missing attribute value end quote: <#{name}>: <#{quote}>" | ||
154 | - raise REXML::ParseException.new(message, @source) | ||
155 | end | ||
156 | - end | ||
157 | - name = scanner[1] | ||
158 | - prefix = scanner[2] | ||
159 | - local_part = scanner[3] | ||
160 | - # quote = scanner[4] | ||
161 | - value = scanner[5] | ||
162 | - if prefix == "xmlns" | ||
163 | - if local_part == "xml" | ||
164 | - if value != "http://www.w3.org/XML/1998/namespace" | ||
165 | - msg = "The 'xml' prefix must not be bound to any other namespace "+ | ||
166 | + value = match[2] | ||
167 | + if prefix == "xmlns" | ||
168 | + if local_part == "xml" | ||
169 | + if value != "http://www.w3.org/XML/1998/namespace" | ||
170 | + msg = "The 'xml' prefix must not be bound to any other namespace "+ | ||
171 | + "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" | ||
172 | + raise REXML::ParseException.new( msg, @source, self ) | ||
173 | + end | ||
174 | + elsif local_part == "xmlns" | ||
175 | + msg = "The 'xmlns' prefix must not be declared "+ | ||
176 | "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" | ||
177 | - raise REXML::ParseException.new( msg, @source, self ) | ||
178 | + raise REXML::ParseException.new( msg, @source, self) | ||
179 | end | ||
180 | - elsif local_part == "xmlns" | ||
181 | - msg = "The 'xmlns' prefix must not be declared "+ | ||
182 | - "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" | ||
183 | - raise REXML::ParseException.new( msg, @source, self) | ||
184 | + curr_ns << local_part | ||
185 | + elsif prefix | ||
186 | + prefixes << prefix unless prefix == "xml" | ||
187 | end | ||
188 | - curr_ns << local_part | ||
189 | - elsif prefix | ||
190 | - prefixes << prefix unless prefix == "xml" | ||
191 | - end | ||
192 | |||
193 | - if attributes.has_key?(name) | ||
194 | - msg = "Duplicate attribute #{name.inspect}" | ||
195 | - raise REXML::ParseException.new(msg, @source, self) | ||
196 | - end | ||
197 | + if attributes.has_key?(name) | ||
198 | + msg = "Duplicate attribute #{name.inspect}" | ||
199 | + raise REXML::ParseException.new(msg, @source, self) | ||
200 | + end | ||
201 | |||
202 | - attributes[name] = value | ||
203 | + attributes[name] = value | ||
204 | + else | ||
205 | + message = "Invalid attribute name: <#{@source.buffer.split(%r{[/>\s]}).first}>" | ||
206 | + raise REXML::ParseException.new(message, @source) | ||
207 | + end | ||
208 | end | ||
209 | - return attributes, closed | ||
210 | end | ||
211 | end | ||
212 | end | ||
diff --git a/meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0002.patch b/meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0002.patch new file mode 100644 index 0000000000..e091aa7e79 --- /dev/null +++ b/meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0002.patch | |||
@@ -0,0 +1,130 @@ | |||
1 | From cb158582f18cebb3bf7b3f21f230e2fb17d435aa Mon Sep 17 00:00:00 2001 | ||
2 | From: Sutou Kouhei <kou@clear-code.com> | ||
3 | Date: Sat, 17 Aug 2024 17:39:14 +0900 | ||
4 | Subject: [PATCH] parser: keep the current namespaces instead of stack of Set | ||
5 | |||
6 | It improves namespace resolution performance for deep element. | ||
7 | |||
8 | CVE: CVE-2024-43398 | ||
9 | |||
10 | Upstream-Status: Backport [https://github.com/ruby/rexml/commit/cb158582f18cebb3bf7b3f21f230e2fb17d435aa] | ||
11 | |||
12 | Signed-off-by: Rob Woolley <rob.woolley@windriver.com> | ||
13 | |||
14 | --- | ||
15 | lib/rexml/parsers/baseparser.rb | 45 +++++++++++++++++++++++++-------- | ||
16 | 1 file changed, 35 insertions(+), 10 deletions(-) | ||
17 | |||
18 | Index: ruby-3.1.3/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb | ||
19 | =================================================================== | ||
20 | --- ruby-3.1.3.orig/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb | ||
21 | +++ ruby-3.1.3/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb | ||
22 | @@ -152,7 +152,8 @@ module REXML | ||
23 | @tags = [] | ||
24 | @stack = [] | ||
25 | @entities = [] | ||
26 | - @nsstack = [] | ||
27 | + @namespaces = {} | ||
28 | + @namespaces_restore_stack = [] | ||
29 | end | ||
30 | |||
31 | def position | ||
32 | @@ -235,7 +236,6 @@ module REXML | ||
33 | @source.string = "<!DOCTYPE" + @source.buffer | ||
34 | raise REXML::ParseException.new(message, @source) | ||
35 | end | ||
36 | - @nsstack.unshift(curr_ns=Set.new) | ||
37 | name = parse_name(base_error_message) | ||
38 | if @source.match(/\s*\[/um, true) | ||
39 | id = [nil, nil, nil] | ||
40 | @@ -320,7 +320,7 @@ module REXML | ||
41 | val = attdef[4] if val == "#FIXED " | ||
42 | pairs[attdef[0]] = val | ||
43 | if attdef[0] =~ /^xmlns:(.*)/ | ||
44 | - @nsstack[0] << $1 | ||
45 | + @namespaces[$1] = val | ||
46 | end | ||
47 | end | ||
48 | end | ||
49 | @@ -365,7 +365,7 @@ module REXML | ||
50 | begin | ||
51 | if @source.match("<", true) | ||
52 | if @source.match("/", true) | ||
53 | - @nsstack.shift | ||
54 | + @namespaces_restore_stack.pop | ||
55 | last_tag = @tags.pop | ||
56 | md = @source.match(CLOSE_PATTERN, true) | ||
57 | if md and !last_tag | ||
58 | @@ -411,18 +411,18 @@ module REXML | ||
59 | @document_status = :in_element | ||
60 | prefixes = Set.new | ||
61 | prefixes << md[2] if md[2] | ||
62 | - @nsstack.unshift(curr_ns=Set.new) | ||
63 | - attributes, closed = parse_attributes(prefixes, curr_ns) | ||
64 | + push_namespaces_restore | ||
65 | + attributes, closed = parse_attributes(@prefixes) | ||
66 | # Verify that all of the prefixes have been defined | ||
67 | for prefix in prefixes | ||
68 | - unless @nsstack.find{|k| k.member?(prefix)} | ||
69 | + unless @namespaces.key?(prefix) | ||
70 | raise UndefinedNamespaceException.new(prefix,@source,self) | ||
71 | end | ||
72 | end | ||
73 | |||
74 | if closed | ||
75 | @closed = tag | ||
76 | - @nsstack.shift | ||
77 | + pop_namespaces_restore | ||
78 | else | ||
79 | @tags.push( tag ) | ||
80 | end | ||
81 | @@ -512,6 +512,31 @@ module REXML | ||
82 | end | ||
83 | |||
84 | private | ||
85 | + def add_namespace(prefix, uri) | ||
86 | + @namespaces_restore_stack.last[prefix] = @namespaces[prefix] | ||
87 | + if uri.nil? | ||
88 | + @namespaces.delete(prefix) | ||
89 | + else | ||
90 | + @namespaces[prefix] = uri | ||
91 | + end | ||
92 | + end | ||
93 | + | ||
94 | + def push_namespaces_restore | ||
95 | + namespaces_restore = {} | ||
96 | + @namespaces_restore_stack.push(namespaces_restore) | ||
97 | + namespaces_restore | ||
98 | + end | ||
99 | + | ||
100 | + def pop_namespaces_restore | ||
101 | + namespaces_restore = @namespaces_restore_stack.pop | ||
102 | + namespaces_restore.each do |prefix, uri| | ||
103 | + if uri.nil? | ||
104 | + @namespaces.delete(prefix) | ||
105 | + else | ||
106 | + @namespaces[prefix] = uri | ||
107 | + end | ||
108 | + end | ||
109 | + end | ||
110 | |||
111 | def record_entity_expansion | ||
112 | @entity_expansion_count += 1 | ||
113 | @@ -631,7 +656,7 @@ module REXML | ||
114 | [:processing_instruction, match_data[1], match_data[2]] | ||
115 | end | ||
116 | |||
117 | - def parse_attributes(prefixes, curr_ns) | ||
118 | + def parse_attributes(prefixes) | ||
119 | attributes = {} | ||
120 | closed = false | ||
121 | while true | ||
122 | @@ -672,7 +697,7 @@ module REXML | ||
123 | "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" | ||
124 | raise REXML::ParseException.new( msg, @source, self) | ||
125 | end | ||
126 | - curr_ns << local_part | ||
127 | + add_namespace(local_part, value) | ||
128 | elsif prefix | ||
129 | prefixes << prefix unless prefix == "xml" | ||
130 | end | ||
diff --git a/meta/recipes-devtools/ruby/ruby/CVE-2024-43398.patch b/meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0003.patch index 02dc0a20be..2a48aabbc5 100644 --- a/meta/recipes-devtools/ruby/ruby/CVE-2024-43398.patch +++ b/meta/recipes-devtools/ruby/ruby/CVE-2024-43398-0003.patch | |||
@@ -47,17 +47,17 @@ diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb b/.bundle/ | |||
47 | index e32c7f4..154f2ac 100644 | 47 | index e32c7f4..154f2ac 100644 |
48 | --- a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb | 48 | --- a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb |
49 | +++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb | 49 | +++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb |
50 | @@ -634,6 +634,7 @@ module REXML | 50 | @@ -658,6 +658,7 @@ module REXML |
51 | 51 | ||
52 | def parse_attributes(prefixes, curr_ns) | 52 | def parse_attributes(prefixes) |
53 | attributes = {} | 53 | attributes = {} |
54 | + expanded_names = {} | 54 | + expanded_names = {} |
55 | closed = false | 55 | closed = false |
56 | match_data = @source.match(/^(.*?)(\/)?>/um, true) | 56 | while true |
57 | if match_data.nil? | 57 | if @source.match(">", true) |
58 | @@ -641,6 +642,20 @@ module REXML | 58 | @@ -707,6 +708,20 @@ module REXML |
59 | raise REXML::ParseException.new(message, @source) | 59 | raise REXML::ParseException.new(msg, @source, self) |
60 | end | 60 | end |
61 | 61 | ||
62 | + unless prefix == "xmlns" | 62 | + unless prefix == "xmlns" |
63 | + uri = @namespaces[prefix] | 63 | + uri = @namespaces[prefix] |
@@ -73,9 +73,6 @@ index e32c7f4..154f2ac 100644 | |||
73 | + expanded_names[expanded_name] = prefix | 73 | + expanded_names[expanded_name] = prefix |
74 | + end | 74 | + end |
75 | + | 75 | + |
76 | raw_attributes = match_data[1] | 76 | attributes[name] = value |
77 | closed = !match_data[2].nil? | 77 | else |
78 | return attributes, closed if raw_attributes.nil? | 78 | message = "Invalid attribute name: <#{@source.buffer.split(%r{[/>\s]}).first}>" |
79 | -- | ||
80 | 2.40.0 | ||
81 | |||
diff --git a/meta/recipes-devtools/ruby/ruby_3.1.3.bb b/meta/recipes-devtools/ruby/ruby_3.1.3.bb index 65d62002ec..19641e5a51 100644 --- a/meta/recipes-devtools/ruby/ruby_3.1.3.bb +++ b/meta/recipes-devtools/ruby/ruby_3.1.3.bb | |||
@@ -48,7 +48,9 @@ SRC_URI = "http://cache.ruby-lang.org/pub/ruby/${SHRT_VER}/ruby-${PV}.tar.gz \ | |||
48 | file://CVE-2024-41946.patch \ | 48 | file://CVE-2024-41946.patch \ |
49 | file://CVE-2025-27220.patch \ | 49 | file://CVE-2025-27220.patch \ |
50 | file://CVE-2025-27219.patch \ | 50 | file://CVE-2025-27219.patch \ |
51 | file://CVE-2024-43398.patch \ | 51 | file://CVE-2024-43398-0001.patch \ |
52 | file://CVE-2024-43398-0002.patch \ | ||
53 | file://CVE-2024-43398-0003.patch \ | ||
52 | file://CVE-2025-27221-0001.patch \ | 54 | file://CVE-2025-27221-0001.patch \ |
53 | file://CVE-2025-27221-0002.patch \ | 55 | file://CVE-2025-27221-0002.patch \ |
54 | " | 56 | " |