Compare commits

..

4 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
e38791976e Remove added tests and revert test changes 2026-07-02 08:30:59 +00:00
copilot-swe-agent[bot]
068859d338 Apply remaining changes 2026-07-02 08:26:17 +00:00
copilot-swe-agent[bot]
e34375c0cc Add subst resolution for Kotlin and Go extractors 2026-07-02 08:22:53 +00:00
copilot-swe-agent[bot]
5079680558 Initial plan 2026-07-02 08:17:28 +00:00
64 changed files with 7885 additions and 8082 deletions

View File

@@ -6,7 +6,6 @@ private import cpp as Cpp
private import codeql.dataflow.internal.FlowSummaryImpl
private import codeql.dataflow.internal.AccessPathSyntax as AccessPath
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific as DataFlowImplSpecific
private import semmle.code.cpp.dataflow.ExternalFlow
@@ -21,22 +20,8 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
class SinkBase = Void;
class FlowSummaryCallBase = CallInstruction;
predicate callableFromSource(SummarizedCallableBase c) { exists(c.getBlock()) }
FlowSummaryCallBase getASourceCall(SummarizedCallableBase sc) {
result.getStaticCallTarget() = sc
}
DataFlowCallable getSummarizedCallableAsDataFlowCallable(SummarizedCallableBase c) {
result.asSummarizedCallable() = c
}
DataFlowCallable getSourceCallEnclosingCallable(FlowSummaryCallBase call) {
result.asSourceCallable() = call.getEnclosingFunction()
}
ArgumentPosition callbackSelfParameterPosition() { result = TDirectPosition(-1) }
ReturnKind getStandardReturnValueKind() { result = getReturnValueKind("") }
@@ -45,10 +30,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
arg = repeatStars(result.(NormalReturnKind).getIndirectionIndex())
}
ParameterPosition getFlowSummaryParameterPosition(ReturnKind rk) {
result = TFlowSummaryPosition(rk)
}
string encodeParameterPosition(ParameterPosition pos) { result = pos.toString() }
string encodeArgumentPosition(ArgumentPosition pos) { result = pos.toString() }
@@ -133,22 +114,10 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
private import Make<Location, DataFlowImplSpecific::CppDataFlow, Input> as Impl
private module StepsInput implements Impl::Private::StepsInputSig {
Impl::Private::SummaryNode getSummaryNode(Node n) {
result = n.(FlowSummaryNode).getSummaryNode()
}
DataFlowCall getACall(Public::SummarizedCallable sc) {
result.getStaticCallTarget().getUnderlyingCallable() = sc
}
Node getSourceOutNode(Input::FlowSummaryCallBase call, ReturnKind rk) {
exists(IndirectReturnOutNode out | result = out |
out.getCallInstruction() = call and
pragma[only_bind_out](rk.(NormalReturnKind).getIndirectionIndex()) =
pragma[only_bind_out](out.getIndirectionIndex())
)
}
DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() }
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() }

View File

@@ -1534,8 +1534,12 @@ class FlowSummaryNode extends Node, TFlowSummaryNode {
result = this.getSummaryNode().getSummarizedCallable()
}
/**
* Gets the enclosing callable. For a `FlowSummaryNode` this is always the
* summarized function this node is part of.
*/
override DataFlowCallable getEnclosingCallable() {
result = FlowSummaryImpl::Private::getEnclosingCallable(this.getSummaryNode())
result.asSummarizedCallable() = this.getSummarizedCallable()
}
override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() }

View File

@@ -561,21 +561,6 @@ class SummaryArgumentNode extends ArgumentNode, FlowSummaryNode {
}
}
/** An argument node that re-enters return output as input to a flow summary. */
private class FlowSummaryArgumentNode extends ArgumentNode, FlowSummaryNode {
private CallInstruction callInstruction;
private ReturnKind rk;
FlowSummaryArgumentNode() {
this.getSummaryNode() = FlowSummaryImpl::Private::summaryArgumentNode(callInstruction, rk)
}
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
call.asCallInstruction() = callInstruction and
pos = TFlowSummaryPosition(rk)
}
}
/** A parameter position represented by an integer. */
class ParameterPosition = Position;
@@ -631,18 +616,6 @@ class IndirectionPosition extends Position, TIndirectionPosition {
final override int getIndirectionIndex() { result = indirectionIndex }
}
class FlowSummaryPosition extends Position, TFlowSummaryPosition {
ReturnKind rk;
FlowSummaryPosition() { this = TFlowSummaryPosition(rk) }
override string toString() { result = "write to: " + rk.toString() }
override int getArgumentIndex() { none() }
final override int getIndirectionIndex() { result = rk.getIndirectionIndex() }
}
newtype TPosition =
TDirectPosition(int argumentIndex) {
exists(any(CallInstruction c).getArgument(argumentIndex))
@@ -661,8 +634,7 @@ newtype TPosition =
p = f.getParameter(argumentIndex) and
indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1]
)
} or
TFlowSummaryPosition(ReturnKind rk) { FlowSummaryImpl::Private::relevantFlowSummaryPosition(rk) }
}
private newtype TReturnKind =
TNormalReturnKind(int indirectionIndex) {

View File

@@ -158,7 +158,7 @@ private module Cached {
model = ""
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
}

View File

@@ -67,7 +67,7 @@ private module Cached {
model = ""
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
or
// object->field conflation for content that is a `TaintInheritingContent`.

View File

@@ -53,17 +53,14 @@ models
| 52 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
| 53 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
| 54 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
| 55 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual |
| 56 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual |
| 57 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual |
| 58 | Summary: ; TemplateClass1; true; templateFunction2<U,V>; (U,V); ; Argument[1]; ReturnValue; value; manual |
| 59 | Summary: ; TemplateClass1<T>; false; templateFunction<U>; (T,U); ; Argument[0]; ReturnValue; value; manual |
| 60 | Summary: ; TemplateClass2<T,U>; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual |
| 61 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual |
| 62 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual |
| 63 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual |
| 64 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual |
| 65 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
| 55 | Summary: ; TemplateClass1; true; templateFunction2<U,V>; (U,V); ; Argument[1]; ReturnValue; value; manual |
| 56 | Summary: ; TemplateClass1<T>; false; templateFunction<U>; (T,U); ; Argument[0]; ReturnValue; value; manual |
| 57 | Summary: ; TemplateClass2<T,U>; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual |
| 58 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual |
| 59 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual |
| 60 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual |
| 61 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual |
| 62 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
edges
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:32 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:32 Sink:MaD:2 |
@@ -72,16 +69,16 @@ edges
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:65 |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:62 |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:29 |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | |
| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:61 |
| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:58 |
| azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | |
| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:62 |
| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:59 |
| azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | |
| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:63 |
| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:60 |
| azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | |
| azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | |
| azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | |
@@ -97,10 +94,10 @@ edges
| azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | |
| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:26 |
| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | |
| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:63 |
| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:60 |
| azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | |
| azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | |
| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:64 |
| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:61 |
| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | |
| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:30 |
| azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | |
@@ -162,27 +159,27 @@ edges
| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | |
| test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | |
| test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:1 |
| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:59 |
| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:56 |
| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:25 |
| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | |
| test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | |
| test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:1 |
| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:60 |
| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:57 |
| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:25 |
| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | |
| test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | |
| test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:1 |
| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:60 |
| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:57 |
| test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | |
| test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | |
| test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | |
| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:58 |
| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:55 |
| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:25 |
| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | |
| test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | |
| test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:1 |
| test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | |
| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:58 |
| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:55 |
| test.cpp:186:2:186:2 | *s [post update] [myField] | test.cpp:187:33:187:34 | *& ... [myField] | provenance | |
| test.cpp:186:2:186:24 | ... = ... | test.cpp:186:2:186:2 | *s [post update] [myField] | provenance | |
| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:25 |
@@ -195,18 +192,6 @@ edges
| test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | |
| test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:201:10:201:10 | x | provenance | Sink:MaD:1 |
| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:51 |
| test.cpp:216:3:216:4 | get_ptr output argument [value] | test.cpp:217:11:217:12 | *rf [value] | provenance | |
| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:57 |
| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:25 |
| test.cpp:217:11:217:12 | *rf [value] | test.cpp:217:14:217:18 | value | provenance | |
| test.cpp:217:14:217:18 | value | test.cpp:217:14:217:18 | value | provenance | |
| test.cpp:217:14:217:18 | value | test.cpp:218:11:218:11 | x | provenance | Sink:MaD:1 |
| test.cpp:222:3:222:3 | operator[] output argument | test.cpp:223:12:223:12 | *s | provenance | |
| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:56 |
| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:25 |
| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:55 |
| test.cpp:223:13:223:15 | call to operator[] | test.cpp:223:13:223:15 | call to operator[] | provenance | |
| test.cpp:223:13:223:15 | call to operator[] | test.cpp:224:11:224:11 | c | provenance | Sink:MaD:1 |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:24:8:24:11 | * ... | provenance | |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | |
@@ -485,20 +470,6 @@ nodes
| test.cpp:200:10:200:33 | call to read_field_from_struct_2 | semmle.label | call to read_field_from_struct_2 |
| test.cpp:200:35:200:36 | *& ... [myField] | semmle.label | *& ... [myField] |
| test.cpp:201:10:201:10 | x | semmle.label | x |
| test.cpp:216:3:216:4 | get_ptr output argument [value] | semmle.label | get_ptr output argument [value] |
| test.cpp:216:3:216:28 | ... = ... | semmle.label | ... = ... |
| test.cpp:216:18:216:26 | call to ymlSource | semmle.label | call to ymlSource |
| test.cpp:217:11:217:12 | *rf [value] | semmle.label | *rf [value] |
| test.cpp:217:14:217:18 | value | semmle.label | value |
| test.cpp:217:14:217:18 | value | semmle.label | value |
| test.cpp:218:11:218:11 | x | semmle.label | x |
| test.cpp:222:3:222:3 | operator[] output argument | semmle.label | operator[] output argument |
| test.cpp:222:3:222:20 | ... = ... | semmle.label | ... = ... |
| test.cpp:222:10:222:20 | call to ymlSource | semmle.label | call to ymlSource |
| test.cpp:223:12:223:12 | *s | semmle.label | *s |
| test.cpp:223:13:223:15 | call to operator[] | semmle.label | call to operator[] |
| test.cpp:223:13:223:15 | call to operator[] | semmle.label | call to operator[] |
| test.cpp:224:11:224:11 | c | semmle.label | c |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | semmle.label | *call to GetCommandLineA |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | semmle.label | *call to GetCommandLineA |
| windows.cpp:24:8:24:11 | * ... | semmle.label | * ... |

View File

@@ -23,7 +23,4 @@ extensions:
- ["", "TemplateClass1", True, "templateFunction2<U,V>", "(U,V)", "", "Argument[1]", "ReturnValue", "value", "manual"]
- ["", "TemplateClass2<T,U>", True, "function", "(U,T)", "", "Argument[1]", "ReturnValue", "value", "manual"]
- ["", "", False, "read_field_from_struct", "", "", "Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]", "ReturnValue", "value", "manual"]
- ["", "", False, "read_field_from_struct_2", "", "", "Argument[*0].Field[MyGlobalStruct::myField]", "ReturnValue", "value", "manual"]
- ["", "ReverseFlow", True, "get_ptr", "", "", "ReturnValue[*]", "Argument[-1].Field[ReverseFlow::value]", "value", "manual"]
- ["", "MyString", True, "operator[]", "", "", "ReturnValue[*]", "Argument[-1]", "taint", "manual"]
- ["", "MyString", True, "operator[]", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
- ["", "", False, "read_field_from_struct_2", "", "", "Argument[*0].Field[MyGlobalStruct::myField]", "ReturnValue", "value", "manual"]

View File

@@ -21,5 +21,3 @@
| test.cpp:173:10:173:10 | y | test-sink |
| test.cpp:188:10:188:10 | x | test-sink |
| test.cpp:201:10:201:10 | x | test-sink |
| test.cpp:218:11:218:11 | x | test-sink |
| test.cpp:224:11:224:11 | c | test-sink |

View File

@@ -15,8 +15,6 @@
| test.cpp:170:10:170:18 | call to ymlSource | local |
| test.cpp:186:14:186:22 | call to ymlSource | local |
| test.cpp:199:14:199:22 | call to ymlSource | local |
| test.cpp:216:18:216:26 | call to ymlSource | local |
| test.cpp:222:10:222:20 | call to ymlSource | local |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | local |
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | local |
| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | local |

View File

@@ -199,28 +199,4 @@ void test_fully_qualified_field_test_2() {
s.myField = ymlSource();
int x = read_field_from_struct_2(&s);
ymlSink(x); // $ ir
}
struct ReverseFlow {
int value;
int& get_ptr();
};
struct MyString {
char& operator[](unsigned);
};
void test_reverse_flow(unsigned i, unsigned j) {
{
ReverseFlow rf;
rf.get_ptr() = ymlSource();
int x = rf.value;
ymlSink(x); // $ ir
}
{
MyString s;
s[i] = ymlSource();
char c = s[j];
ymlSink(c); // $ ir
}
}

View File

@@ -714,7 +714,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
) and
model = ""
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
}

View File

@@ -34,8 +34,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CsharpDataFlow>
class SinkBase = Void;
class FlowSummaryCallBase = Void;
predicate neutralElement(SummarizedCallableBase c, string kind, string provenance, boolean isExact) {
interpretNeutral(c, kind, provenance, isExact)
}
@@ -203,10 +201,6 @@ private module TypesInput implements Impl::Private::TypesInputSig {
}
private module StepsInput implements Impl::Private::StepsInputSig {
Impl::Private::SummaryNode getSummaryNode(Node n) {
result = n.(FlowSummaryNode).getSummaryNode()
}
DataFlowCall getACall(Public::SummarizedCallable sc) {
sc = viableCallable(result).asSummarizedCallable()
}

View File

@@ -171,7 +171,7 @@ private module Cached {
) and
model = ""
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
}
}

View File

@@ -186,6 +186,13 @@ private Expr aspWrittenValue(AspInlineMember m) {
m.getMember().(Callable).canReturn(result)
}
private string makeUrl(Location l) {
exists(string path, int sl, int sc, int el, int ec |
l.hasLocationInfo(path, sl, sc, el, ec) and
result = "file://" + path + ":" + sl + ":" + sc + ":" + el + ":" + ec
)
}
/**
* A sink for writes to properties that are accessed in ASP pages.
*
@@ -201,7 +208,10 @@ private class AspxCodeSink extends Sink {
AspxCodeSink() { this.getExpr() = aspWrittenValue(inline) }
override string explanation() { result = "member is accessed inline in an ASPX page" }
override string explanation() {
result =
"member is [[\"accessed inline\"|\"" + makeUrl(inline.getLocation()) + "\"]] in an ASPX page"
}
}
/** A sink for the output stream associated with a `HttpListenerResponse`. */

View File

@@ -69,26 +69,6 @@ The CodeQL library for Java and Kotlin analysis exposes the following extensible
The extensible predicates are populated using the models defined in data extension files.
Specifying types in Java and Kotlin models
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Nested and inner classes** are denoted by joining the enclosing type and the nested type with a dollar sign (``$``), for example ``Outer$Inner``. This applies both to the type column and to nested types in a signature. For example, the ``Level`` enum nested inside the ``Logger`` interface, nested inside the ``System`` class, is written as ``System$Logger$Level``:
.. code-block:: yaml
- ["java.lang", "System$Logger", True, "log", "(System$Logger$Level,String)", "", "Argument[1]", "log-injection", "manual"]
**Generics** are erased, so type parameters are removed:
- In the type column, leave out any type parameters, so ``List<E>`` becomes ``List``.
- In the signature, replace each type parameter with its upper bound, or ``Object`` if it has none. So ``T`` from ``<T>`` becomes ``Object``, and ``T`` from ``<T extends Number>`` becomes ``Number``.
For example, ``forEach`` on ``Iterable<T>`` takes a ``Consumer<? super T>`` argument, so the type is ``Iterable`` and the signature is ``(Consumer)``:
.. code-block:: yaml
- ["java.lang", "Iterable", True, "forEach", "(Consumer)", "", "Argument[this].Element", "Argument[0].Parameter[0]", "value", "manual"]
Examples of custom model definitions
------------------------------------

View File

@@ -18,7 +18,7 @@
.NET 5, .NET 6, .NET 7, .NET 8, .NET 9, .NET 10","``.sln``, ``.slnx``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``"
GitHub Actions,"Not applicable",Not applicable,"``.github/workflows/*.yml``, ``.github/workflows/*.yaml``, ``**/action.yml``, ``**/action.yaml``"
Go (aka Golang), "Go up to 1.26", "Go 1.11 or more recent", ``.go``
Java,"Java 7 to 27 [6]_","javac (OpenJDK and Oracle JDK),
Java,"Java 7 to 26 [6]_","javac (OpenJDK and Oracle JDK),
Eclipse compiler for Java (ECJ) [7]_",``.java``
Kotlin,"Kotlin 1.8.0 to 2.4.0\ *x*","kotlinc",``.kt``
@@ -36,7 +36,7 @@
.. [3] Objective-C, Objective-C++, C++/CLI, and C++/CX are not supported.
.. [4] Support for the clang-cl compiler is preliminary.
.. [5] Support for the Arm Compiler (armcc) is preliminary.
.. [6] Builds that execute on Java 7 to 27 can be analyzed. The analysis understands standard language features in Java 8 to 27; "preview" and "incubator" features are not supported. Source code using Java language versions older than Java 8 are analyzed as Java 8 code.
.. [6] Builds that execute on Java 7 to 26 can be analyzed. The analysis understands standard language features in Java 8 to 26; "preview" and "incubator" features are not supported. Source code using Java language versions older than Java 8 are analyzed as Java 8 code.
.. [7] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin.
.. [8] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files.
.. [9] The extractor requires Python 3 to run. To analyze Python 2.7 you should install both versions of Python.

View File

@@ -19,6 +19,7 @@ go_library(
"//go/extractor/dbscheme",
"//go/extractor/diagnostics",
"//go/extractor/srcarchive",
"//go/extractor/subst",
"//go/extractor/toolchain",
"//go/extractor/trap",
"//go/extractor/util",

View File

@@ -25,6 +25,7 @@ import (
"github.com/github/codeql-go/extractor/dbscheme"
"github.com/github/codeql-go/extractor/diagnostics"
"github.com/github/codeql-go/extractor/srcarchive"
"github.com/github/codeql-go/extractor/subst"
"github.com/github/codeql-go/extractor/toolchain"
"github.com/github/codeql-go/extractor/trap"
"github.com/github/codeql-go/extractor/util"
@@ -764,9 +765,9 @@ func normalizedPath(ast *ast.File, fset *token.FileSet) string {
file := fset.File(ast.Package).Name()
path, err := filepath.EvalSymlinks(file)
if err != nil {
return file
path = file
}
return path
return subst.ResolvePath(path)
}
// extractFile extracts AST information for the given file

12
go/extractor/subst/BUILD.bazel generated Normal file
View File

@@ -0,0 +1,12 @@
load("@rules_go//go:def.bzl", "go_library")
go_library(
name = "subst",
srcs = [
"subst.go",
"subst_other.go",
"subst_windows.go",
],
importpath = "github.com/github/codeql-go/extractor/subst",
visibility = ["//go:__subpackages__"],
)

View File

@@ -0,0 +1,30 @@
package subst
// ResolvePath resolves subst'd drive letters in a full path.
// If the path starts with a subst'd drive letter, replaces it with the backing path.
// Otherwise returns the path unchanged.
func ResolvePath(path string) string {
return resolvePath(path, ResolveDrive)
}
func resolvePath(path string, resolveDrive func(string) string) string {
if len(path) < 3 {
return path
}
if path[1] != ':' {
return path
}
if path[2] != '\\' && path[2] != '/' {
return path
}
c := path[0]
if !((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
return path
}
resolved := resolveDrive(path[:3])
if resolved == "" {
return path
}
return resolved + path[2:]
}

View File

@@ -0,0 +1,6 @@
//go:build !windows
package subst
// ResolveDrive is a no-op on non-Windows platforms.
func ResolveDrive(driveRoot string) string { return "" }

View File

@@ -0,0 +1,67 @@
//go:build windows
package subst
import (
"os"
"path/filepath"
"syscall"
"unsafe"
)
var (
dll *syscall.DLL
procResolve *syscall.Proc
procFree *syscall.Proc
available bool
)
func init() {
dist := os.Getenv("CODEQL_DIST")
if dist == "" {
return
}
dllPath := filepath.Join(dist, "tools", "win64", "canonicalize.dll")
d, err := syscall.LoadDLL(dllPath)
if err != nil {
return
}
p, err := d.FindProc("resolve_subst_u8")
if err != nil {
return
}
f, _ := d.FindProc("resolve_subst_free_u8")
dll = d
procResolve = p
procFree = f
available = true
}
// ResolveDrive resolves a subst'd drive root (e.g. "X:\") to its backing path.
// Returns "" if the drive is not subst'd or on error.
func ResolveDrive(driveRoot string) string {
if !available {
return ""
}
driveBytes := append([]byte(driveRoot), 0)
ret, _, _ := procResolve.Call(uintptr(unsafe.Pointer(&driveBytes[0])))
if ret == 0 {
return ""
}
result := goString((*byte)(unsafe.Pointer(ret)))
if procFree != nil {
procFree.Call(ret)
}
return result
}
func goString(p *byte) string {
if p == nil {
return ""
}
var n int
for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ {
ptr = unsafe.Add(ptr, 1)
}
return string(unsafe.Slice(p, n))
}

View File

@@ -141,7 +141,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
any(FunctionModel m).flowStep(nodeFrom, nodeTo) and
model = "FunctionModel"
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
}

View File

@@ -31,8 +31,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::GoDataFlow> {
class SinkBase = Void;
class FlowSummaryCallBase = Void;
predicate callableFromSource(SummarizedCallableBase c) { exists(c.getFuncDef()) }
predicate neutralElement(
@@ -115,10 +113,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::GoDataFlow> {
private import Make<Location, DataFlowImplSpecific::GoDataFlow, Input> as Impl
private module StepsInput implements Impl::Private::StepsInputSig {
Impl::Private::SummaryNode getSummaryNode(Node n) {
result = n.(FlowSummaryNode).getSummaryNode()
}
DataFlowCall getACall(Public::SummarizedCallable sc) {
exists(DataFlow::CallNode call |
call.asExpr() = result and

View File

@@ -109,8 +109,8 @@ private predicate localAdditionalForwardTaintStep(
or
any(AdditionalTaintStep a).step(pred, succ) and model = "AdditionalTaintStep"
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(pred,
succ.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false, model)
FlowSummaryImpl::Private::Steps::summaryLocalStep(pred.(DataFlowPrivate::FlowSummaryNode)
.getSummaryNode(), succ.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false, model)
}
/**

View File

@@ -188,8 +188,6 @@ org.apache.hadoop.hive.ql.metadata,1,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,
org.apache.hc.client5.http.async.methods,84,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,84,,,,,,,,,,,,,,,,,,
org.apache.hc.client5.http.classic.methods,37,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,37,,,,,,,,,,,,,,,,,,
org.apache.hc.client5.http.fluent,19,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,19,,,,,,,,,,,,,,,,,,
org.apache.hc.client5.http.protocol,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
org.apache.hc.client5.http.utils,,,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,
org.apache.hc.core5.benchmark,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,
org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,
org.apache.hc.core5.http,73,2,45,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,72,,,,,,,,,,,,,,,,2,45,
1 package sink source summary sink:bean-validation sink:command-injection sink:credentials-key sink:credentials-password sink:credentials-username sink:encryption-iv sink:encryption-salt sink:environment-injection sink:file-content-store sink:fragment-injection sink:groovy-injection sink:hostname-verification sink:html-injection sink:information-leak sink:intent-redirection sink:jexl-injection sink:jndi-injection sink:js-injection sink:ldap-injection sink:log-injection sink:mvel-injection sink:notification sink:ognl-injection sink:path-injection sink:path-injection[read] sink:pending-intents sink:regex-use sink:regex-use[-1] sink:regex-use[0] sink:regex-use[] sink:regex-use[f-1] sink:regex-use[f1] sink:regex-use[f] sink:request-forgery sink:response-splitting sink:sql-injection sink:template-injection sink:trust-boundary-violation sink:unsafe-deserialization sink:url-forward sink:url-redirection sink:xpath-injection sink:xslt-injection source:android-external-storage-dir source:commandargs source:contentprovider source:database source:environment source:file source:remote summary:taint summary:value
188 org.apache.hc.client5.http.async.methods 84 84
189 org.apache.hc.client5.http.classic.methods 37 37
190 org.apache.hc.client5.http.fluent 19 19
org.apache.hc.client5.http.protocol 1 1
org.apache.hc.client5.http.utils 7 7
191 org.apache.hc.core5.benchmark 1 1
192 org.apache.hc.core5.function 1 1
193 org.apache.hc.core5.http 73 2 45 1 72 2 45

View File

@@ -40,6 +40,6 @@ Java framework & library support
`Spring <https://spring.io/>`_,``org.springframework.*``,46,494,143,26,,28,14,,35
`Thymeleaf <https://www.thymeleaf.org/>`_,``org.thymeleaf``,,2,2,,,,,,
`jOOQ <https://www.jooq.org/>`_,``org.jooq``,,,1,,,1,,,
Others,"``actions.osgi``, ``antlr``, ``ch.ethz.ssh2``, ``cn.hutool.core.codec``, ``com.alibaba.com.caucho.hessian.io``, ``com.alibaba.druid.sql``, ``com.alibaba.fastjson2``, ``com.amazonaws.auth``, ``com.auth0.jwt.algorithms``, ``com.azure.identity``, ``com.caucho.burlap.io``, ``com.caucho.hessian.io``, ``com.cedarsoftware.util.io``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.esotericsoftware.yamlbeans``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.microsoft.sqlserver.jdbc``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2``, ``com.sshtools.j2ssh.authentication``, ``com.sun.crypto.provider``, ``com.sun.jndi.ldap``, ``com.sun.net.httpserver``, ``com.sun.net.ssl``, ``com.sun.rowset``, ``com.sun.security.auth.module``, ``com.sun.security.ntlm``, ``com.sun.security.sasl.digest``, ``com.thoughtworks.xstream``, ``com.trilead.ssh2``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``hudson``, ``io.jsonwebtoken``, ``io.undertow.server.handlers.resource``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``liquibase.database.jvm``, ``liquibase.statement.core``, ``net.lingala.zip4j``, ``net.schmizz.sshj``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.avro``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.exec``, ``org.apache.commons.fileupload``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.lang``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.cxf.catalog``, ``org.apache.cxf.common.classloader``, ``org.apache.cxf.common.jaxb``, ``org.apache.cxf.common.logging``, ``org.apache.cxf.configuration.jsse``, ``org.apache.cxf.helpers``, ``org.apache.cxf.resource``, ``org.apache.cxf.staxutils``, ``org.apache.cxf.tools.corba.utils``, ``org.apache.cxf.tools.util``, ``org.apache.cxf.transform``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hadoop.hive.ql.exec``, ``org.apache.hadoop.hive.ql.metadata``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hc.client5.http.protocol``, ``org.apache.hc.client5.http.utils``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.ibatis.mapping``, ``org.apache.log4j``, ``org.apache.shiro.authc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.shiro.mgt``, ``org.apache.sshd.client.session``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.codehaus.cargo.container.installer``, ``org.dom4j``, ``org.exolab.castor.xml``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.gradle.api.file``, ``org.ho.yaml``, ``org.influxdb``, ``org.jabsorb``, ``org.jboss.vfs``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.keycloak.models.map.storage``, ``org.kohsuke.stapler``, ``org.lastaflute.web``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.owasp.esapi``, ``org.pac4j.jwt.config.encryption``, ``org.pac4j.jwt.config.signature``, ``org.scijava.log``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``software.amazon.awssdk.transfer.s3.model``, ``sun.jvmstat.perfdata.monitor.protocol.local``, ``sun.jvmstat.perfdata.monitor.protocol.rmi``, ``sun.misc``, ``sun.net.ftp``, ``sun.net.www.protocol.http``, ``sun.security.acl``, ``sun.security.jgss.krb5``, ``sun.security.krb5``, ``sun.security.pkcs``, ``sun.security.pkcs11``, ``sun.security.provider``, ``sun.security.ssl``, ``sun.security.x509``, ``sun.tools.jconsole``",127,6042,775,148,6,14,18,,186
Totals,,382,26411,2707,421,16,137,33,1,415
Others,"``actions.osgi``, ``antlr``, ``ch.ethz.ssh2``, ``cn.hutool.core.codec``, ``com.alibaba.com.caucho.hessian.io``, ``com.alibaba.druid.sql``, ``com.alibaba.fastjson2``, ``com.amazonaws.auth``, ``com.auth0.jwt.algorithms``, ``com.azure.identity``, ``com.caucho.burlap.io``, ``com.caucho.hessian.io``, ``com.cedarsoftware.util.io``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.esotericsoftware.yamlbeans``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.microsoft.sqlserver.jdbc``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2``, ``com.sshtools.j2ssh.authentication``, ``com.sun.crypto.provider``, ``com.sun.jndi.ldap``, ``com.sun.net.httpserver``, ``com.sun.net.ssl``, ``com.sun.rowset``, ``com.sun.security.auth.module``, ``com.sun.security.ntlm``, ``com.sun.security.sasl.digest``, ``com.thoughtworks.xstream``, ``com.trilead.ssh2``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``hudson``, ``io.jsonwebtoken``, ``io.undertow.server.handlers.resource``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``liquibase.database.jvm``, ``liquibase.statement.core``, ``net.lingala.zip4j``, ``net.schmizz.sshj``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.avro``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.exec``, ``org.apache.commons.fileupload``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.lang``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.cxf.catalog``, ``org.apache.cxf.common.classloader``, ``org.apache.cxf.common.jaxb``, ``org.apache.cxf.common.logging``, ``org.apache.cxf.configuration.jsse``, ``org.apache.cxf.helpers``, ``org.apache.cxf.resource``, ``org.apache.cxf.staxutils``, ``org.apache.cxf.tools.corba.utils``, ``org.apache.cxf.tools.util``, ``org.apache.cxf.transform``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hadoop.hive.ql.exec``, ``org.apache.hadoop.hive.ql.metadata``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.ibatis.mapping``, ``org.apache.log4j``, ``org.apache.shiro.authc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.shiro.mgt``, ``org.apache.sshd.client.session``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.codehaus.cargo.container.installer``, ``org.dom4j``, ``org.exolab.castor.xml``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.gradle.api.file``, ``org.ho.yaml``, ``org.influxdb``, ``org.jabsorb``, ``org.jboss.vfs``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.keycloak.models.map.storage``, ``org.kohsuke.stapler``, ``org.lastaflute.web``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.owasp.esapi``, ``org.pac4j.jwt.config.encryption``, ``org.pac4j.jwt.config.signature``, ``org.scijava.log``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``software.amazon.awssdk.transfer.s3.model``, ``sun.jvmstat.perfdata.monitor.protocol.local``, ``sun.jvmstat.perfdata.monitor.protocol.rmi``, ``sun.misc``, ``sun.net.ftp``, ``sun.net.www.protocol.http``, ``sun.security.acl``, ``sun.security.jgss.krb5``, ``sun.security.krb5``, ``sun.security.pkcs``, ``sun.security.pkcs11``, ``sun.security.provider``, ``sun.security.ssl``, ``sun.security.x509``, ``sun.tools.jconsole``",127,6034,775,148,6,14,18,,186
Totals,,382,26403,2707,421,16,137,33,1,415

View File

@@ -1242,12 +1242,13 @@ public class FileUtil
public static File tryMakeCanonical (File f)
{
try {
return f.getCanonicalFile();
f = f.getCanonicalFile();
}
catch (IOException ignored) {
Exceptions.ignore(ignored, "Can't log error: Could be too verbose.");
return new File(simplifyPath(f));
f = new File(simplifyPath(f));
}
return SubstResolver.resolve(f);
}

View File

@@ -0,0 +1,76 @@
package com.semmle.util.files;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Resolves Windows {@code subst}ed drive letters to their underlying paths. On non-Windows
* platforms, or when the native library failed to load, {@link #resolve(File)} is a no-op that
* returns its argument unchanged.
*/
public class SubstResolver {
private static final boolean available;
static {
boolean loaded = false;
if (File.separatorChar == '\\') {
String dist = System.getenv("CODEQL_DIST");
if (dist != null && !dist.isEmpty()) {
try {
Path library = Paths.get(dist).resolve("tools").resolve("win64")
.resolve("canonicalize.dll").toAbsolutePath();
System.load(library.toString());
loaded = true;
} catch (RuntimeException | UnsatisfiedLinkError ignored) {
}
}
}
available = loaded;
}
private SubstResolver() {}
/**
* Given a drive root like {@code "X:\\"}, returns the path that drive is
* {@code subst}ed to, or {@code null} if the letter isn't a subst mapping.
*/
private static native String nativeResolveSubst(String driveRoot);
/**
* If {@code f} is an absolute path starting with a {@code subst}ed drive letter, return an
* equivalent path with the drive letter replaced by its target. Otherwise return {@code f}
* unchanged.
*/
public static File resolve(File f) {
if (!available) {
return f;
}
String path = f.getPath();
if (path.length() < 3 || path.charAt(1) != ':') {
return f;
}
char sep = path.charAt(2);
if (sep != '\\' && sep != '/') {
return f;
}
if (!isDriveLetter(path.charAt(0))) {
return f;
}
String resolved = nativeResolveSubst(path.substring(0, 3));
if (resolved == null) {
return f;
}
return new File(resolved + path.substring(2));
}
private static boolean isDriveLetter(char c) {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
public static boolean isAvailable() {
return available;
}
}

View File

@@ -247,8 +247,8 @@ private predicate simpleLocalFlowStep0(Node node1, Node node2, string model) {
or
cloneStep(node1, node2) and model = "CloneStep"
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(node1, node2.(FlowSummaryNode).getSummaryNode(),
true, model)
FlowSummaryImpl::Private::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
node2.(FlowSummaryNode).getSummaryNode(), true, model)
}
/**

View File

@@ -41,8 +41,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::JavaDataFlow> {
class SinkBase = Void;
class FlowSummaryCallBase = Void;
predicate neutralElement(
Input::SummarizedCallableBase c, string kind, string provenance, boolean isExact
) {
@@ -146,10 +144,6 @@ private module TypesInput implements Impl::Private::TypesInputSig {
}
private module StepsInput implements Impl::Private::StepsInputSig {
Impl::Private::SummaryNode getSummaryNode(Node n) {
result = n.(FlowSummaryNode).getSummaryNode()
}
DataFlowCall getACall(Public::SummarizedCallable sc) {
sc = viableCallable(result).asSummarizedCallable()
}

View File

@@ -145,8 +145,8 @@ private module Cached {
)
)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(src,
sink.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false, model)
FlowSummaryImpl::Private::Steps::summaryLocalStep(src.(DataFlowPrivate::FlowSummaryNode)
.getSummaryNode(), sink.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false, model)
}
/**

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The Java extractor and QL libraries now support Java 27.

View File

@@ -13,7 +13,8 @@ predicate taintFlowUpdate(DataFlow::ParameterNode p1, DataFlow::ParameterNode p2
}
predicate summaryStep(FlowSummaryNode src, FlowSummaryNode sink) {
FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink.getSummaryNode(), false, _) or
FlowSummaryImpl::Private::Steps::summaryLocalStep(src.getSummaryNode(), sink.getSummaryNode(),
false, _) or
FlowSummaryImpl::Private::Steps::summaryReadStep(src.getSummaryNode(), _, sink.getSummaryNode()) or
FlowSummaryImpl::Private::Steps::summaryStoreStep(src.getSummaryNode(), _, sink.getSummaryNode())
}

View File

@@ -1212,8 +1212,8 @@ private predicate valuePreservingStep(Node node1, Node node2) {
or
node2 = FlowSteps::getThrowTarget(node1)
or
FlowSummaryPrivate::Steps::summaryLocalStep(node1, node2.(FlowSummaryNode).getSummaryNode(), true,
_) // TODO: preserve 'model'
FlowSummaryPrivate::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
node2.(FlowSummaryNode).getSummaryNode(), true, _) // TODO: preserve 'model'
}
predicate knownSourceModel(Node sink, string model) { none() }

View File

@@ -142,10 +142,6 @@ string encodeArgumentPosition(ArgumentPosition pos) {
ReturnKind getStandardReturnValueKind() { result = MkNormalReturnKind() and Stage::ref() }
private module FlowSummaryStepInput implements Private::StepsInputSig {
Private::SummaryNode getSummaryNode(DataFlow::Node n) {
result = n.(FlowSummaryNode).getSummaryNode()
}
overlay[global]
DataFlowCall getACall(SummarizedCallable sc) {
exists(LibraryCallable callable | callable = sc |

View File

@@ -12,8 +12,8 @@ cached
predicate defaultAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
TaintTracking::AdditionalTaintStep::step(node1, node2)
or
FlowSummaryPrivate::Steps::summaryLocalStep(node1, node2.(FlowSummaryNode).getSummaryNode(),
false, _) // TODO: preserve 'model' parameter
FlowSummaryPrivate::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
node2.(FlowSummaryNode).getSummaryNode(), false, _) // TODO: preserve 'model' parameter
or
// Convert steps out of array elements to plain taint steps
FlowSummaryPrivate::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(),

View File

@@ -3,7 +3,6 @@ private import DataFlowImplSpecific
private import codeql.dataflow.DataFlow as SharedDataFlow
private import codeql.dataflow.TaintTracking as SharedTaintTracking
private import codeql.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import codeql.util.Void
module JSDataFlow implements SharedDataFlow::InputSig<Location> {
import Private
@@ -29,8 +28,6 @@ module JSFlowSummary implements FlowSummaryImpl::InputSig<Location, JSDataFlow>
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
import FlowSummaryPrivate
class FlowSummaryCallBase = Void;
overlay[local]
predicate callableFromSource(SummarizedCallableBase c) { none() }

View File

@@ -70,7 +70,7 @@ No user-facing changes.
### Minor Analysis Improvements
* Added new full SSRF sanitization barrier from the new AntiSSRF library.
* Added new full SSRF sanitization barrier from the new AntiSSRF library.
* When a guard such as `isSafe(x)` is defined, we now also automatically handle `isSafe(x) == true` and `isSafe(x) != false`.
## 6.1.1
@@ -169,7 +169,7 @@ No user-facing changes.
### Minor Analysis Improvements
- The modelling of Psycopg2 now supports the use of `psycopg2.pool` connection pools for handling database connections.
* Removed `lxml` as an XML bomb sink. The underlying libxml2 library now includes [entity reference loop detection](https://github.com/lxml/lxml/blob/f33ac2c2f5f9c4c4c1fc47f363be96db308f2fa6/doc/FAQ.txt#L1077) that prevents XML bomb attacks.
* Removed `lxml` as an XML bomb sink. The underlying libxml2 library now includes [entity reference loop detection](https://github.com/lxml/lxml/blob/f33ac2c2f5f9c4c4c1fc47f363be96db308f2fa6/doc/FAQ.txt#L1077) that prevents XML bomb attacks.
## 4.0.13
@@ -262,7 +262,7 @@ No user-facing changes.
### Minor Analysis Improvements
* The sensitive data library has been improved so that `snake_case` style variable names are recognized more reliably. This may result in more sensitive data being identified, and more results from queries that use the sensitive data library.
- Additional taint steps through methods of `lxml.etree.Element` and `lxml.etree.ElementTree` objects from the `lxml` PyPI package have been modeled.
- Additional taint steps through methods of `lxml.etree.Element` and `lxml.etree.ElementTree` objects from the `lxml` PyPI package have been modeled.
## 3.1.0
@@ -316,7 +316,7 @@ No user-facing changes.
### Minor Analysis Improvements
* The common sanitizer guard `StringConstCompareBarrier` has been renamed to `ConstCompareBarrier` and expanded to cover comparisons with other constant values such as `None`. This may result in fewer false positive results for several queries.
* The common sanitizer guard `StringConstCompareBarrier` has been renamed to `ConstCompareBarrier` and expanded to cover comparisons with other constant values such as `None`. This may result in fewer false positive results for several queries.
## 2.0.0
@@ -545,7 +545,7 @@ No user-facing changes.
### New Features
* The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`.
* The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`.
Hence it is no longer needed to provide `none()` implementations of these predicates if they are not needed.
### Minor Analysis Improvements
@@ -572,7 +572,7 @@ No user-facing changes.
* Deleted many deprecated predicates and classes with uppercase `API`, `HTTP`, `XSS`, `SQL`, etc. in their names. Use the PascalCased versions instead.
* Deleted the deprecated `getName()` predicate from the `Container` class, use `getAbsolutePath()` instead.
* Deleted many deprecated module names that started with a lowercase letter, use the versions that start with an uppercase letter instead.
* Deleted many deprecated predicates in `PointsTo.qll`.
* Deleted many deprecated predicates in `PointsTo.qll`.
* Deleted many deprecated files from the `semmle.python.security` package.
* Deleted the deprecated `BottleRoutePointToExtension` class from `Extensions.qll`.
* Type tracking is now aware of flow summaries. This leads to a richer API graph, and may lead to more results in some queries.
@@ -729,7 +729,7 @@ No user-facing changes.
### Deprecated APIs
* Some unused predicates in `SsaDefinitions.qll`, `TObject.qll`, `protocols.qll`, and the `pointsto/` folder have been deprecated.
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
### Minor Analysis Improvements
@@ -748,9 +748,9 @@ No user-facing changes.
### Deprecated APIs
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
* The utility files previously in the `semmle.python.security.performance` package have been moved to the `semmle.python.security.regexp` package.
* The utility files previously in the `semmle.python.security.performance` package have been moved to the `semmle.python.security.regexp` package.
The previous files still exist as deprecated aliases.
### Minor Analysis Improvements
@@ -843,9 +843,9 @@ No user-facing changes.
### Deprecated APIs
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
* Some modules that started with a lowercase letter have been renamed to follow our style-guide.
* Some modules that started with a lowercase letter have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
### New Features

View File

@@ -529,7 +529,7 @@ predicate simpleLocalFlowStepForTypetracking(Node nodeFrom, Node nodeTo) {
}
private predicate summaryLocalStep(Node nodeFrom, Node nodeTo, string model) {
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
}

View File

@@ -20,8 +20,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::PythonDataFlow>
class SinkBase = Void;
class FlowSummaryCallBase = Void;
predicate callableFromSource(SummarizedCallableBase c) { none() }
ArgumentPosition callbackSelfParameterPosition() { result.isLambdaSelf() }
@@ -113,10 +111,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::PythonDataFlow>
private import Make<Location, DataFlowImplSpecific::PythonDataFlow, Input> as Impl
private module StepsInput implements Impl::Private::StepsInputSig {
Impl::Private::SummaryNode getSummaryNode(Node n) {
result = n.(FlowSummaryNode).getSummaryNode()
}
overlay[global]
DataFlowCall getACall(Public::SummarizedCallable sc) {
result =

View File

@@ -80,8 +80,10 @@ private module Cached {
) and
model = ""
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
nodeTo.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false, model)
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom
.(DataFlowPrivate::FlowSummaryNode)
.getSummaryNode(), nodeTo.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false,
model)
}
}

View File

@@ -170,13 +170,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */
predicate levelStepCall(Node nodeFrom, LocalSourceNode nodeTo) {
// HOTFIX: `instanceFieldStep` is temporarily disabled (via `and none()`).
// It uses `classInstanceTracker(cls)` -- itself a type-tracker run --
// from inside `levelStepCall`, creating a structural mutual recursion
// that causes catastrophic query slowdowns on some OOP-heavy Python
// codebases (e.g. mypy and dask). The `and none()` should be removed
// once that recursion is redesigned.
instanceFieldStep(nodeFrom, nodeTo) and none()
instanceFieldStep(nodeFrom, nodeTo)
or
inheritedFieldStep(nodeFrom, nodeTo)
}

View File

@@ -157,7 +157,7 @@ class MyClass2(object):
print(self.foo) # $ tracked MISSING: tracked=foo
instance = MyClass2()
print(instance.foo) # $ MISSING: tracked=foo tracked
print(instance.foo) # $ tracked MISSING: tracked=foo
instance.print_foo() # $ MISSING: tracked=foo
@@ -195,7 +195,7 @@ class Sub1(Base1):
sub1 = Sub1()
sub1.read_foo()
print(sub1.foo) # $ MISSING: tracked=foo tracked
print(sub1.foo) # $ tracked MISSING: tracked=foo
# attribute written in a subclass method, read in an inherited base class method
@@ -210,7 +210,7 @@ class Sub2(Base2):
sub2 = Sub2()
sub2.read_bar()
print(sub2.bar) # $ MISSING: tracked=bar tracked
print(sub2.bar) # $ tracked MISSING: tracked=bar
# attribute written in a base class method, read on an instance of the subclass
@@ -223,4 +223,4 @@ class Sub3(Base3):
pass
sub3 = Sub3()
print(sub3.baz) # $ MISSING: tracked=baz tracked
print(sub3.baz) # $ tracked MISSING: tracked=baz

View File

@@ -1,6 +1,7 @@
#select
| app.py:23:20:23:24 | ControlFlowNode for query | app.py:20:18:20:21 | ControlFlowNode for name | app.py:23:20:23:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:20:18:20:21 | ControlFlowNode for name | user-provided value |
| app.py:30:20:30:24 | ControlFlowNode for query | app.py:27:19:27:22 | ControlFlowNode for name | app.py:30:20:30:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:27:19:27:22 | ControlFlowNode for name | user-provided value |
| app.py:37:20:37:24 | ControlFlowNode for query | app.py:34:19:34:22 | ControlFlowNode for name | app.py:37:20:37:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:34:19:34:22 | ControlFlowNode for name | user-provided value |
| app.py:44:20:44:24 | ControlFlowNode for query | app.py:41:19:41:22 | ControlFlowNode for name | app.py:44:20:44:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:41:19:41:22 | ControlFlowNode for name | user-provided value |
| app.py:51:20:51:24 | ControlFlowNode for query | app.py:48:19:48:22 | ControlFlowNode for name | app.py:51:20:51:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:48:19:48:22 | ControlFlowNode for name | user-provided value |
| sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | This SQL query depends on a $@. | sql_injection.py:14:15:14:22 | ControlFlowNode for username | user-provided value |
@@ -24,6 +25,8 @@ edges
| app.py:21:5:21:9 | ControlFlowNode for query | app.py:23:20:23:24 | ControlFlowNode for query | provenance | |
| app.py:27:19:27:22 | ControlFlowNode for name | app.py:28:5:28:9 | ControlFlowNode for query | provenance | |
| app.py:28:5:28:9 | ControlFlowNode for query | app.py:30:20:30:24 | ControlFlowNode for query | provenance | |
| app.py:34:19:34:22 | ControlFlowNode for name | app.py:35:5:35:9 | ControlFlowNode for query | provenance | |
| app.py:35:5:35:9 | ControlFlowNode for query | app.py:37:20:37:24 | ControlFlowNode for query | provenance | |
| app.py:41:19:41:22 | ControlFlowNode for name | app.py:42:5:42:9 | ControlFlowNode for query | provenance | |
| app.py:42:5:42:9 | ControlFlowNode for query | app.py:44:20:44:24 | ControlFlowNode for query | provenance | |
| app.py:48:19:48:22 | ControlFlowNode for name | app.py:49:5:49:9 | ControlFlowNode for query | provenance | |
@@ -51,6 +54,9 @@ nodes
| app.py:27:19:27:22 | ControlFlowNode for name | semmle.label | ControlFlowNode for name |
| app.py:28:5:28:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query |
| app.py:30:20:30:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query |
| app.py:34:19:34:22 | ControlFlowNode for name | semmle.label | ControlFlowNode for name |
| app.py:35:5:35:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query |
| app.py:37:20:37:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query |
| app.py:41:19:41:22 | ControlFlowNode for name | semmle.label | ControlFlowNode for name |
| app.py:42:5:42:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query |
| app.py:44:20:44:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query |

View File

@@ -31,10 +31,10 @@ async def unsafe2(name: str): # $ Source
cursor.close()
@app.get("/unsafe3/")
async def unsafe3(name: str): # $ MISSING: Source
async def unsafe3(name: str): # $ Source
query = "select * from users where name=" + name
cursor = hdb_con3.cursor()
cursor.execute(query) # $ MISSING: Alert
cursor.execute(query) # $ Alert
cursor.close()
@app.get("/unsafe4/")

View File

@@ -198,7 +198,8 @@ module LocalFlow {
FlowSummaryNode nodeFrom, FlowSummaryNode nodeTo, FlowSummaryImpl::Public::SummarizedCallable c,
string model
) {
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo.getSummaryNode(), true, model) and
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.getSummaryNode(),
nodeTo.getSummaryNode(), true, model) and
c = nodeFrom.getSummarizedCallable()
}

View File

@@ -18,8 +18,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::RubyDataFlow> {
class SinkBase = Void;
class FlowSummaryCallBase = Void;
predicate callableFromSource(SummarizedCallableBase c) { none() }
ArgumentPosition callbackSelfParameterPosition() { result.isLambdaSelf() }
@@ -159,10 +157,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::RubyDataFlow> {
private import Make<Location, DataFlowImplSpecific::RubyDataFlow, Input> as Impl
private module StepsInput implements Impl::Private::StepsInputSig {
Impl::Private::SummaryNode getSummaryNode(Node n) {
result = n.(FlowSummaryNode).getSummaryNode()
}
DataFlowCall getACall(Public::SummarizedCallable sc) {
result.asCall().getAstNode() = sc.(LibraryCallable).getACall()
or

View File

@@ -109,7 +109,7 @@ private module Cached {
) and
model = ""
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
or
any(FlowSteps::AdditionalTaintStep s).step(nodeFrom, nodeTo) and model = "AdditionalTaintStep"

View File

@@ -180,7 +180,7 @@ Expr getPostUpdateReverseStep(Expr e, boolean preservesValue) {
module LocalFlow {
predicate flowSummaryLocalStep(Node nodeFrom, Node nodeTo, string model) {
exists(FlowSummaryImpl::Public::SummarizedCallable c |
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model) and
c = nodeFrom.(FlowSummaryNode).getSummarizedCallable()
)

View File

@@ -11,7 +11,6 @@ private import codeql.rust.dataflow.FlowSummary
private import codeql.rust.dataflow.Ssa
private import codeql.rust.dataflow.internal.ModelsAsData
private import Content
private import Node
predicate encodeContentTupleField(TupleFieldContent c, string arg) {
exists(Addressable a, int pos, string prefix |
@@ -29,12 +28,9 @@ predicate encodeContentStructField(StructFieldContent c, string arg) {
module Input implements InputSig<Location, RustDataFlow> {
private import codeql.rust.frameworks.stdlib.Stdlib
private import codeql.util.Void
class SummarizedCallableBase = Function;
class FlowSummaryCallBase = Void;
predicate callableFromSource(SummarizedCallableBase c) { c.fromSource() }
abstract private class SourceSinkBase extends AstNode {
@@ -148,10 +144,6 @@ module Input implements InputSig<Location, RustDataFlow> {
private import Make<Location, RustDataFlow, Input> as Impl
module StepsInput implements Impl::Private::StepsInputSig {
Impl::Private::SummaryNode getSummaryNode(RustDataFlow::Node n) {
result = n.(FlowSummaryNode).getSummaryNode()
}
DataFlowCall getACall(Public::SummarizedCallable sc) { result.asCall().getStaticTarget() = sc }
/** Gets the argument of `source` described by `sc`, if any. */

View File

@@ -83,7 +83,7 @@ module RustTaintTrackingGen<DataFlowImpl::RustDataFlowInputSig I> implements
pred.(Node::PostUpdateNode).getPreUpdateNode().asExpr(), _, succ, _)
)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(pred,
FlowSummaryImpl::Private::Steps::summaryLocalStep(pred.(Node::FlowSummaryNode).getSummaryNode(),
succ.(Node::FlowSummaryNode).getSummaryNode(), false, model)
}

View File

@@ -62,34 +62,24 @@ module HardcodedCryptographicValue {
abstract class Barrier extends DataFlow::Node { }
/**
* Holds if `e` is a literal or a combination of literals that is constant.
* A literal, considered as a flow source.
*/
private predicate isConstant(Expr e) {
e instanceof LiteralExpr // e.g. `0`
or
forex(Expr elem | elem = e.(ArrayListExpr).getExpr(_) | isConstant(elem)) // e.g. `[0, 0, 0, 0]`
or
isConstant(e.(ArrayRepeatExpr).getRepeatOperand()) // e.g. `[0; 10]`
or
// e.g. `const MY_CONST: u64 = ...`
// the constant initializer / body is the preferred source location for flow paths, when available.
e = any(Const c).getBody()
or
// e.g. `u64::MAX`
// when the constant initializer is not available as a source location (case above), use the access instead.
e instanceof ConstAccess and
not exists(e.(ConstAccess).getConst().getBody())
or
// e.g. `1 << 4`
isConstant(e.(BinaryExpr).getLhs()) and
isConstant(e.(BinaryExpr).getRhs())
private class LiteralSource extends Source {
LiteralSource() { this.asExpr() instanceof LiteralExpr }
}
/**
* A constant, considered as a flow source.
* An array initialized from a list of literals, considered as a single flow source. For example:
* ```
* [0, 0, 0, 0]
* [0; 10]
* ```
*/
private class ConstantSource extends Source {
ConstantSource() { isConstant(this.asExpr()) }
private class ArrayListSource extends Source {
ArrayListSource() {
this.asExpr().(ArrayListExpr).getExpr(_) instanceof LiteralExpr or
this.asExpr().(ArrayRepeatExpr).getRepeatOperand() instanceof LiteralExpr
}
}
/**
@@ -165,24 +155,4 @@ module HardcodedCryptographicValue {
)
}
}
/**
* An arithmetic or bitwise operation that acts as a barrier.
*
* This prevents false positives where a hard-coded value is combined with
* non-constant data through operations like `+`, `^`, or `+=` (including string concatenation).
*/
private class ArithmeticOperationBarrier extends Barrier {
ArithmeticOperationBarrier() {
// binary operations (e.g. `a + b`, `a ^ b`)
this.asExpr() = any(BinaryArithmeticOperation a).getAnOperand()
or
this.asExpr() = any(BinaryBitwiseOperation a).getAnOperand()
or
// compound assignments (e.g. `a += b`, `a ^= b`)
this.asExpr() = any(AssignArithmeticOperation a).getAnOperand()
or
this.asExpr() = any(AssignBitwiseOperation a).getAnOperand()
}
}
}

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `rust/hard-coded-cryptographic-value` query now treats arithmetic and bitwise operations, including string append operations, as barriers. This addresses false positive results where hard-coded constants are combined with non-constant data, such as incrementing a nonce or appending variable data to a constant prefix.

View File

@@ -1,5 +1,5 @@
multipleResolvedTargets
| main.rs:2240:9:2240:31 | ... .my_add(...) |
| main.rs:2242:9:2242:29 | ... .my_add(...) |
| main.rs:2757:13:2757:17 | x.f() |
| main.rs:2223:9:2223:31 | ... .my_add(...) |
| main.rs:2225:9:2225:29 | ... .my_add(...) |
| main.rs:2740:13:2740:17 | x.f() |
| regressions.rs:179:17:179:27 | ... + ... |

View File

@@ -264,10 +264,6 @@ mod method_non_parametric_trait_impl {
}
}
trait MyTrait2<B> {
fn m3(self) -> B;
}
trait MyProduct<A, B> {
// MyProduct::fst
fn fst(self) -> A;
@@ -279,10 +275,6 @@ mod method_non_parametric_trait_impl {
x.m1() // $ target=m1
}
fn call_trait_m1_trait2_m3<T1, T2: MyTrait<T1>, T3: MyTrait2<T2>>(x: T3) -> T1 {
x.m3().m1() // $ target=m1 target=m3
}
impl MyTrait<S1> for MyThing<S1> {
// MyThing<S1>::m1
fn m1(self) -> S1 {
@@ -297,13 +289,6 @@ mod method_non_parametric_trait_impl {
}
}
impl MyTrait2<MyThing<S1>> for MyThing<S2> {
// MyThing<S2>::m3
fn m3(self) -> MyThing<S1> {
MyThing { a: S1 }
}
}
// Implementation where the type parameter `TD` only occurs in the
// implemented trait and not the implementing type.
impl<TD> MyTrait<TD> for MyThing<S3>
@@ -468,8 +453,6 @@ mod method_non_parametric_trait_impl {
let thing = MyThing { a: S1 };
let i = thing.convert_to(); // $ type=i:S1 target=T::convert_to
let j = convert_to(thing); // $ target=convert_to $ MISSING: type=j:S1 -- the blanket implementation `impl<T: MyTrait<S1>> ConvertTo<S1> for T` is currently not included in the constraint analysis
let x = call_trait_m1_trait2_m3(MyThing { a: S2 }); // $ target=call_trait_m1_trait2_m3 type=x:S1
}
}

View File

@@ -10,50 +10,45 @@
| test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:22:16:22:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:22:16:22:24 | ...::from | a key |
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:42:14:42:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:42:14:42:32 | ...::from | a key |
| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:53:14:53:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:53:14:53:32 | ...::from | a key |
| test_heuristic.rs:38:25:38:30 | 0xFFFF | test_heuristic.rs:38:25:38:30 | 0xFFFF | test_heuristic.rs:81:22:81:31 | MY_CONST_1 | This hard-coded value is used as $@. | test_heuristic.rs:81:22:81:31 | MY_CONST_1 | a salt |
| test_heuristic.rs:39:25:39:59 | ... as u64 | test_heuristic.rs:39:25:39:59 | ... as u64 | test_heuristic.rs:82:22:82:31 | MY_CONST_2 | This hard-coded value is used as $@. | test_heuristic.rs:82:22:82:31 | MY_CONST_2 | a salt |
| test_heuristic.rs:40:27:40:32 | 0xFFFF | test_heuristic.rs:40:27:40:32 | 0xFFFF | test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | This hard-coded value is used as $@. | test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | a salt |
| test_heuristic.rs:49:31:49:38 | [0u8; 16] | test_heuristic.rs:49:31:49:38 | [0u8; 16] | test_heuristic.rs:50:41:50:48 | const_iv | This hard-coded value is used as $@. | test_heuristic.rs:50:41:50:48 | const_iv | an initialization vector |
| test_heuristic.rs:68:30:68:37 | "secret" | test_heuristic.rs:68:30:68:37 | "secret" | test_heuristic.rs:68:30:68:37 | "secret" | This hard-coded value is used as $@. | test_heuristic.rs:68:30:68:37 | "secret" | a password |
| test_heuristic.rs:69:20:69:27 | [0u8; 16] | test_heuristic.rs:69:20:69:27 | [0u8; 16] | test_heuristic.rs:69:19:69:27 | &... | This hard-coded value is used as $@. | test_heuristic.rs:69:19:69:27 | &... | a nonce |
| test_heuristic.rs:70:31:70:38 | [0u8; 16] | test_heuristic.rs:70:31:70:38 | [0u8; 16] | test_heuristic.rs:70:30:70:38 | &... | This hard-coded value is used as $@. | test_heuristic.rs:70:30:70:38 | &... | a salt |
| test_heuristic.rs:72:22:72:22 | 0 | test_heuristic.rs:72:22:72:22 | 0 | test_heuristic.rs:72:22:72:22 | 0 | This hard-coded value is used as $@. | test_heuristic.rs:72:22:72:22 | 0 | a salt |
| test_heuristic.rs:76:22:76:27 | ... << ... | test_heuristic.rs:76:22:76:27 | ... << ... | test_heuristic.rs:76:22:76:27 | ... << ... | This hard-coded value is used as $@. | test_heuristic.rs:76:22:76:27 | ... << ... | a salt |
| test_heuristic.rs:78:22:78:29 | ...::MAX | test_heuristic.rs:78:22:78:29 | ...::MAX | test_heuristic.rs:78:22:78:29 | ...::MAX | This hard-coded value is used as $@. | test_heuristic.rs:78:22:78:29 | ...::MAX | a salt |
| test_heuristic.rs:79:22:79:33 | ... / ... | test_heuristic.rs:79:22:79:33 | ... / ... | test_heuristic.rs:79:22:79:33 | ... / ... | This hard-coded value is used as $@. | test_heuristic.rs:79:22:79:33 | ... / ... | a salt |
| test_heuristic.rs:86:29:86:32 | 1u64 | test_heuristic.rs:86:29:86:32 | 1u64 | test_heuristic.rs:87:22:87:31 | MY_CONST_5 | This hard-coded value is used as $@. | test_heuristic.rs:87:22:87:31 | MY_CONST_5 | a salt |
| test_heuristic.rs:88:29:88:33 | ... + ... | test_heuristic.rs:88:29:88:33 | ... + ... | test_heuristic.rs:89:22:89:31 | MY_CONST_6 | This hard-coded value is used as $@. | test_heuristic.rs:89:22:89:31 | MY_CONST_6 | a salt |
| test_heuristic.rs:44:31:44:38 | [0u8; 16] | test_heuristic.rs:44:31:44:38 | [0u8; 16] | test_heuristic.rs:45:41:45:48 | const_iv | This hard-coded value is used as $@. | test_heuristic.rs:45:41:45:48 | const_iv | an initialization vector |
| test_heuristic.rs:63:30:63:37 | "secret" | test_heuristic.rs:63:30:63:37 | "secret" | test_heuristic.rs:63:30:63:37 | "secret" | This hard-coded value is used as $@. | test_heuristic.rs:63:30:63:37 | "secret" | a password |
| test_heuristic.rs:64:20:64:27 | [0u8; 16] | test_heuristic.rs:64:20:64:27 | [0u8; 16] | test_heuristic.rs:64:19:64:27 | &... | This hard-coded value is used as $@. | test_heuristic.rs:64:19:64:27 | &... | a nonce |
| test_heuristic.rs:65:31:65:38 | [0u8; 16] | test_heuristic.rs:65:31:65:38 | [0u8; 16] | test_heuristic.rs:65:30:65:38 | &... | This hard-coded value is used as $@. | test_heuristic.rs:65:30:65:38 | &... | a salt |
| test_heuristic.rs:67:22:67:22 | 0 | test_heuristic.rs:67:22:67:22 | 0 | test_heuristic.rs:67:22:67:22 | 0 | This hard-coded value is used as $@. | test_heuristic.rs:67:22:67:22 | 0 | a salt |
| test_heuristic.rs:69:32:69:32 | 1 | test_heuristic.rs:69:32:69:32 | 1 | test_heuristic.rs:69:22:69:32 | ... + ... | This hard-coded value is used as $@. | test_heuristic.rs:69:22:69:32 | ... + ... | a salt |
| test_heuristic.rs:70:34:70:35 | 32 | test_heuristic.rs:70:34:70:35 | 32 | test_heuristic.rs:70:22:70:62 | ... ^ ... | This hard-coded value is used as $@. | test_heuristic.rs:70:22:70:62 | ... ^ ... | a salt |
| test_heuristic.rs:70:52:70:61 | 0xFFFFFFFF | test_heuristic.rs:70:52:70:61 | 0xFFFFFFFF | test_heuristic.rs:70:22:70:62 | ... ^ ... | This hard-coded value is used as $@. | test_heuristic.rs:70:22:70:62 | ... ^ ... | a salt |
edges
| test_cipher.rs:18:9:18:14 | const1 [&ref] | test_cipher.rs:19:73:19:78 | const1 [&ref] | provenance | |
| test_cipher.rs:18:28:18:36 | &... [&ref] | test_cipher.rs:18:9:18:14 | const1 [&ref] | provenance | |
| test_cipher.rs:18:29:18:36 | [0u8; 16] | test_cipher.rs:18:28:18:36 | &... [&ref] | provenance | |
| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:3 Sink:MaD:3 |
| test_cipher.rs:19:73:19:78 | const1 [&ref] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | provenance | MaD:13 |
| test_cipher.rs:19:73:19:78 | const1 [&ref] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | provenance | MaD:17 |
| test_cipher.rs:25:9:25:14 | const4 [&ref] | test_cipher.rs:26:66:26:71 | const4 [&ref] | provenance | |
| test_cipher.rs:25:28:25:36 | &... [&ref] | test_cipher.rs:25:9:25:14 | const4 [&ref] | provenance | |
| test_cipher.rs:25:29:25:36 | [0u8; 16] | test_cipher.rs:25:28:25:36 | &... [&ref] | provenance | |
| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:4 Sink:MaD:4 |
| test_cipher.rs:26:66:26:71 | const4 [&ref] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | provenance | MaD:13 |
| test_cipher.rs:26:66:26:71 | const4 [&ref] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | provenance | MaD:17 |
| test_cipher.rs:29:9:29:14 | const5 [&ref] | test_cipher.rs:30:95:30:100 | const5 [&ref] | provenance | |
| test_cipher.rs:29:28:29:36 | &... [&ref] | test_cipher.rs:29:9:29:14 | const5 [&ref] | provenance | |
| test_cipher.rs:29:29:29:36 | [0u8; 16] | test_cipher.rs:29:28:29:36 | &... [&ref] | provenance | |
| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:5 Sink:MaD:5 |
| test_cipher.rs:30:95:30:100 | const5 [&ref] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | provenance | MaD:13 |
| test_cipher.rs:30:95:30:100 | const5 [&ref] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | provenance | MaD:17 |
| test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | |
| test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | |
| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:3 Sink:MaD:3 |
| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:13 |
| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:17 |
| test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | |
| test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | |
| test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | |
| test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | |
| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:3 Sink:MaD:3 |
| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:13 |
| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:17 |
| test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | |
| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:7 |
| test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | |
| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 |
| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:13 |
| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:17 |
| test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | |
| test_cipher.rs:73:9:73:14 | const2 [&ref] | test_cipher.rs:74:46:74:51 | const2 [&ref] | provenance | |
| test_cipher.rs:73:18:73:26 | &... [&ref] | test_cipher.rs:73:9:73:14 | const2 [&ref] | provenance | |
@@ -69,27 +64,26 @@ edges
| test_cookie.rs:22:27:22:32 | array2 | test_cookie.rs:22:26:22:32 | &array2 [&ref] | provenance | |
| test_cookie.rs:38:9:38:14 | array2 | test_cookie.rs:42:34:42:39 | array2 | provenance | |
| test_cookie.rs:38:18:38:37 | ...::from(...) | test_cookie.rs:38:9:38:14 | array2 | provenance | |
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:8 |
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:9 |
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:10 |
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:11 |
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:12 |
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:13 |
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:14 |
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:15 |
| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:16 |
| test_cookie.rs:42:34:42:39 | array2 | test_cookie.rs:42:14:42:32 | ...::from | provenance | MaD:2 Sink:MaD:2 |
| test_cookie.rs:49:9:49:14 | array3 [element] | test_cookie.rs:53:34:53:39 | array3 [element] | provenance | |
| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:14 |
| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:18 |
| test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | test_cookie.rs:49:9:49:14 | array3 [element] | provenance | |
| test_cookie.rs:53:34:53:39 | array3 [element] | test_cookie.rs:53:14:53:32 | ...::from | provenance | MaD:2 Sink:MaD:2 |
| test_heuristic.rs:38:25:38:30 | 0xFFFF | test_heuristic.rs:81:22:81:31 | MY_CONST_1 | provenance | |
| test_heuristic.rs:39:25:39:59 | ... as u64 | test_heuristic.rs:82:22:82:31 | MY_CONST_2 | provenance | |
| test_heuristic.rs:39:62:40:33 | static MY_STATIC_3 | test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | provenance | |
| test_heuristic.rs:40:27:40:32 | 0xFFFF | test_heuristic.rs:39:62:40:33 | static MY_STATIC_3 | provenance | |
| test_heuristic.rs:49:9:49:16 | const_iv [&ref] | test_heuristic.rs:50:41:50:48 | const_iv | provenance | |
| test_heuristic.rs:49:30:49:38 | &... [&ref] | test_heuristic.rs:49:9:49:16 | const_iv [&ref] | provenance | |
| test_heuristic.rs:49:31:49:38 | [0u8; 16] | test_heuristic.rs:49:30:49:38 | &... [&ref] | provenance | |
| test_heuristic.rs:69:20:69:27 | [0u8; 16] | test_heuristic.rs:69:19:69:27 | &... | provenance | |
| test_heuristic.rs:70:31:70:38 | [0u8; 16] | test_heuristic.rs:70:30:70:38 | &... | provenance | |
| test_heuristic.rs:86:29:86:32 | 1u64 | test_heuristic.rs:87:22:87:31 | MY_CONST_5 | provenance | |
| test_heuristic.rs:88:29:88:33 | ... + ... | test_heuristic.rs:89:22:89:31 | MY_CONST_6 | provenance | |
| test_heuristic.rs:44:9:44:16 | const_iv [&ref] | test_heuristic.rs:45:41:45:48 | const_iv | provenance | |
| test_heuristic.rs:44:30:44:38 | &... [&ref] | test_heuristic.rs:44:9:44:16 | const_iv [&ref] | provenance | |
| test_heuristic.rs:44:31:44:38 | [0u8; 16] | test_heuristic.rs:44:30:44:38 | &... [&ref] | provenance | |
| test_heuristic.rs:64:20:64:27 | [0u8; 16] | test_heuristic.rs:64:19:64:27 | &... | provenance | |
| test_heuristic.rs:65:31:65:38 | [0u8; 16] | test_heuristic.rs:65:30:65:38 | &... | provenance | |
| test_heuristic.rs:69:32:69:32 | 1 | test_heuristic.rs:69:22:69:32 | ... + ... | provenance | MaD:8 |
| test_heuristic.rs:70:23:70:35 | ... << ... | test_heuristic.rs:70:22:70:62 | ... ^ ... | provenance | MaD:10 |
| test_heuristic.rs:70:34:70:35 | 32 | test_heuristic.rs:70:23:70:35 | ... << ... | provenance | MaD:11 |
| test_heuristic.rs:70:41:70:61 | ... & ... | test_heuristic.rs:70:22:70:62 | ... ^ ... | provenance | MaD:10 |
| test_heuristic.rs:70:52:70:61 | 0xFFFFFFFF | test_heuristic.rs:70:41:70:61 | ... & ... | provenance | MaD:9 |
models
| 1 | Sink: <_ as crypto_common::KeyInit>::new_from_slice; Argument[0]; credentials-key |
| 2 | Sink: <biscotti::crypto::master::Key>::from; Argument[0]; credentials-key |
@@ -98,13 +92,17 @@ models
| 5 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyIvInit>::new; Argument[1]; credentials-iv |
| 6 | Sink: <cookie::secure::key::Key>::from; Argument[0].Reference; credentials-key |
| 7 | Source: core::mem::zeroed; ReturnValue.Element; constant-source |
| 8 | Summary: <alloc::vec::Vec as core::convert::From>::from; Argument[0].Field[alloc::borrow::Cow::Owned(0)]; ReturnValue; value |
| 9 | Summary: <alloc::vec::Vec as core::convert::From>::from; Argument[0].Field[alloc::bstr::ByteString(0)]; ReturnValue; value |
| 10 | Summary: <alloc::vec::Vec as core::convert::From>::from; Argument[0].Field[alloc::collections::binary_heap::BinaryHeap::data]; ReturnValue; value |
| 11 | Summary: <alloc::vec::Vec as core::convert::From>::from; Argument[0].Field[alloc::string::String::vec]; ReturnValue; value |
| 12 | Summary: <alloc::vec::Vec as core::convert::From>::from; Argument[0]; ReturnValue; taint |
| 13 | Summary: <generic_array::GenericArray>::from_slice; Argument[0].Reference; ReturnValue.Reference; value |
| 14 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value |
| 8 | Summary: <_ as core::ops::arith::Add>::add; Argument[self,0]; ReturnValue; taint |
| 9 | Summary: <_ as core::ops::bit::BitAnd>::bitand; Argument[self,0]; ReturnValue; taint |
| 10 | Summary: <_ as core::ops::bit::BitXor>::bitxor; Argument[self,0]; ReturnValue; taint |
| 11 | Summary: <_ as core::ops::bit::Shl>::shl; Argument[self,0]; ReturnValue; taint |
| 12 | Summary: <alloc::vec::Vec as core::convert::From>::from; Argument[0].Field[alloc::borrow::Cow::Owned(0)]; ReturnValue; value |
| 13 | Summary: <alloc::vec::Vec as core::convert::From>::from; Argument[0].Field[alloc::bstr::ByteString(0)]; ReturnValue; value |
| 14 | Summary: <alloc::vec::Vec as core::convert::From>::from; Argument[0].Field[alloc::collections::binary_heap::BinaryHeap::data]; ReturnValue; value |
| 15 | Summary: <alloc::vec::Vec as core::convert::From>::from; Argument[0].Field[alloc::string::String::vec]; ReturnValue; value |
| 16 | Summary: <alloc::vec::Vec as core::convert::From>::from; Argument[0]; ReturnValue; taint |
| 17 | Summary: <generic_array::GenericArray>::from_slice; Argument[0].Reference; ReturnValue.Reference; value |
| 18 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value |
nodes
| test_cipher.rs:18:9:18:14 | const1 [&ref] | semmle.label | const1 [&ref] |
| test_cipher.rs:18:28:18:36 | &... [&ref] | semmle.label | &... [&ref] |
@@ -168,28 +166,21 @@ nodes
| test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | semmle.label | ...::from_elem(...) [element] |
| test_cookie.rs:53:14:53:32 | ...::from | semmle.label | ...::from |
| test_cookie.rs:53:34:53:39 | array3 [element] | semmle.label | array3 [element] |
| test_heuristic.rs:38:25:38:30 | 0xFFFF | semmle.label | 0xFFFF |
| test_heuristic.rs:39:25:39:59 | ... as u64 | semmle.label | ... as u64 |
| test_heuristic.rs:39:62:40:33 | static MY_STATIC_3 | semmle.label | static MY_STATIC_3 |
| test_heuristic.rs:40:27:40:32 | 0xFFFF | semmle.label | 0xFFFF |
| test_heuristic.rs:49:9:49:16 | const_iv [&ref] | semmle.label | const_iv [&ref] |
| test_heuristic.rs:49:30:49:38 | &... [&ref] | semmle.label | &... [&ref] |
| test_heuristic.rs:49:31:49:38 | [0u8; 16] | semmle.label | [0u8; 16] |
| test_heuristic.rs:50:41:50:48 | const_iv | semmle.label | const_iv |
| test_heuristic.rs:68:30:68:37 | "secret" | semmle.label | "secret" |
| test_heuristic.rs:69:19:69:27 | &... | semmle.label | &... |
| test_heuristic.rs:69:20:69:27 | [0u8; 16] | semmle.label | [0u8; 16] |
| test_heuristic.rs:70:30:70:38 | &... | semmle.label | &... |
| test_heuristic.rs:70:31:70:38 | [0u8; 16] | semmle.label | [0u8; 16] |
| test_heuristic.rs:72:22:72:22 | 0 | semmle.label | 0 |
| test_heuristic.rs:76:22:76:27 | ... << ... | semmle.label | ... << ... |
| test_heuristic.rs:78:22:78:29 | ...::MAX | semmle.label | ...::MAX |
| test_heuristic.rs:79:22:79:33 | ... / ... | semmle.label | ... / ... |
| test_heuristic.rs:81:22:81:31 | MY_CONST_1 | semmle.label | MY_CONST_1 |
| test_heuristic.rs:82:22:82:31 | MY_CONST_2 | semmle.label | MY_CONST_2 |
| test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | semmle.label | MY_STATIC_3 |
| test_heuristic.rs:86:29:86:32 | 1u64 | semmle.label | 1u64 |
| test_heuristic.rs:87:22:87:31 | MY_CONST_5 | semmle.label | MY_CONST_5 |
| test_heuristic.rs:88:29:88:33 | ... + ... | semmle.label | ... + ... |
| test_heuristic.rs:89:22:89:31 | MY_CONST_6 | semmle.label | MY_CONST_6 |
| test_heuristic.rs:44:9:44:16 | const_iv [&ref] | semmle.label | const_iv [&ref] |
| test_heuristic.rs:44:30:44:38 | &... [&ref] | semmle.label | &... [&ref] |
| test_heuristic.rs:44:31:44:38 | [0u8; 16] | semmle.label | [0u8; 16] |
| test_heuristic.rs:45:41:45:48 | const_iv | semmle.label | const_iv |
| test_heuristic.rs:63:30:63:37 | "secret" | semmle.label | "secret" |
| test_heuristic.rs:64:19:64:27 | &... | semmle.label | &... |
| test_heuristic.rs:64:20:64:27 | [0u8; 16] | semmle.label | [0u8; 16] |
| test_heuristic.rs:65:30:65:38 | &... | semmle.label | &... |
| test_heuristic.rs:65:31:65:38 | [0u8; 16] | semmle.label | [0u8; 16] |
| test_heuristic.rs:67:22:67:22 | 0 | semmle.label | 0 |
| test_heuristic.rs:69:22:69:32 | ... + ... | semmle.label | ... + ... |
| test_heuristic.rs:69:32:69:32 | 1 | semmle.label | 1 |
| test_heuristic.rs:70:22:70:62 | ... ^ ... | semmle.label | ... ^ ... |
| test_heuristic.rs:70:23:70:35 | ... << ... | semmle.label | ... << ... |
| test_heuristic.rs:70:34:70:35 | 32 | semmle.label | 32 |
| test_heuristic.rs:70:41:70:61 | ... & ... | semmle.label | ... & ... |
| test_heuristic.rs:70:52:70:61 | 0xFFFFFFFF | semmle.label | 0xFFFFFFFF |
subpaths

View File

@@ -35,11 +35,6 @@ impl MyCryptor {
}
}
const MY_CONST_1: u64 = 0xFFFF; // $ Alert[rust/hard-coded-cryptographic-value]
const MY_CONST_2: u64 = std::env::consts::ARCH.len() as u64; // $ Alert[rust/hard-coded-cryptographic-value]
static MY_STATIC_3: u64 = 0xFFFF; // $ Alert[rust/hard-coded-cryptographic-value]
static MY_STATIC_4: u64 = std::env::consts::ARCH.len() as u64;
fn test(var_string: &str, var_data: &[u8;16], var_u64: u64) {
encrypt_with("plaintext", var_data, var_data);
@@ -71,32 +66,6 @@ fn test(var_string: &str, var_data: &[u8;16], var_u64: u64) {
mc2.set_salt_u64(0); // $ Alert[rust/hard-coded-cryptographic-value]
mc2.set_salt_u64(var_u64);
mc2.set_salt_u64(var_u64 + 1);
mc2.set_salt_u64((var_u64 << 32) ^ (var_u64 & 0xFFFFFFFF));
mc2.set_salt_u64(1 << 4); // $ Alert[rust/hard-coded-cryptographic-value]
mc2.set_salt_u64(u64::MAX); // $ Alert[rust/hard-coded-cryptographic-value]
mc2.set_salt_u64(u64::MAX / 4); // $ Alert[rust/hard-coded-cryptographic-value]
mc2.set_salt_u64(MY_CONST_1); // $ Sink[rust/hard-coded-cryptographic-value]
mc2.set_salt_u64(MY_CONST_2); // $ Sink[rust/hard-coded-cryptographic-value]
mc2.set_salt_u64(MY_STATIC_3); // $ Sink[rust/hard-coded-cryptographic-value]
mc2.set_salt_u64(MY_STATIC_4);
const MY_CONST_5: u64 = 1u64; // $ Alert[rust/hard-coded-cryptographic-value]
mc2.set_salt_u64(MY_CONST_5); // $ Sink[rust/hard-coded-cryptographic-value]
const MY_CONST_6: u64 = 2 + 3; // $ Alert[rust/hard-coded-cryptographic-value]
mc2.set_salt_u64(MY_CONST_6); // $ Sink[rust/hard-coded-cryptographic-value]
let mut key1 = "foo".to_string(); // $ MISSING: Alert[rust/hard-coded-cryptographic-value]
key1 += "bar"; // $ MISSING: Alert[rust/hard-coded-cryptographic-value]
let _ = MyCryptor::new(&key1);
let mut key2 = "foo".to_string();
key2 += var_string;
let _ = MyCryptor::new(&key2);
let mut key3 = var_string.to_string();
key3 += "bar";
let _ = MyCryptor::new(&key3);
mc2.set_salt_u64(var_u64 + 1); // $ SPURIOUS: Alert[rust/hard-coded-cryptographic-value]
mc2.set_salt_u64((var_u64 << 32) ^ (var_u64 & 0xFFFFFFFF)); // $ SPURIOUS: Alert[rust/hard-coded-cryptographic-value]
}

View File

@@ -54,24 +54,6 @@ signature module InputSig<LocationSig Location, DF::InputSig<Location> Lang> {
none()
}
/**
* A base class of calls that are candidates for flow summary modeling.
*/
class FlowSummaryCallBase {
string toString();
}
/** Gets a call that targets summarized callable `sc`. */
default FlowSummaryCallBase getASourceCall(SummarizedCallableBase sc) { none() }
/** Gets the callable corresponding to summarized callable `c`. */
default Lang::DataFlowCallable getSummarizedCallableAsDataFlowCallable(SummarizedCallableBase c) {
none()
}
/** Gets the enclosing callable of `call`. */
default Lang::DataFlowCallable getSourceCallEnclosingCallable(FlowSummaryCallBase call) { none() }
/** Gets the parameter position representing a callback itself, if any. */
default Lang::ArgumentPosition callbackSelfParameterPosition() { none() }
@@ -92,9 +74,6 @@ signature module InputSig<LocationSig Location, DF::InputSig<Location> Lang> {
result = getStandardReturnValueKind()
}
/** Gets the parameter position corresponding to a flow-summary return kind `rk`, if any. */
default Lang::ParameterPosition getFlowSummaryParameterPosition(Lang::ReturnKind rk) { none() }
/** Gets the textual representation of parameter position `pos` used in MaD. */
string encodeParameterPosition(Lang::ParameterPosition pos);
@@ -681,10 +660,6 @@ module Make<
s.length() = 1 and
s.head() instanceof TArgumentSummaryComponent
or
// ReturnValue.*
s.length() = 1 and
s.head() instanceof TReturnSummaryComponent
or
// Argument[n].ReturnValue.*
s.length() = 2 and
s.head() instanceof TReturnSummaryComponent and
@@ -1162,13 +1137,6 @@ module Make<
outputState(c, s) and s = SummaryComponentStack::argument(_)
}
private predicate relevantFlowSummaryPosition(SummarizedCallable c, ReturnKind rk) {
exists(SummaryComponentStack input |
summary(c, input, _, _, _) and
input = TSingletonSummaryComponentStack(TReturnSummaryComponent(rk))
)
}
pragma[nomagic]
private predicate sourceOutputStateEntry(
SourceElement source, SummaryComponentStack s, string kind, string model
@@ -1304,12 +1272,6 @@ module Make<
TSummaryParameterNode(SummarizedCallable c, ParameterPosition pos) {
summaryParameterNodeRange(c, pos)
} or
TSummaryReturnArgumentNode(FlowSummaryCallBase call, ReturnKind rk) {
exists(SummarizedCallable sc |
call = getASourceCall(sc) and
relevantFlowSummaryPosition(sc, rk)
)
} or
TSourceOutputNode(SourceElement source, SummaryNodeState state, string kind, string model) {
state.isSourceOutputState(source, _, kind, model)
} or
@@ -1359,40 +1321,6 @@ module Make<
override SinkElement getSinkElement() { none() }
}
private class SummaryReturnArgumentNode extends SummaryNode, TSummaryReturnArgumentNode {
private FlowSummaryCallBase call;
private ReturnKind rk;
SummaryReturnArgumentNode() { this = TSummaryReturnArgumentNode(call, rk) }
override string toString() { result = "[summary] value written to " + rk + " at " + call }
override SummarizedCallable getSummarizedCallable() { none() }
override SourceElement getSourceElement() { none() }
override SinkElement getSinkElement() { none() }
}
/**
* Gets the summary node that represents the argument node used to transfer
* flow into the caller when a value is written to the value returned by
* `call` with kind `rk`.
*/
SummaryNode summaryArgumentNode(FlowSummaryCallBase call, ReturnKind rk) {
result = TSummaryReturnArgumentNode(call, rk)
}
/** Gets the enclosing callable for summary node `sn`. */
DataFlowCallable getEnclosingCallable(SummaryNode sn) {
result = getSummarizedCallableAsDataFlowCallable(sn.getSummarizedCallable())
or
exists(FlowSummaryCallBase call |
sn = TSummaryReturnArgumentNode(call, _) and
result = getSourceCallEnclosingCallable(call)
)
}
class SourceOutputNode extends SummaryNode, TSourceOutputNode {
private SourceElement source_;
private SummaryNodeState state_;
@@ -1499,12 +1427,6 @@ module Make<
SummarizedCallable c, SummaryNodeState state, ParameterPosition pos
) {
state.isInputState(c, SummaryComponentStack::argument(pos))
or
exists(ReturnKind rk |
relevantFlowSummaryPosition(c, rk) and
state.isInputState(c, SummaryComponentStack::return(rk)) and
pos = getFlowSummaryParameterPosition(rk)
)
}
/**
@@ -1638,9 +1560,6 @@ module Make<
)
}
/** Holds if return kind `rk` is a relevant return kind for flow summary modeling. */
predicate relevantFlowSummaryPosition(ReturnKind rk) { relevantFlowSummaryPosition(_, rk) }
/**
* Holds if flow is allowed to pass from the parameter at position `pos` of `c`,
* to a return node, and back out to the parameter.
@@ -1817,15 +1736,9 @@ module Make<
}
signature module StepsInputSig {
/** Gets the summary node represented by data-flow node `n`, if any. */
SummaryNode getSummaryNode(Node n);
/** Gets a call that targets summarized callable `sc`. */
DataFlowCall getACall(SummarizedCallable sc);
/** Gets the out node of kind `rk` for `call`, if any. */
default Node getSourceOutNode(FlowSummaryCallBase call, ReturnKind rk) { none() }
/** Gets the enclosing callable of `source`. */
DataFlowCallable getSourceNodeEnclosingCallable(SourceBase source);
@@ -1852,7 +1765,7 @@ module Make<
* Holds if there is a local step from `pred` to `succ`, which is synthesized
* from a flow summary.
*/
private predicate summaryLocalStepImpl(
predicate summaryLocalStep(
SummaryNode pred, SummaryNode succ, boolean preservesValue, string model
) {
exists(
@@ -1898,24 +1811,9 @@ module Make<
)
}
/** Holds if there is a local step between data-flow nodes synthesized from a flow summary. */
predicate summaryLocalStep(Node pred, SummaryNode succ, boolean preservesValue, string model) {
exists(SummaryNode predSummary |
predSummary = StepsInput::getSummaryNode(pred) and
summaryLocalStepImpl(predSummary, succ, preservesValue, model)
)
or
exists(FlowSummaryCallBase summaryCall, ReturnKind rk, SummarizedCallable sc |
pred = StepsInput::getSourceOutNode(summaryCall, rk) and
summaryCall = getASourceCall(sc) and
summary(sc, SummaryComponentStack::return(rk), _, preservesValue, model) and
succ = TSummaryReturnArgumentNode(summaryCall, rk)
)
}
/** Holds if the value of `succ` is uniquely determined by the value of `pred`. */
predicate summaryLocalMustFlowStep(SummaryNode pred, SummaryNode succ) {
pred = unique(SummaryNode n1 | summaryLocalStepImpl(n1, succ, true, _))
pred = unique(SummaryNode n1 | summaryLocalStep(n1, succ, true, _))
}
/**
@@ -2037,7 +1935,7 @@ module Make<
or
exists(SummaryNode mid, boolean clearsOrExpectsMid |
paramReachesLocal(p, mid, clearsOrExpectsMid) and
summaryLocalStepImpl(mid, n, true, _) and
summaryLocalStep(mid, n, true, _) and
if
summaryClearsContent(n, _) or
summaryExpectsContent(n, _)
@@ -2095,7 +1993,7 @@ module Make<
*/
predicate summaryThroughStepValue(ArgNode arg, Node out, SummarizedCallable sc) {
exists(SummaryNode ret |
summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), ret, true, _)
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, true, _)
)
}
@@ -2108,7 +2006,7 @@ module Make<
*/
predicate summaryThroughStepTaint(ArgNode arg, Node out, SummarizedCallable sc) {
exists(SummaryNode ret |
summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), ret, false, _)
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, false, _)
)
}
@@ -2122,7 +2020,7 @@ module Make<
predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
exists(SummaryNode mid, SummaryNode ret |
summaryReadStep(summaryArgParamRetOut(arg, ret, out, sc), c, mid) and
summaryLocalStepImpl(mid, ret, _, _)
summaryLocalStep(mid, ret, _, _)
)
}
@@ -2135,7 +2033,7 @@ module Make<
*/
predicate summarySetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
exists(SummaryNode mid, SummaryNode ret |
summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), mid, _, _) and
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), mid, _, _) and
summaryStoreStep(mid, c, ret)
)
}
@@ -2851,11 +2749,9 @@ module Make<
key = "semmle.label" and val = n.toString()
}
private Node getNode(SummaryNode sn) { sn = StepsInput::getSummaryNode(result) }
private predicate edgesComponent(NodeOrCall a, NodeOrCall b, string value) {
exists(boolean preservesValue |
PrivateSteps::summaryLocalStep(getNode(a.asNode()), b.asNode(), preservesValue, _) and
PrivateSteps::summaryLocalStep(a.asNode(), b.asNode(), preservesValue, _) and
if preservesValue = true then value = "value" else value = "taint"
)
or

View File

@@ -1346,14 +1346,6 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
module MatchingWithEnvironment<MatchingWithEnvironmentInputSig Input> {
private import Input
pragma[nomagic]
private TypeParameter getDeclTypeParameter(Declaration decl, TypeArgumentPosition tapos) {
exists(TypeParameterPosition tppos |
result = decl.getTypeParameter(tppos) and
typeArgumentParameterPositionMatch(tapos, tppos)
)
}
/**
* Gets the type of the type argument at `path` in `a` that corresponds to
* the type parameter `tp` in `target`, if any.
@@ -1364,11 +1356,11 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
*/
bindingset[a, target]
pragma[inline_late]
Type getTypeArgument(Access a, Declaration target, TypeParameter tp, TypePath path) {
exists(TypeArgumentPosition tapos |
private Type getTypeArgument(Access a, Declaration target, TypeParameter tp, TypePath path) {
exists(TypeArgumentPosition tapos, TypeParameterPosition tppos |
result = a.getTypeArgument(tapos, path) and
tp = getDeclTypeParameter(target, tapos) and
not isPseudoType(result)
tp = target.getTypeParameter(tppos) and
typeArgumentParameterPositionMatch(tapos, tppos)
)
}
@@ -1534,35 +1526,42 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
private module AccessConstraint {
private predicate relevantAccessConstraint(
Access a, AccessEnvironment e, Declaration target, TypeParameter constrainedTp,
Access a, AccessEnvironment e, Declaration target, AccessPosition apos, TypePath path,
TypeMention constraint
) {
target = a.getTarget(e) and
typeParameterHasConstraint(target, constrainedTp, constraint)
typeParameterHasConstraint(target, apos, _, path, constraint)
}
private newtype TRelevantAccess =
MkRelevantAccess(Access a, AccessEnvironment e, TypeParameter constrainedTp) {
relevantAccessConstraint(a, e, _, constrainedTp, _)
MkRelevantAccess(Access a, AccessPosition apos, AccessEnvironment e, TypePath path) {
relevantAccessConstraint(a, e, _, apos, path, _)
}
/**
* If the access `a` for `apos`, environment `e`, and `path` has an inferred type
* which type inference requires to satisfy some constraint.
*/
private class RelevantAccess extends MkRelevantAccess {
Access a;
AccessPosition apos;
AccessEnvironment e;
TypeParameter constrainedTp;
TypePath path;
RelevantAccess() { this = MkRelevantAccess(a, e, constrainedTp) }
RelevantAccess() { this = MkRelevantAccess(a, apos, e, path) }
pragma[nomagic]
Type getTypeAt(TypePath path) { typeMatch(a, e, _, path, result, constrainedTp) }
Type getTypeAt(TypePath suffix) {
result = a.getInferredType(e, apos, path.appendInverse(suffix))
}
/** Gets the constraint that this relevant access should satisfy. */
TypeMention getConstraint(Declaration target) {
relevantAccessConstraint(a, e, target, constrainedTp, result)
relevantAccessConstraint(a, e, target, apos, path, result)
}
string toString() {
result = a.toString() + ", " + e.toString() + ", " + constrainedTp.toString()
result = a.toString() + ", " + apos.toString() + ", " + path.toString()
}
Location getLocation() { result = a.getLocation() }
@@ -1578,7 +1577,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
class TypeMatchingContext = Access;
TypeMatchingContext getTypeMatchingContext(RelevantAccess at) {
at = MkRelevantAccess(result, _, _)
at = MkRelevantAccess(result, _, _, _)
}
pragma[nomagic]
@@ -1592,32 +1591,41 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
SatisfiesTypeParameterConstraintInput>;
pragma[nomagic]
predicate argSatisfiesConstraintAtTypeParameter(
predicate satisfiesConstraintAtTypeParameter(
Access a, AccessEnvironment e, Declaration target, AccessPosition apos, TypePath prefix,
TypeMention constraint, TypePath pathToTypeParamInConstraint,
TypePath pathToTypeParamInSub
) {
exists(RelevantAccess ra, TypeParameter constrainedTp |
ra = MkRelevantAccess(a, e, constrainedTp) and
relevantAccessConstraint(a, e, target, constrainedTp, constraint) and
exists(RelevantAccess ra |
ra = MkRelevantAccess(a, apos, e, prefix) and
SatisfiesTypeParameterConstraint::satisfiesConstraintAtTypeParameter(ra, constraint,
pathToTypeParamInConstraint, pathToTypeParamInSub) and
exists(DeclarationPosition dpos |
accessDeclarationPositionMatch(apos, dpos) and
constrainedTp = target.getDeclaredType(dpos, prefix)
)
constraint = ra.getConstraint(target)
)
}
pragma[nomagic]
predicate satisfiesConstraint(
Access a, AccessEnvironment e, Declaration target, TypeParameter constrainedTp,
Access a, AccessEnvironment e, Declaration target, AccessPosition apos, TypePath prefix,
TypeMention constraint, TypePath path, Type t
) {
exists(RelevantAccess ra |
ra = MkRelevantAccess(a, e, constrainedTp) and
relevantAccessConstraint(a, e, target, constrainedTp, constraint) and
SatisfiesTypeParameterConstraint::satisfiesConstraint(ra, constraint, path, t)
ra = MkRelevantAccess(a, apos, e, prefix) and
SatisfiesTypeParameterConstraint::satisfiesConstraint(ra, constraint, path, t) and
constraint = ra.getConstraint(target)
)
}
pragma[nomagic]
predicate satisfiesConstraintThrough(
Access a, AccessEnvironment e, Declaration target, AccessPosition apos, TypePath prefix,
TypeAbstraction abs, TypeMention constraint, TypePath path, Type t
) {
exists(RelevantAccess ra |
ra = MkRelevantAccess(a, apos, e, prefix) and
SatisfiesTypeParameterConstraint::satisfiesConstraintThrough(ra, abs, constraint, path,
t) and
constraint = ra.getConstraint(target)
)
}
}
@@ -1636,44 +1644,51 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
}
/**
* Holds if the type parameter `constrainedTp` applies to `target` and the
* constraint `constraint` applies to `constrainedTp`.
* Holds if the type parameter `constrainedTp` occurs in the declared type of
* `target` at `apos` and `pathToConstrained`, and there is a constraint
* `constraint` on `constrainedTp`.
*/
pragma[nomagic]
private predicate typeParameterHasConstraint(
Declaration target, TypeParameter constrainedTp, TypeMention constraint
Declaration target, AccessPosition apos, TypeParameter constrainedTp,
TypePath pathToConstrained, TypeMention constraint
) {
constrainedTp = target.getTypeParameter(_) and
constraint = getATypeParameterConstraint(constrainedTp, target)
exists(DeclarationPosition dpos |
accessDeclarationPositionMatch(apos, dpos) and
constrainedTp = target.getTypeParameter(_) and
constrainedTp = target.getDeclaredType(dpos, pathToConstrained) and
constraint = getATypeParameterConstraint(constrainedTp, target)
)
}
/**
* Holds if the type parameter `constrainedTp` applies to `target`, the
* constraint `constraint` applies to `constrainedTp`, and type parameter
* `tp` occurs at `pathToTp` in `constraint`.
* Holds if the declared type of `target` contains a type parameter at
* `apos` and `pathToConstrained` that must satisfy `constraint` and `tp`
* occurs at `pathToTp` in `constraint`.
*
* For example, in
*
* ```csharp
* interface IFoo<A> { }
* T1 M<T1, T2>(T2 item) where T2 : IFoo<T1> { }
* ```
*
* with the method declaration being the target, we have the following
* - `constrainedTp = T2`,
* with the method declaration being the target and with `apos`
* corresponding to `item`, we have the following
* - `pathToConstrained = ""`,
* - `tp = T1`,
* - `constraint = IFoo`,
* - `tp = T1`, and
* - `pathToTp = "A"`.
*/
pragma[nomagic]
private predicate typeParameterConstraintHasTypeParameter(
Declaration target, TypeParameter constrainedTp, TypeMention constraint, TypePath pathToTp,
TypeParameter tp
Declaration target, AccessPosition apos, TypePath pathToConstrained, TypeMention constraint,
TypePath pathToTp, TypeParameter tp
) {
typeParameterHasConstraint(target, constrainedTp, constraint) and
tp = target.getTypeParameter(_) and
tp = constraint.getTypeAt(pathToTp) and
constrainedTp != tp
exists(TypeParameter constrainedTp |
typeParameterHasConstraint(target, apos, constrainedTp, pathToConstrained, constraint) and
tp = target.getTypeParameter(_) and
tp = constraint.getTypeAt(pathToTp) and
constrainedTp != tp
)
}
pragma[nomagic]
@@ -1681,9 +1696,9 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
Access a, AccessEnvironment e, Declaration target, TypePath path, Type t, TypeParameter tp
) {
not exists(getTypeArgument(a, target, tp, _)) and
exists(TypeMention constraint, TypeParameter constrainedTp, TypePath pathToTp |
typeParameterConstraintHasTypeParameter(target, constrainedTp, constraint, pathToTp, tp) and
AccessConstraint::satisfiesConstraint(a, e, target, constrainedTp, constraint,
exists(TypeMention constraint, AccessPosition apos, TypePath pathToTp, TypePath pathToTp2 |
typeParameterConstraintHasTypeParameter(target, apos, pathToTp2, constraint, pathToTp, tp) and
AccessConstraint::satisfiesConstraint(a, e, target, apos, pathToTp2, constraint,
pathToTp.appendInverse(path), t)
)
}
@@ -1766,7 +1781,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
Declaration target, TypePath prefix, TypeMention constraint,
TypePath pathToTypeParamInConstraint, TypePath pathToTypeParamInSub
|
AccessConstraint::argSatisfiesConstraintAtTypeParameter(a, e, target, apos, prefix,
AccessConstraint::satisfiesConstraintAtTypeParameter(a, e, target, apos, prefix,
constraint, pathToTypeParamInConstraint, pathToTypeParamInSub)
|
exists(TypePath suffix |
@@ -1832,12 +1847,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
*/
typeMatch(a, e, target, suffix, result, tp) and
exists(TypeParameter constrainedTp, DeclarationPosition dpos |
typeParameterConstraintHasTypeParameter(target, constrainedTp, constraint, pathToTp,
tp) and
accessDeclarationPositionMatch(apos, dpos) and
constrainedTp = target.getDeclaredType(dpos, _)
) and
typeParameterConstraintHasTypeParameter(target, apos, _, constraint, pathToTp, tp) and
pathToTp = pathToTypeParamInConstraint.appendInverse(mid) and
path = prefix.append(pathToTypeParamInSub.append(mid).append(suffix))
)

View File

@@ -305,7 +305,7 @@ private module Cached {
model = ""
or
// flow through a flow summary (extension of `SummaryModelCsv`)
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
}

View File

@@ -20,8 +20,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::SwiftDataFlow>
class SinkBase = Void;
class FlowSummaryCallBase = Void;
predicate callableFromSource(SummarizedCallableBase c) { c.hasBody() }
ArgumentPosition callbackSelfParameterPosition() { result instanceof ThisArgumentPosition }
@@ -115,10 +113,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::SwiftDataFlow>
private import Make<Location, DataFlowImplSpecific::SwiftDataFlow, Input> as Impl
private module StepsInput implements Impl::Private::StepsInputSig {
Impl::Private::SummaryNode getSummaryNode(Node n) {
result = n.(FlowSummaryNode).getSummaryNode()
}
DataFlowCall getACall(Public::SummarizedCallable sc) { result.asCall().getStaticTarget() = sc }
DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() }

View File

@@ -76,7 +76,7 @@ private module Cached {
model = ""
or
// flow through a flow summary (extension of `SummaryModelCsv`)
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
or
any(AdditionalTaintStep a).step(nodeFrom, nodeTo) and model = "AdditionalTaintStep"