Address comments

This commit is contained in:
Arthur Baars
2021-09-24 15:27:53 +02:00
parent 2b077595ae
commit 089f9d87d4
4 changed files with 69 additions and 32 deletions

View File

@@ -90,40 +90,69 @@ private class FeatureDTDLOAD extends Feature, TDTDLOAD {
override string getConstantName() { result = "DTDLOAD" }
}
private API::Node parseOptionsModule() {
result = API::getTopLevelMember("Nokogiri").getMember("XML").getMember("ParseOptions")
or
result = API::getTopLevelMember("LibXML").getMember("XML").getMember("Options")
or
result = API::getTopLevelMember("XML").getMember("Options")
}
private DataFlow::LocalSourceNode trackFeature(Feature f, boolean enable, TypeTracker t) {
t.start() and
(
result.asExpr().getExpr().(IntegerLiteral).getValue().bitAnd(f.getValue()) = f.getValue() and
enable = true
// An integer literal with the feature-bit enabled/disabled
exists(int bitValue |
bitValue = result.asExpr().getExpr().(IntegerLiteral).getValue().bitAnd(f.getValue())
|
if bitValue = 0 then enable = false else enable = true
)
or
// Use of a constant f
enable = true and
result =
API::getTopLevelMember("Nokogiri")
.getMember("XML")
.getMember("ParseOptions")
.getMember(f.getConstantName())
.getAUse()
result = parseOptionsModule().getMember(f.getConstantName()).getAUse()
or
enable = true and
result =
[API::getTopLevelMember("LibXML").getMember("XML"), API::getTopLevelMember("XML")]
.getMember("Options")
.getMember(f.getConstantName())
.getAUse()
// If a feature is enabled in any of the operands of the `|` and `|=` operators
// then the feature is also enabled in the result of the operators.
exists(CfgNodes::ExprNodes::OperationCfgNode operation |
operation = result.asExpr().(CfgNodes::ExprNodes::OperationCfgNode) and
(
operation.getExpr() instanceof BitwiseOrExpr or
operation.getExpr() instanceof AssignBitwiseOrExpr
)
|
enable = true and
operation.getAnOperand() = trackFeature(f, true).asExpr()
or
enable = false and
operation.getAnOperand() = trackFeature(f, false).asExpr() and
forall(DataFlow::Node n | n.asExpr() = operation.getAnOperand() | n != trackFeature(f, true))
)
or
(
result.asExpr().getExpr() instanceof BitwiseOrExpr or
result.asExpr().getExpr() instanceof AssignBitwiseOrExpr or
result.asExpr().getExpr() instanceof BitwiseAndExpr or
result.asExpr().getExpr() instanceof AssignBitwiseAndExpr
) and
result.asExpr().(CfgNodes::ExprNodes::OperationCfgNode).getAnOperand() =
trackFeature(f, enable).asExpr()
// If a feature is disabled in any of the operands of the `&` and `&=` operators
// then the feature is also disabled in the result of the operators.
exists(CfgNodes::ExprNodes::OperationCfgNode operation |
operation = result.asExpr().(CfgNodes::ExprNodes::OperationCfgNode) and
(
operation.getExpr() instanceof BitwiseAndExpr or
operation.getExpr() instanceof AssignBitwiseAndExpr
)
|
enable = false and
operation.getAnOperand() = trackFeature(f, false).asExpr()
or
enable = true and
operation.getAnOperand() = trackFeature(f, true).asExpr() and
forall(DataFlow::Node n | n.asExpr() = operation.getAnOperand() | n != trackFeature(f, false))
)
or
// The complement operator toggles a feature from enabled to disabled and vice-versa
result.asExpr().getExpr() instanceof ComplementExpr and
result.asExpr().(CfgNodes::ExprNodes::OperationCfgNode).getAnOperand() =
trackFeature(f, enable.booleanNot()).asExpr()
or
// Nokogiri has a ParseOptions class that is a wrapper around the bit-fields and
// provides methods for querying and updating the fields.
result =
API::getTopLevelMember("Nokogiri")
.getMember("XML")
@@ -132,6 +161,9 @@ private DataFlow::LocalSourceNode trackFeature(Feature f, boolean enable, TypeTr
result.asExpr().(CfgNodes::ExprNodes::CallCfgNode).getArgument(0) =
trackFeature(f, enable).asExpr()
or
// The Nokogiri ParseOptions class has methods for setting/unsetting features.
// The method names are the lowercase variants of the constant names, with a "no"
// prefix for unsetting a feature.
exists(CfgNodes::ExprNodes::CallCfgNode call |
enable = true and
call.getExpr().(MethodCall).getMethodName() = f.getConstantName().toLowerCase()
@@ -140,16 +172,13 @@ private DataFlow::LocalSourceNode trackFeature(Feature f, boolean enable, TypeTr
call.getExpr().(MethodCall).getMethodName() = "no" + f.getConstantName().toLowerCase()
|
(
result.asExpr() = call
or
// these methods update the receiver
result.flowsTo(any(DataFlow::Node n | n.asExpr() = call.getReceiver()))
or
// in addition they return the (updated) receiver to allow chaining calls.
result.asExpr() = call
)
)
or
exists(CfgNodes::ExprNodes::CallCfgNode call |
trackFeature(f, enable).asExpr() = call.getReceiver() and
result.asExpr() = call
)
)
or
exists(TypeTracker t2 | result = trackFeature(f, enable, t2).track(t2, t))

View File

@@ -11,6 +11,6 @@ class LibXmlRubyXXE < ApplicationController
XML::Document.string(content, { options: 2 })
XML::Parser.string(content, { options: 2 })
LibXML::XML::Parser.file(content, { options: 1 }) # OK
LibXML::XML::Parser.file(content, { options: 2048 }) # OK
end

View File

@@ -16,13 +16,15 @@ class NokogiriXXE < ApplicationController
Nokogiri::XML::parse(content, nil, nil, (Nokogiri::XML::ParseOptions.new 0).noent)
Nokogiri::XML::parse(content) { |x| x.noent }
Nokogiri::XML::parse(content) { |x| x.nononet }
Nokogiri::XML::parse(content) { |x| x.nononet } #FAIL
Nokogiri::XML::parse(content) { |x| x.nodtdload } # OK
Nokogiri::XML::parse(content) { |x| x.nonet.noent.nodtdload }
Nokogiri::XML::parse(content, nil, nil, 1) # OK
Nokogiri::XML::parse(content, nil, nil, 2048) # OK
Nokogiri::XML::parse(content, nil, nil, 3)
Nokogiri::XML::parse(content) { |x| x.nonet.nodtdload } # OK
Nokogiri::XML::parse(content, nil, nil, Nokogiri::XML::ParseOptions::NOENT & ~Nokogiri::XML::ParseOptions::NOBLANKS)
Nokogiri::XML::parse(content, nil, nil, ~Nokogiri::XML::ParseOptions::NONET | Nokogiri::XML::ParseOptions::NOBLANKS)
end

View File

@@ -20,6 +20,8 @@ edges
| Nokogiri.rb:3:15:3:20 | call to params : | Nokogiri.rb:19:26:19:32 | content |
| Nokogiri.rb:3:15:3:20 | call to params : | Nokogiri.rb:22:26:22:32 | content |
| Nokogiri.rb:3:15:3:20 | call to params : | Nokogiri.rb:25:26:25:32 | content |
| Nokogiri.rb:3:15:3:20 | call to params : | Nokogiri.rb:27:26:27:32 | content |
| Nokogiri.rb:3:15:3:20 | call to params : | Nokogiri.rb:28:26:28:32 | content |
nodes
| LibXmlRuby.rb:3:15:3:20 | call to params : | semmle.label | call to params : |
| LibXmlRuby.rb:4:34:4:40 | content | semmle.label | content |
@@ -44,6 +46,8 @@ nodes
| Nokogiri.rb:19:26:19:32 | content | semmle.label | content |
| Nokogiri.rb:22:26:22:32 | content | semmle.label | content |
| Nokogiri.rb:25:26:25:32 | content | semmle.label | content |
| Nokogiri.rb:27:26:27:32 | content | semmle.label | content |
| Nokogiri.rb:28:26:28:32 | content | semmle.label | content |
subpaths
#select
| LibXmlRuby.rb:4:34:4:40 | content | LibXmlRuby.rb:3:15:3:20 | call to params : | LibXmlRuby.rb:4:34:4:40 | content | Unsafe parsing of XML file from $@. | LibXmlRuby.rb:3:15:3:20 | call to params | user input |
@@ -67,3 +71,5 @@ subpaths
| Nokogiri.rb:19:26:19:32 | content | Nokogiri.rb:3:15:3:20 | call to params : | Nokogiri.rb:19:26:19:32 | content | Unsafe parsing of XML file from $@. | Nokogiri.rb:3:15:3:20 | call to params | user input |
| Nokogiri.rb:22:26:22:32 | content | Nokogiri.rb:3:15:3:20 | call to params : | Nokogiri.rb:22:26:22:32 | content | Unsafe parsing of XML file from $@. | Nokogiri.rb:3:15:3:20 | call to params | user input |
| Nokogiri.rb:25:26:25:32 | content | Nokogiri.rb:3:15:3:20 | call to params : | Nokogiri.rb:25:26:25:32 | content | Unsafe parsing of XML file from $@. | Nokogiri.rb:3:15:3:20 | call to params | user input |
| Nokogiri.rb:27:26:27:32 | content | Nokogiri.rb:3:15:3:20 | call to params : | Nokogiri.rb:27:26:27:32 | content | Unsafe parsing of XML file from $@. | Nokogiri.rb:3:15:3:20 | call to params | user input |
| Nokogiri.rb:28:26:28:32 | content | Nokogiri.rb:3:15:3:20 | call to params : | Nokogiri.rb:28:26:28:32 | content | Unsafe parsing of XML file from $@. | Nokogiri.rb:3:15:3:20 | call to params | user input |