Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions csharp/ql/lib/semmle/code/csharp/frameworks/system/Xml.qll
Original file line number Diff line number Diff line change
Expand Up @@ -141,23 +141,43 @@ class XmlReaderSettingsCreation extends ObjectCreation {

/** Gets a value set on the `ValidationType` property, if any. */
SystemXmlValidationType getValidationType() {
result.getAnAccess() =
result.getAnAccess() = this.getAValidationTypeValue()
}

/** Gets an expression assigned to the `ValidationType` property in this local context. */
Expr getAValidationTypeValue() {
result =
this.getPropertyValue(any(SystemXmlXmlReaderSettingsClass s).getValidationTypeProperty())
}

/** Gets a flag set on the `ValidationFlags` property, if any. */
SystemXmlSchemaXmlSchemaValidationFlags getAValidationFlag() {
result.getAnAccess() =
result.getAnAccess() = this.getAValidationFlagValue()
}

/** Gets an expression assigned to the `ValidationFlags` property in this local context. */
Expr getAValidationFlagValue() {
result =
this.getPropertyValue(any(SystemXmlXmlReaderSettingsClass s).getValidationFlagsProperty())
}

/** Gets a value set for the given property in this local context. */
private Expr getPropertyValue(Property p) {
p = settings.getAProperty() and
exists(PropertyCall set, Expr arg |
set.getTarget() = p.getSetter() and
DataFlow::localExprFlow(this, set.getQualifier()) and
arg = set.getAnArgument() and
exists(Expr arg |
(
exists(PropertyCall set |
set.getTarget() = p.getSetter() and
DataFlow::localExprFlow(this, set.getQualifier()) and
arg = set.getAnArgument()
)
or
exists(MemberInitializer initializer |
initializer = this.getInitializer().(ObjectInitializer).getAMemberInitializer() and
initializer.getInitializedMember() = p and
arg = initializer.getRightOperand()
)
) and
result = getBitwiseOrOperand*(arg)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import csharp
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
private import semmle.code.csharp.frameworks.system.Xml
private import semmle.code.csharp.frameworks.system.IO
private import semmle.code.csharp.security.Sanitizers

/**
Expand Down Expand Up @@ -61,6 +62,51 @@ deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource
*/
class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }

private predicate hasUnknownSettingsUse(XmlReaderSettingsCreation creation) {
exists(Expr use, Call call |
DataFlow::localExprFlow(creation, use) and
(
use = call.getAnArgument() and
not use = call.(XmlReaderCreateCall).getArgumentForName("settings")
or
use = call.(MethodCall).getQualifier()
)
)
or
exists(LocalVariable variable, VariableAccess use |
DataFlow::localExprFlow(creation, variable.getAnAccess()) and
use = variable.getAnAccess() and
use.getEnclosingCallable() != creation.getEnclosingCallable()
)
or
exists(AssignExpr assignment |
DataFlow::localExprFlow(creation, assignment.getRightOperand()) and
not assignment.getLeftOperand().(VariableAccess).getTarget() instanceof LocalVariable
)
}

private predicate specifiesSchemaValidation(
XmlReaderSettingsCreation creation, XmlReaderCreateCall createCall
) {
creation.getValidationType().hasName("Schema") and
not exists(Expr value |
value = creation.getAValidationTypeValue() and
not value = any(SystemXmlValidationType schema | schema.hasName("Schema")).getAnAccess()
) and
(
not exists(creation.getInitializer())
or
creation.getEnclosingCallable() = createCall.getEnclosingCallable() and
DataFlow::localExprFlow(creation, createCall.getSettings()) and
not hasUnknownSettingsUse(creation) and
not exists(Expr value |
value = creation.getAValidationFlagValue() and
not value instanceof BitwiseOrOperation and
not value = any(SystemXmlSchemaXmlSchemaValidationFlags flag).getAnAccess()
)
)
}

/**
* The input argument to a call to `XmlReader.Create` where the input will not be validated against
* a schema.
Expand All @@ -85,11 +131,11 @@ class XmlReaderCreateCallSink extends Sink {
// internally); or
// - The ProcessSchemaLocation option is set (this allows the document to reference a
// schema by location that this document will validate against).
result = "the 'XmlReaderSettings' instance does not specify the 'ValidationType' as 'Schema'." and
result = "the 'XmlReaderSettings' instance is not known to enforce schema validation." and
exists(XmlReaderSettingsCreation settingsCreation |
settingsCreation = createCall.getSettings().getASettingsCreation()
|
not settingsCreation.getValidationType().hasName("Schema")
not specifiesSchemaValidation(settingsCreation, createCall)
)
or
exists(string badValidationFlag |
Expand All @@ -109,3 +155,13 @@ class XmlReaderCreateCallSink extends Sink {
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }

private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }

private class NullStreamSanitizer extends Sanitizer {
NullStreamSanitizer() {
exists(FieldAccess access |
this.getExpr() = access and
access.getTarget().getDeclaringType() instanceof SystemIOStreamClass and
access.getTarget().hasName("Null")
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;
using System.Web;
using System.Xml;
using System.Xml.Schema;
Expand Down Expand Up @@ -52,4 +53,125 @@ public bool IsReusable
return true;
}
}

public void ProcessInitializedSettings(HttpContext ctx)
{
string xml = ctx.Request.QueryString["xml"]; // $ Source
var schemaSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema
};
schemaSettings.Schemas.Add("urn:my-schema", "my.xsd");
XmlReader.Create(new StringReader(xml), schemaSettings);

var inlineSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema,
ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema
};
XmlReader.Create(new StringReader(xml), inlineSettings); // $ Alert

var locationSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema,
ValidationFlags = XmlSchemaValidationFlags.ProcessSchemaLocation
};
XmlReader.Create(new StringReader(xml), locationSettings); // $ Alert

var resetSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema
};
resetSettings.ValidationType = ValidationType.None;
XmlReader.Create(new StringReader(xml), resetSettings); // $ Alert

var unknownSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema
};
unknownSettings.ValidationType = (ValidationType)int.Parse(ctx.Request.QueryString["type"]);
XmlReader.Create(new StringReader(xml), unknownSettings); // $ Alert

var escapedSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema
};
DisableValidation(escapedSettings);
XmlReader.Create(new StringReader(xml), escapedSettings); // $ Alert

var unknownFlagsSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema
};
unknownFlagsSettings.ValidationFlags =
(XmlSchemaValidationFlags)int.Parse(ctx.Request.QueryString["flags"]);
XmlReader.Create(new StringReader(xml), unknownFlagsSettings); // $ Alert

var aliasSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema
};
var alias = aliasSettings;
alias.ValidationType = ValidationType.None;
XmlReader.Create(new StringReader(xml), aliasSettings); // $ Alert

var capturedSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema
};
Action reset = () => capturedSettings.ValidationType = ValidationType.None;
reset();
XmlReader.Create(new StringReader(xml), capturedSettings); // $ Alert

var storedSettings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema
};
SharedSettings = storedSettings;
DisableValidation(SharedSettings);
XmlReader.Create(new StringReader(xml), storedSettings); // $ Alert

var returnedSettings = CreateSettings();
DisableValidation(returnedSettings);
XmlReader.Create(new StringReader(xml), returnedSettings); // $ Alert

XmlReader.Create(new StringReader(xml), new XmlReaderSettings
{
ValidationType = ValidationType.Schema,
ValidationFlags = XmlSchemaValidationFlags.ProcessIdentityConstraints |
XmlSchemaValidationFlags.AllowXmlAttributes
});
}

private static XmlReaderSettings SharedSettings;

private static XmlReaderSettings CreateSettings()
{
return new XmlReaderSettings { ValidationType = ValidationType.Schema };
}

private static void DisableValidation(XmlReaderSettings settings)
{
settings.ValidationType = ValidationType.None;
}

public void ProcessStreams(HttpContext ctx)
{
var input = new MemoryStream(Encoding.UTF8.GetBytes(ctx.Request.QueryString["xml"])); // $ Source
input.CopyTo(Stream.Null);
XmlReader.Create(Stream.Null);

var stream = new MemoryStream();
input.CopyTo(stream);
stream.Position = 0;
XmlReader.Create(stream); // $ Alert

Streams.Null = new MemoryStream(Encoding.UTF8.GetBytes(ctx.Request.QueryString["otherXml"])); // $ Source
XmlReader.Create(Streams.Null); // $ Alert
}

private static class Streams
{
public static Stream Null;
}
}
Loading
Loading