mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge branch 'master' of git.semmle.com:Semmle/ql into ASPNetPagesValidateRequest
# Conflicts: # change-notes/1.24/analysis-csharp.md
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
The <code>requestValidationMode</code> attribute in ASP.NET is used to configure built-in validation to
|
||||
protect applications against code injections. Downgrading or disabling
|
||||
this configuration is not recommended. The default value of 4.5
|
||||
is the only recommended value, as previous versions only test a subset of requests.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
Always set <code>requestValidationMode</code> to 4.5, or leave it at its default value.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>
|
||||
The following example shows the <code>requestValidationMode</code>
|
||||
attribute set to a value of 4.0, which disables some protections and
|
||||
ignores individual <code>Page</code> directives:
|
||||
</p>
|
||||
|
||||
<sample src="ASPNetRequestValidationModeBad.config" />
|
||||
|
||||
<p>
|
||||
Setting the value to 4.5 enables request validation for all requests:
|
||||
</p>
|
||||
|
||||
<sample src="ASPNetRequestValidationModeGood.config" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
Microsoft:
|
||||
<a
|
||||
href="https://docs.microsoft.com/en-us/dotnet/api/system.web.configuration.httpruntimesection.requestvalidationmode?view=netframework-4.8">HttpRuntimeSection.RequestValidationMode Property
|
||||
</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP:
|
||||
<a
|
||||
href="https://www.owasp.org/index.php/ASP.NET_Request_Validation">ASP.NET Request Validation</a>.
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @name Insecure configuration for ASP.NET requestValidationMode
|
||||
* @description Setting 'requestValidationMode' to less than 4.5 disables built-in validations
|
||||
* included by default in ASP.NET. Disabling or downgrading this protection is not
|
||||
* recommended.
|
||||
* @kind problem
|
||||
* @id cs/insecure-request-validation-mode
|
||||
* @problem.severity warning
|
||||
* @tags security
|
||||
* external/cwe/cwe-016
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
||||
from XMLAttribute reqValidationMode
|
||||
where
|
||||
reqValidationMode.getName().toLowerCase() = "requestvalidationmode" and
|
||||
reqValidationMode.getValue().toFloat() < 4.5
|
||||
select reqValidationMode,
|
||||
"Insecure value for requestValidationMode (" + reqValidationMode.getValue() + ")."
|
||||
@@ -0,0 +1,5 @@
|
||||
<configuration>
|
||||
<system.web>
|
||||
<httpRuntime requestValidationMode="4.0"/>
|
||||
</system.web>
|
||||
</configuration>
|
||||
@@ -0,0 +1,5 @@
|
||||
<configuration>
|
||||
<system.web>
|
||||
<httpRuntime requestValidationMode="4.5"/>
|
||||
</system.web>
|
||||
</configuration>
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough0(
|
||||
ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate simpleArgumentFlowsThrough1(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
|
||||
) {
|
||||
nodeCand1(arg, unbind(config)) and
|
||||
not outBarrier(arg, config) and
|
||||
exists(ParameterNode p, ReturnNode ret |
|
||||
simpleParameterFlow(p, ret, t, config) and
|
||||
kind = ret.getKind() and
|
||||
simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
|
||||
viableParamArg(call, p, arg)
|
||||
)
|
||||
}
|
||||
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
nodeCand1(out, unbind(config)) and
|
||||
not inBarrier(out, config) and
|
||||
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
|
||||
simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ private module ImplCommon {
|
||||
*/
|
||||
cached
|
||||
predicate read(Node node1, Content f, Node node2) {
|
||||
readStep(node1, f, node2) and storeStep(_, f, _)
|
||||
readStep(node1, f, node2)
|
||||
or
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
read0(call, kind, node1, f) and
|
||||
|
||||
@@ -113,6 +113,12 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon
|
||||
scope = e2 and
|
||||
isSuccessor = true
|
||||
)
|
||||
or
|
||||
e2 = any(OperatorCall oc |
|
||||
oc.getTarget().(ConversionOperator).fromLibrary() and
|
||||
e1 = oc.getAnArgument() and
|
||||
isSuccessor = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -190,10 +190,16 @@ private module Internal {
|
||||
abstract RuntimeCallable getADynamicTarget();
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasOverrider(OverridableCallable oc, ValueOrRefType t) {
|
||||
exists(oc.getAnOverrider(t))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasCallable(OverridableCallable source, ValueOrRefType t, OverridableCallable c) {
|
||||
c.getSourceDeclaration() = source and
|
||||
t.hasCallable(c) and
|
||||
hasOverrider(c, t) and
|
||||
hasQualifierTypeOverridden0(t, _) and
|
||||
hasQualifierTypeOverridden1(source, _)
|
||||
}
|
||||
@@ -215,15 +221,19 @@ private module Internal {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasQualifierTypeOverridden0(ValueOrRefType t, DispatchMethodOrAccessorCall call) {
|
||||
exists(Type t0 | t0 = getAPossibleType(call.getQualifier(), false) |
|
||||
t = t0
|
||||
hasOverrider(_, t) and
|
||||
(
|
||||
exists(Type t0 | t0 = getAPossibleType(call.getQualifier(), false) |
|
||||
t = t0
|
||||
or
|
||||
Unification::subsumes(t0, t)
|
||||
or
|
||||
t = t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()
|
||||
)
|
||||
or
|
||||
Unification::subsumes(t0, t)
|
||||
or
|
||||
t = t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()
|
||||
constrainedTypeParameterQualifierTypeSubsumes(t,
|
||||
getAConstrainedTypeParameterQualifierType(call))
|
||||
)
|
||||
or
|
||||
constrainedTypeParameterQualifierTypeSubsumes(t, getAConstrainedTypeParameterQualifierType(call))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
private newtype TMemoryAccessKind =
|
||||
TIndirectMemoryAccess() or
|
||||
TIndirectMayMemoryAccess() or
|
||||
TBufferMemoryAccess() or
|
||||
TBufferMayMemoryAccess() or
|
||||
TEscapedMemoryAccess() or
|
||||
TEscapedMayMemoryAccess() or
|
||||
TNonLocalMayMemoryAccess() or
|
||||
TNonLocalMemoryAccess() or
|
||||
TPhiMemoryAccess() or
|
||||
TUnmodeledMemoryAccess() or
|
||||
TChiTotalMemoryAccess() or
|
||||
@@ -35,16 +32,6 @@ class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
|
||||
final override predicate usesAddressOperand() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result may access some, all, or none of the memory at the address specified by the
|
||||
* `AddressOperand` on the same instruction.
|
||||
*/
|
||||
class IndirectMayMemoryAccess extends MemoryAccessKind, TIndirectMayMemoryAccess {
|
||||
override string toString() { result = "indirect(may)" }
|
||||
|
||||
final override predicate usesAddressOperand() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result accesses memory starting at the address specified by the `AddressOperand`
|
||||
* on the same instruction, accessing a number of consecutive elements given by the
|
||||
@@ -56,17 +43,6 @@ class BufferMemoryAccess extends MemoryAccessKind, TBufferMemoryAccess {
|
||||
final override predicate usesAddressOperand() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result may access some, all, or none of the memory starting at the address
|
||||
* specified by the `AddressOperand` on the same instruction, accessing a number of consecutive
|
||||
* elements given by the `BufferSizeOperand`.
|
||||
*/
|
||||
class BufferMayMemoryAccess extends MemoryAccessKind, TBufferMayMemoryAccess {
|
||||
override string toString() { result = "buffer(may)" }
|
||||
|
||||
final override predicate usesAddressOperand() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result accesses all memory whose address has escaped.
|
||||
*/
|
||||
@@ -75,18 +51,11 @@ class EscapedMemoryAccess extends MemoryAccessKind, TEscapedMemoryAccess {
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result may access all memory whose address has escaped.
|
||||
* The operand or result access all memory whose address has escaped, other than data on the stack
|
||||
* frame of the current function.
|
||||
*/
|
||||
class EscapedMayMemoryAccess extends MemoryAccessKind, TEscapedMayMemoryAccess {
|
||||
override string toString() { result = "escaped(may)" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result may access all memory whose address has escaped, other than data on the
|
||||
* stack frame of the current function.
|
||||
*/
|
||||
class NonLocalMayMemoryAccess extends MemoryAccessKind, TNonLocalMayMemoryAccess {
|
||||
override string toString() { result = "nonlocal(may)" }
|
||||
class NonLocalMemoryAccess extends MemoryAccessKind, TNonLocalMemoryAccess {
|
||||
override string toString() { result = "nonlocal" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -359,24 +359,25 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
int getDisplayIndexInBlock() {
|
||||
exists(IRBlock block |
|
||||
block = getBlock() and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
this = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
this = block.getInstruction(result)
|
||||
or
|
||||
this = rank[-result - 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction()
|
||||
|
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
or
|
||||
this instanceof PhiInstruction and
|
||||
this = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction()
|
||||
|
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private int getLineRank() {
|
||||
this = rank[result](Instruction instr |
|
||||
instr.getAST().getFile() = getAST().getFile() and
|
||||
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
@@ -385,8 +386,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* Example: `r1_1`
|
||||
*/
|
||||
string getResultId() {
|
||||
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||
getDisplayIndexInBlock().toString()
|
||||
result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -550,6 +550,16 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
MemoryAccessKind getResultMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the memory access performed by this instruction's result will not always write to
|
||||
* every bit in the memory location. This is most commonly used for memory accesses that may or
|
||||
* may not actually occur depending on runtime state (for example, the write side effect of an
|
||||
* output parameter that is not written to on all paths), or for accesses where the memory
|
||||
* location is a conservative estimate of the memory that might actually be accessed at runtime
|
||||
* (for example, the global side effects of a function call).
|
||||
*/
|
||||
predicate hasResultMayMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Gets the operand that holds the memory address to which this instruction stores its
|
||||
* result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()`
|
||||
@@ -1206,9 +1216,9 @@ class SideEffectInstruction extends Instruction {
|
||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect }
|
||||
|
||||
final override MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
|
||||
|
||||
final override predicate hasResultMayMemoryAccess() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1306,9 +1316,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
|
||||
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
|
||||
}
|
||||
|
||||
final override MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof IndirectMayMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
|
||||
|
||||
final override predicate hasResultMayMemoryAccess() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1318,9 +1328,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
|
||||
class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
|
||||
BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect }
|
||||
|
||||
final override MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMayMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
|
||||
|
||||
final override predicate hasResultMayMemoryAccess() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1332,9 +1342,9 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
|
||||
getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect
|
||||
}
|
||||
|
||||
final override MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMayMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
|
||||
|
||||
final override predicate hasResultMayMemoryAccess() { any() }
|
||||
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
}
|
||||
@@ -1345,9 +1355,9 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
|
||||
class InlineAsmInstruction extends Instruction {
|
||||
InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm }
|
||||
|
||||
final override MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
|
||||
|
||||
final override predicate hasResultMayMemoryAccess() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -194,6 +194,16 @@ class MemoryOperand extends Operand {
|
||||
*/
|
||||
MemoryAccessKind getMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the memory access performed by this operand will not always read from every bit in the
|
||||
* memory location. This is most commonly used for memory accesses that may or may not actually
|
||||
* occur depending on runtime state (for example, the write side effect of an output parameter
|
||||
* that is not written to on all paths), or for accesses where the memory location is a
|
||||
* conservative estimate of the memory that might actually be accessed at runtime (for example,
|
||||
* the global side effects of a function call).
|
||||
*/
|
||||
predicate hasMayMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Returns the operand that holds the memory address from which the current operand loads its
|
||||
* value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2`
|
||||
@@ -397,13 +407,13 @@ class SideEffectOperand extends TypedOperand {
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
useInstr instanceof AliasedUseInstruction and
|
||||
result instanceof NonLocalMayMemoryAccess
|
||||
result instanceof NonLocalMemoryAccess
|
||||
or
|
||||
useInstr instanceof CallSideEffectInstruction and
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
result instanceof EscapedMemoryAccess
|
||||
or
|
||||
useInstr instanceof CallReadSideEffectInstruction and
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
result instanceof EscapedMemoryAccess
|
||||
or
|
||||
useInstr instanceof IndirectReadSideEffectInstruction and
|
||||
result instanceof IndirectMemoryAccess
|
||||
@@ -418,10 +428,22 @@ class SideEffectOperand extends TypedOperand {
|
||||
result instanceof BufferMemoryAccess
|
||||
or
|
||||
useInstr instanceof IndirectMayWriteSideEffectInstruction and
|
||||
result instanceof IndirectMayMemoryAccess
|
||||
result instanceof IndirectMemoryAccess
|
||||
or
|
||||
useInstr instanceof BufferMayWriteSideEffectInstruction and
|
||||
result instanceof BufferMayMemoryAccess
|
||||
result instanceof BufferMemoryAccess
|
||||
}
|
||||
|
||||
final override predicate hasMayMemoryAccess() {
|
||||
useInstr instanceof AliasedUseInstruction
|
||||
or
|
||||
useInstr instanceof CallSideEffectInstruction
|
||||
or
|
||||
useInstr instanceof CallReadSideEffectInstruction
|
||||
or
|
||||
useInstr instanceof IndirectMayWriteSideEffectInstruction
|
||||
or
|
||||
useInstr instanceof BufferMayWriteSideEffectInstruction
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -359,24 +359,25 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
int getDisplayIndexInBlock() {
|
||||
exists(IRBlock block |
|
||||
block = getBlock() and
|
||||
(
|
||||
exists(int index, int phiCount |
|
||||
phiCount = count(block.getAPhiInstruction()) and
|
||||
this = block.getInstruction(index) and
|
||||
result = index + phiCount
|
||||
this = block.getInstruction(result)
|
||||
or
|
||||
this = rank[-result - 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction()
|
||||
|
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
or
|
||||
this instanceof PhiInstruction and
|
||||
this = rank[result + 1](PhiInstruction phiInstr |
|
||||
phiInstr = block.getAPhiInstruction()
|
||||
|
|
||||
phiInstr order by phiInstr.getUniqueId()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private int getLineRank() {
|
||||
this = rank[result](Instruction instr |
|
||||
instr.getAST().getFile() = getAST().getFile() and
|
||||
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
|
||||
|
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human-readable string that uniquely identifies this instruction
|
||||
* within the function. This string is used to refer to this instruction when
|
||||
@@ -385,8 +386,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* Example: `r1_1`
|
||||
*/
|
||||
string getResultId() {
|
||||
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||
getDisplayIndexInBlock().toString()
|
||||
result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -550,6 +550,16 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
MemoryAccessKind getResultMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the memory access performed by this instruction's result will not always write to
|
||||
* every bit in the memory location. This is most commonly used for memory accesses that may or
|
||||
* may not actually occur depending on runtime state (for example, the write side effect of an
|
||||
* output parameter that is not written to on all paths), or for accesses where the memory
|
||||
* location is a conservative estimate of the memory that might actually be accessed at runtime
|
||||
* (for example, the global side effects of a function call).
|
||||
*/
|
||||
predicate hasResultMayMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Gets the operand that holds the memory address to which this instruction stores its
|
||||
* result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()`
|
||||
@@ -1206,9 +1216,9 @@ class SideEffectInstruction extends Instruction {
|
||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect }
|
||||
|
||||
final override MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
|
||||
|
||||
final override predicate hasResultMayMemoryAccess() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1306,9 +1316,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
|
||||
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
|
||||
}
|
||||
|
||||
final override MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof IndirectMayMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
|
||||
|
||||
final override predicate hasResultMayMemoryAccess() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1318,9 +1328,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
|
||||
class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
|
||||
BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect }
|
||||
|
||||
final override MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMayMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
|
||||
|
||||
final override predicate hasResultMayMemoryAccess() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1332,9 +1342,9 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
|
||||
getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect
|
||||
}
|
||||
|
||||
final override MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMayMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
|
||||
|
||||
final override predicate hasResultMayMemoryAccess() { any() }
|
||||
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
}
|
||||
@@ -1345,9 +1355,9 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
|
||||
class InlineAsmInstruction extends Instruction {
|
||||
InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm }
|
||||
|
||||
final override MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
}
|
||||
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
|
||||
|
||||
final override predicate hasResultMayMemoryAccess() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -194,6 +194,16 @@ class MemoryOperand extends Operand {
|
||||
*/
|
||||
MemoryAccessKind getMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the memory access performed by this operand will not always read from every bit in the
|
||||
* memory location. This is most commonly used for memory accesses that may or may not actually
|
||||
* occur depending on runtime state (for example, the write side effect of an output parameter
|
||||
* that is not written to on all paths), or for accesses where the memory location is a
|
||||
* conservative estimate of the memory that might actually be accessed at runtime (for example,
|
||||
* the global side effects of a function call).
|
||||
*/
|
||||
predicate hasMayMemoryAccess() { none() }
|
||||
|
||||
/**
|
||||
* Returns the operand that holds the memory address from which the current operand loads its
|
||||
* value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2`
|
||||
@@ -397,13 +407,13 @@ class SideEffectOperand extends TypedOperand {
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
useInstr instanceof AliasedUseInstruction and
|
||||
result instanceof NonLocalMayMemoryAccess
|
||||
result instanceof NonLocalMemoryAccess
|
||||
or
|
||||
useInstr instanceof CallSideEffectInstruction and
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
result instanceof EscapedMemoryAccess
|
||||
or
|
||||
useInstr instanceof CallReadSideEffectInstruction and
|
||||
result instanceof EscapedMayMemoryAccess
|
||||
result instanceof EscapedMemoryAccess
|
||||
or
|
||||
useInstr instanceof IndirectReadSideEffectInstruction and
|
||||
result instanceof IndirectMemoryAccess
|
||||
@@ -418,10 +428,22 @@ class SideEffectOperand extends TypedOperand {
|
||||
result instanceof BufferMemoryAccess
|
||||
or
|
||||
useInstr instanceof IndirectMayWriteSideEffectInstruction and
|
||||
result instanceof IndirectMayMemoryAccess
|
||||
result instanceof IndirectMemoryAccess
|
||||
or
|
||||
useInstr instanceof BufferMayWriteSideEffectInstruction and
|
||||
result instanceof BufferMayMemoryAccess
|
||||
result instanceof BufferMemoryAccess
|
||||
}
|
||||
|
||||
final override predicate hasMayMemoryAccess() {
|
||||
useInstr instanceof AliasedUseInstruction
|
||||
or
|
||||
useInstr instanceof CallSideEffectInstruction
|
||||
or
|
||||
useInstr instanceof CallReadSideEffectInstruction
|
||||
or
|
||||
useInstr instanceof IndirectMayWriteSideEffectInstruction
|
||||
or
|
||||
useInstr instanceof BufferMayWriteSideEffectInstruction
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ private module Cached {
|
||||
hasUseAtRank(useLocation, useBlock, useRank, oldInstruction) and
|
||||
definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank) and
|
||||
overlap = Alias::getOverlap(defLocation, useLocation) and
|
||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation)
|
||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, _)
|
||||
)
|
||||
else (
|
||||
result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and
|
||||
@@ -149,13 +149,13 @@ private module Cached {
|
||||
) {
|
||||
exists(
|
||||
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
|
||||
OldBlock predBlock, OldBlock defBlock, int defOffset
|
||||
OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation
|
||||
|
|
||||
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset,
|
||||
overlap) and
|
||||
hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and
|
||||
instr = Phi(phiBlock, useLocation) and
|
||||
newPredecessorBlock = getNewBlock(predBlock) and
|
||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation)
|
||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ private module Cached {
|
||||
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
|
||||
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
|
||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar)
|
||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -396,11 +396,7 @@ private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
|
||||
defLocation.getVirtualVariable() = vvar and
|
||||
// If the definition totally (or exactly) overlaps the virtual variable, then there's no need for a `Chi`
|
||||
// instruction.
|
||||
(
|
||||
Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap or
|
||||
def.getResultMemoryAccess() instanceof IndirectMayMemoryAccess or
|
||||
def.getResultMemoryAccess() instanceof BufferMayMemoryAccess
|
||||
)
|
||||
Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap
|
||||
)
|
||||
}
|
||||
|
||||
@@ -560,22 +556,27 @@ module DefUse {
|
||||
bindingset[defOffset, defLocation]
|
||||
pragma[inline]
|
||||
Instruction getDefinitionOrChiInstruction(
|
||||
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation
|
||||
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
|
||||
Alias::MemoryLocation actualDefLocation
|
||||
) {
|
||||
defOffset >= 0 and
|
||||
exists(OldInstruction oldInstr |
|
||||
oldInstr = defBlock.getInstruction(defOffset / 2) and
|
||||
if (defOffset % 2) > 0
|
||||
then
|
||||
then (
|
||||
// An odd offset corresponds to the `Chi` instruction.
|
||||
result = Chi(oldInstr)
|
||||
else
|
||||
result = Chi(oldInstr) and
|
||||
actualDefLocation = defLocation.getVirtualVariable()
|
||||
) else (
|
||||
// An even offset corresponds to the original instruction.
|
||||
result = getNewInstruction(oldInstr)
|
||||
result = getNewInstruction(oldInstr) and
|
||||
actualDefLocation = defLocation
|
||||
)
|
||||
)
|
||||
or
|
||||
defOffset < 0 and
|
||||
result = Phi(defBlock, defLocation)
|
||||
result = Phi(defBlock, defLocation) and
|
||||
actualDefLocation = defLocation
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -713,10 +714,7 @@ module DefUse {
|
||||
defLocation = Alias::getResultMemoryLocation(def) and
|
||||
block.getInstruction(index) = def and
|
||||
overlap = Alias::getOverlap(defLocation, useLocation) and
|
||||
if
|
||||
overlap instanceof MayPartiallyOverlap or
|
||||
def.getResultMemoryAccess() instanceof IndirectMayMemoryAccess or
|
||||
def.getResultMemoryAccess() instanceof BufferMayMemoryAccess
|
||||
if overlap instanceof MayPartiallyOverlap
|
||||
then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
|
||||
else offset = index * 2 // The use will be connected to the definition on the original instruction.
|
||||
)
|
||||
@@ -801,20 +799,19 @@ module DefUse {
|
||||
|
||||
/**
|
||||
* Holds if the `Phi` instruction for location `useLocation` at the beginning of block `phiBlock` has an operand along
|
||||
* the incoming edge from `predBlock`, where that operand's definition is at offset `defOffset` in block `defBlock`,
|
||||
* and overlaps the use operand with overlap relationship `overlap`.
|
||||
* the incoming edge from `predBlock`, where that operand's definition is at offset `defOffset` in block `defBlock`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate hasPhiOperandDefinition(
|
||||
Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock,
|
||||
OldBlock predBlock, OldBlock defBlock, int defOffset, Overlap overlap
|
||||
OldBlock predBlock, OldBlock defBlock, int defOffset
|
||||
) {
|
||||
exists(int defRank |
|
||||
definitionHasPhiNode(useLocation, phiBlock) and
|
||||
predBlock = phiBlock.getAFeasiblePredecessor() and
|
||||
hasDefinitionAtRank(useLocation, defLocation, defBlock, defRank, defOffset) and
|
||||
definitionReachesEndOfBlock(useLocation, defBlock, defRank, predBlock) and
|
||||
overlap = Alias::getOverlap(defLocation, useLocation)
|
||||
exists(Alias::getOverlap(defLocation, useLocation))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import AliasAnalysis
|
||||
private import SimpleSSAImports
|
||||
import SimpleSSAPublicImports
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
@@ -27,20 +28,19 @@ private predicate isVariableModeled(IRVariable var) {
|
||||
// There's no need to check for the right size. An `IRVariable` never has an `UnknownType`, so the test for
|
||||
// `type = var.getType()` is sufficient.
|
||||
forall(Instruction instr, Language::LanguageType type, IntValue bitOffset |
|
||||
hasResultMemoryAccess(instr, var, type, bitOffset)
|
||||
hasResultMemoryAccess(instr, var, type, bitOffset) and
|
||||
not instr.hasResultMayMemoryAccess()
|
||||
|
|
||||
bitOffset = 0 and
|
||||
type.getIRType() = var.getIRType() and
|
||||
not (
|
||||
instr.getResultMemoryAccess() instanceof IndirectMayMemoryAccess or
|
||||
instr.getResultMemoryAccess() instanceof BufferMayMemoryAccess
|
||||
)
|
||||
not instr.hasResultMayMemoryAccess()
|
||||
) and
|
||||
forall(MemoryOperand operand, Language::LanguageType type, IntValue bitOffset |
|
||||
hasOperandMemoryAccess(operand, var, type, bitOffset)
|
||||
|
|
||||
bitOffset = 0 and
|
||||
type.getIRType() = var.getIRType()
|
||||
type.getIRType() = var.getIRType() and
|
||||
not operand.hasMayMemoryAccess()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,4 +2,3 @@ import semmle.code.csharp.ir.implementation.raw.IR
|
||||
import semmle.code.csharp.ir.internal.IntegerConstant as Ints
|
||||
import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
import semmle.code.csharp.ir.internal.Overlap
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.csharp.ir.internal.Overlap
|
||||
@@ -586,6 +586,9 @@
|
||||
| LocalDataFlow.cs:480:67:480:68 | os | LocalDataFlow.cs:486:32:486:33 | access to parameter os |
|
||||
| LocalDataFlow.cs:483:21:483:21 | access to parameter x | LocalDataFlow.cs:483:16:483:21 | ... = ... |
|
||||
| LocalDataFlow.cs:486:32:486:33 | access to parameter os | LocalDataFlow.cs:486:26:486:33 | ... = ... |
|
||||
| LocalDataFlow.cs:491:41:491:44 | args | LocalDataFlow.cs:493:29:493:32 | access to parameter args |
|
||||
| LocalDataFlow.cs:493:29:493:32 | [post] access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args |
|
||||
| LocalDataFlow.cs:493:29:493:32 | access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args |
|
||||
| SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S |
|
||||
| SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access |
|
||||
| SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted |
|
||||
|
||||
@@ -485,4 +485,12 @@ public class LocalDataFlow
|
||||
IEnumerable<object> os2;
|
||||
foreach(var o in os2 = os) { }
|
||||
}
|
||||
|
||||
public static implicit operator LocalDataFlow(string[] args) => null;
|
||||
|
||||
public void ConversionFlow(string[] args)
|
||||
{
|
||||
Span<object> span = args; // flow (library operator)
|
||||
LocalDataFlow x = args; // no flow (source code operator)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -736,6 +736,11 @@
|
||||
| LocalDataFlow.cs:480:67:480:68 | os | LocalDataFlow.cs:486:32:486:33 | access to parameter os |
|
||||
| LocalDataFlow.cs:483:21:483:21 | access to parameter x | LocalDataFlow.cs:483:16:483:21 | ... = ... |
|
||||
| LocalDataFlow.cs:486:32:486:33 | access to parameter os | LocalDataFlow.cs:486:26:486:33 | ... = ... |
|
||||
| LocalDataFlow.cs:491:41:491:44 | args | LocalDataFlow.cs:491:41:491:44 | args |
|
||||
| LocalDataFlow.cs:491:41:491:44 | args | LocalDataFlow.cs:493:29:493:32 | access to parameter args |
|
||||
| LocalDataFlow.cs:493:29:493:32 | [post] access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args |
|
||||
| LocalDataFlow.cs:493:29:493:32 | access to parameter args | LocalDataFlow.cs:493:29:493:32 | call to operator implicit conversion |
|
||||
| LocalDataFlow.cs:493:29:493:32 | access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args |
|
||||
| SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S |
|
||||
| SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access |
|
||||
| SSA.cs:5:26:5:32 | tainted | SSA.cs:5:26:5:32 | tainted |
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace EFCoreTests
|
||||
Sink(taintSource); // Tainted
|
||||
Sink(new RawSqlString(taintSource)); // Tainted
|
||||
Sink((RawSqlString)taintSource); // Tainted
|
||||
Sink((RawSqlString)(FormattableString)$"{taintSource}"); // Not tainted
|
||||
Sink((RawSqlString)(FormattableString)$"{taintSource}"); // Tainted, but not reported because conversion operator is in a stub .cs file
|
||||
|
||||
// Tainted via database, even though technically there were no reads or writes to the database in this particular case.
|
||||
var p1 = new Person { Name = taintSource };
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
| ASPNetRequestValidationModeBad.config:3:5:3:47 | requestValidationMode=4.0 | Insecure value for requestValidationMode (4.0). |
|
||||
@@ -0,0 +1 @@
|
||||
Security Features/CWE-016/ASPNetRequestValidationMode.ql
|
||||
@@ -0,0 +1,5 @@
|
||||
<configuration>
|
||||
<system.web>
|
||||
<httpRuntime requestValidationMode="4.0"/>
|
||||
</system.web>
|
||||
</configuration>
|
||||
@@ -0,0 +1,5 @@
|
||||
<configuration>
|
||||
<system.web>
|
||||
<httpRuntime requestValidationMode="4.5"/>
|
||||
</system.web>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user