Skip to content

Commit 71bcaf0

Browse files
tenderloveflavorjones
authored andcommitted
Work around a bug in libxml2
This commit works around a bug in libxml2 where parsing schemas can result in dangling pointers which can lead to a segv. Upstream bug is here: https://gitlab.gnome.org/GNOME/libxml2/issues/148 Fixes #1985
1 parent 6ce10d1 commit 71bcaf0

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

ext/nokogiri/xml_schema.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,31 @@ static VALUE read_memory(VALUE klass, VALUE content)
133133
return rb_schema;
134134
}
135135

136+
/* Schema creation will remove and deallocate "blank" nodes.
137+
* If those blank nodes have been exposed to Ruby, they could get freed
138+
* out from under the VALUE pointer. This function checks to see if any of
139+
* those nodes have been exposed to Ruby, and if so we should raise an exception.
140+
*/
141+
static int has_blank_nodes_p(VALUE cache)
142+
{
143+
long i;
144+
145+
if (NIL_P(cache)) {
146+
return 0;
147+
}
148+
149+
for (i = 0; i < RARRAY_LEN(cache); i++) {
150+
xmlNodePtr node;
151+
VALUE element = rb_ary_entry(cache, i);
152+
Data_Get_Struct(element, xmlNode, node);
153+
if (xmlIsBlankNode(node)) {
154+
return 1;
155+
}
156+
}
157+
158+
return 0;
159+
}
160+
136161
/*
137162
* call-seq:
138163
* from_document(doc)
@@ -152,6 +177,10 @@ static VALUE from_document(VALUE klass, VALUE document)
152177
/* In case someone passes us a node. ugh. */
153178
doc = doc->doc;
154179

180+
if (has_blank_nodes_p(DOC_NODE_CACHE(doc))) {
181+
rb_raise(rb_eArgError, "Creating a schema from a document that has blank nodes exposed to Ruby is dangerous");
182+
}
183+
155184
ctx = xmlSchemaNewDocParserCtxt(doc);
156185

157186
errors = rb_ary_new();

test/xml/test_schema.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,34 @@ def setup
77
assert @xsd = Nokogiri::XML::Schema(File.read(PO_SCHEMA_FILE))
88
end
99

10+
def test_segv
11+
skip("Pure Java version shouldn't have this bug") unless Nokogiri.uses_libxml?
12+
13+
# This is a test for a workaround for a bug in LibXML2. The upstream
14+
# bug is here: https://gitlab.gnome.org/GNOME/libxml2/issues/148
15+
# Schema creation can result in dangling pointers. If no nodes have
16+
# been exposed, then it should be fine to create a schema. If nodes
17+
# have been exposed to Ruby, then we need to make sure they won't be
18+
# freed out from under us.
19+
doc = <<~doc
20+
<?xml version="1.0" encoding="UTF-8" ?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
21+
<xs:element name="foo" type="xs:string"/></xs:schema>
22+
doc
23+
24+
# This is OK, no nodes have been exposed
25+
xsd_doc = Nokogiri::XML(doc)
26+
assert Nokogiri::XML::Schema.from_document(xsd_doc)
27+
28+
# This is not OK, nodes have been exposed to Ruby
29+
xsd_doc = Nokogiri::XML(doc)
30+
node = xsd_doc.root.children.find(&:blank?) # Finds a node
31+
32+
ex = assert_raise(ArgumentError) do
33+
Nokogiri::XML::Schema.from_document(xsd_doc)
34+
end
35+
assert_match(/blank nodes/, ex.message)
36+
end
37+
1038
def test_schema_from_document
1139
doc = Nokogiri::XML(File.open(PO_SCHEMA_FILE))
1240
assert doc

0 commit comments

Comments
 (0)