Compare commits

..

8 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
57083e7f40 Load canonical-path DLL from CODEQL_EXTRACTOR_GO_ROOT, not CODEQL_DIST 2026-07-01 13:55:18 +00:00
copilot-swe-agent[bot]
f7f537631c Replace non-ASCII em-dash in NativeCanonicalizer.java comment 2026-07-01 13:40:08 +00:00
copilot-swe-agent[bot]
bfa81c30f4 Fix bazel formatting and non-windows build of canonicalize-dll 2026-07-01 13:23:21 +00:00
copilot-swe-agent[bot]
c807858312 Revert remaining go/ql/test changes 2026-07-01 13:12:12 +00:00
copilot-swe-agent[bot]
1a12cd68ec Revert integration-test changes 2026-07-01 13:07:24 +00:00
copilot-swe-agent[bot]
17cbc4990d Use std::mt19937 instead of std::rand for cache eviction
Replace std::rand() with std::mt19937 seeded by std::random_device for
less predictable cache eviction. Also use .first from emplace() instead
of structured binding with ignored second element.
2026-07-01 13:02:00 +00:00
copilot-swe-agent[bot]
77c962b4d9 Add shared canonicalize library and Go/Kotlin integrations
- Add shared/canonicalize/ C++ DLL that resolves Windows paths via
  GetFinalPathNameByHandleW with a full-path cache (matching C#'s
  CanonicalPathCache strategy).
- Add JNI interface (canonicalize_jni.cpp) for Kotlin/Java consumers.
- Add NativeCanonicalizer.java to kotlin-extractor for loading the DLL
  and exposing a resolve() method.
- Call NativeCanonicalizer.resolve() in FileUtil.tryMakeCanonical().
- Add go/extractor/canonicalize package (Windows + non-Windows impls).
- Use canonicalize.CanonicalizePath() in go extractor normalizedPath().
- Update Bazel build files for all new targets and deps.
2026-07-01 12:58:02 +00:00
copilot-swe-agent[bot]
1e33a81d6b Initial plan 2026-07-01 12:52:11 +00:00
76 changed files with 8162 additions and 8128 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

@@ -56,9 +56,19 @@ codeql_pkg_files(
prefix = "tools/{CODEQL_PLATFORM}",
)
codeql_pkg_files(
name = "canonicalize-dll",
srcs = select({
"@platforms//os:windows": ["//shared/canonicalize:pkg"],
"//conditions:default": [],
}),
prefix = "tools/{CODEQL_PLATFORM}",
)
codeql_pack(
name = "go",
srcs = [
":canonicalize-dll",
":extractor-pack-arch",
":resources",
"//go/codeql-tools",

View File

@@ -16,6 +16,7 @@ go_library(
importpath = "github.com/github/codeql-go/extractor",
visibility = ["//visibility:public"],
deps = [
"//go/extractor/canonicalize",
"//go/extractor/dbscheme",
"//go/extractor/diagnostics",
"//go/extractor/srcarchive",

11
go/extractor/canonicalize/BUILD.bazel generated Normal file
View File

@@ -0,0 +1,11 @@
load("@rules_go//go:def.bzl", "go_library")
go_library(
name = "canonicalize",
srcs = [
"canonicalize_other.go",
"canonicalize_windows.go",
],
importpath = "github.com/github/codeql-go/extractor/canonicalize",
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,5 @@
//go:build !windows
package canonicalize
func CanonicalizePath(path string) string { return path }

View File

@@ -0,0 +1,65 @@
//go:build windows
package canonicalize
import (
"os"
"path/filepath"
"syscall"
"unsafe"
)
var (
dll *syscall.DLL
procCanonicalize *syscall.Proc
procFree *syscall.Proc
available bool
)
func init() {
root := os.Getenv("CODEQL_EXTRACTOR_GO_ROOT")
if root == "" {
return
}
dllPath := filepath.Join(root, "tools", "win64", "codeql_canonical_path.dll")
d, err := syscall.LoadDLL(dllPath)
if err != nil {
return
}
p, err := d.FindProc("canonicalize_path_u8")
if err != nil {
return
}
f, _ := d.FindProc("canonicalize_free_u8")
dll = d
procCanonicalize = p
procFree = f
available = true
}
func CanonicalizePath(path string) string {
if !available {
return path
}
pathBytes := append([]byte(path), 0)
ret, _, _ := procCanonicalize.Call(uintptr(unsafe.Pointer(&pathBytes[0])))
if ret == 0 {
return path
}
result := bytePtrToString((*byte)(unsafe.Pointer(ret)))
if procFree != nil {
procFree.Call(ret)
}
return result
}
func bytePtrToString(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

@@ -22,6 +22,7 @@ import (
"sync"
"time"
"github.com/github/codeql-go/extractor/canonicalize"
"github.com/github/codeql-go/extractor/dbscheme"
"github.com/github/codeql-go/extractor/diagnostics"
"github.com/github/codeql-go/extractor/srcarchive"
@@ -766,7 +767,7 @@ func normalizedPath(ast *ast.File, fset *token.FileSet) string {
if err != nil {
return file
}
return path
return canonicalize.CanonicalizePath(path)
}
// extractFile extracts AST information for the given file

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,11 +1242,11 @@ public class FileUtil
public static File tryMakeCanonical (File f)
{
try {
return f.getCanonicalFile();
return NativeCanonicalizer.resolve(f.getCanonicalFile());
}
catch (IOException ignored) {
Exceptions.ignore(ignored, "Can't log error: Could be too verbose.");
return new File(simplifyPath(f));
return NativeCanonicalizer.resolve(new File(simplifyPath(f)));
}
}

View File

@@ -0,0 +1,41 @@
package com.semmle.util.files;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
public class NativeCanonicalizer {
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("codeql_canonical_path.dll").toAbsolutePath();
System.load(library.toString());
loaded = true;
} catch (RuntimeException | UnsatisfiedLinkError ignored) {
}
}
}
available = loaded;
}
private NativeCanonicalizer() {}
// UTF-16 JNI interface - no encoding conversion
private static native String nativeCanonicalizePath(String path);
public static File resolve(File path) {
if (!available) return path;
String result = nativeCanonicalizePath(path.getAbsolutePath());
return result != null ? new File(result) : path;
}
public static boolean isAvailable() {
return available;
}
}

View File

@@ -1,10 +1,4 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["org.apache.hc.client5.http.protocol", "RedirectLocations", True, "add", "(URI)", "", "Argument[0]", "Argument[this].Element", "value", "hq-manual"]
- addsTo:
pack: codeql/java-all
extensible: neutralModel

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["org.apache.hc.client5.http.protocol", "RedirectLocations", True, "add", "(URI)", "", "Argument[0]", "Argument[this].Element", "value", "hq-manual"]

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)
}
@@ -1138,9 +1138,7 @@ predicate clearsContent(Node n, ContentSet cs) {
* Holds if the value that is being tracked is expected to be stored inside content `c`
* at node `n`.
*/
predicate expectsContent(Node n, ContentSet c) {
FlowSummaryImpl::Private::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
}
predicate expectsContent(Node n, ContentSet c) { none() }
/**
* Holds if values stored inside attribute `c` are cleared at node `n`.

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() }
@@ -93,8 +91,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::PythonDataFlow>
cs.isAnyTupleOrDictionaryElement() and result = "AnyTupleOrDictionaryElement" and arg = ""
}
string encodeWithContent(ContentSet c, string arg) { result = "With" + encodeContent(c, arg) }
bindingset[token]
ParameterPosition decodeUnknownParameterPosition(AccessPath::AccessPathTokenBase token) {
// needed to support `Argument[x..y]` ranges
@@ -113,10 +109,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

@@ -4199,9 +4199,11 @@ module StdlibPrivate {
// The positional argument contains a mapping.
// TODO: these values can be overwritten by keyword arguments
// - dict mapping
input = "Argument[0].WithAnyDictionaryElement" and
output = "ReturnValue" and
preservesValue = true
exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
input = "Argument[0].DictionaryElement[" + key + "]" and
output = "ReturnValue.DictionaryElement[" + key + "]" and
preservesValue = true
)
or
// - list-of-pairs mapping
input = "Argument[0].ListElement.TupleElement[1]" and
@@ -4238,7 +4240,9 @@ module StdlibPrivate {
or
input = "Argument[0].SetElement"
or
input = "Argument[0].AnyTupleElement"
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
// Element content is mutated into list element content
@@ -4262,9 +4266,11 @@ module StdlibPrivate {
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0].WithAnyTupleElement" and
output = "ReturnValue" and
preservesValue = true
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]" and
output = "ReturnValue.TupleElement[" + i.toString() + "]" and
preservesValue = true
)
or
input = "Argument[0].ListElement" and
output = "ReturnValue" and
@@ -4288,7 +4294,9 @@ module StdlibPrivate {
or
input = "Argument[0].SetElement"
or
input = "Argument[0].AnyTupleElement"
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
output = "ReturnValue.SetElement" and
@@ -4334,7 +4342,9 @@ module StdlibPrivate {
or
input = "Argument[0].SetElement"
or
input = "Argument[0].AnyTupleElement"
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
output = "ReturnValue.ListElement" and
@@ -4362,7 +4372,9 @@ module StdlibPrivate {
or
content = "SetElement"
or
content = "AnyTupleElement"
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
content = "TupleElement[" + i.toString() + "]"
)
|
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
input = "Argument[0]." + content and
@@ -4392,7 +4404,9 @@ module StdlibPrivate {
or
input = "Argument[0].SetElement"
or
input = "Argument[0].AnyTupleElement"
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
output = "ReturnValue.ListElement" and
@@ -4420,7 +4434,9 @@ module StdlibPrivate {
or
input = "Argument[0].SetElement"
or
input = "Argument[0].AnyTupleElement"
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
output = "ReturnValue" and
@@ -4452,7 +4468,9 @@ module StdlibPrivate {
// We reduce generality slightly by not tracking tuple contents on list arguments beyond the first, for performance.
// TODO: Once we have TupleElementAny, this generality can be increased.
i = 0 and
input = "Argument[1].AnyTupleElement"
exists(DataFlow::TupleElementContent tc, int j | j = tc.getIndex() |
input = "Argument[1].TupleElement[" + j.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
output = "Argument[0].Parameter[" + i.toString() + "]" and
@@ -4481,7 +4499,9 @@ module StdlibPrivate {
or
input = "Argument[1].SetElement"
or
input = "Argument[1].AnyTupleElement"
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[1].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
(output = "Argument[0].Parameter[0]" or output = "ReturnValue.ListElement") and
@@ -4505,7 +4525,9 @@ module StdlibPrivate {
or
input = "Argument[0].SetElement"
or
input = "Argument[0].AnyTupleElement"
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
output = "ReturnValue.ListElement.TupleElement[1]" and
@@ -4530,7 +4552,12 @@ module StdlibPrivate {
or
input = "Argument[" + i.toString() + "].SetElement"
or
input = "Argument[" + i.toString() + "].AnyTupleElement"
// We reduce generality slightly by not tracking tuple contents on arguments beyond the first two, for performance.
// TODO: Once we have TupleElementAny, this generality can be increased.
i in [0 .. 1] and
exists(DataFlow::TupleElementContent tc, int j | j = tc.getIndex() |
input = "Argument[" + i.toString() + "].TupleElement[" + j.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
output = "ReturnValue.ListElement.TupleElement[" + i.toString() + "]" and
@@ -4553,6 +4580,12 @@ module StdlibPrivate {
override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
exists(DataFlow::Content c |
input = "Argument[self]." + c.getMaDRepresentation() and
output = "ReturnValue." + c.getMaDRepresentation() and
preservesValue = true
)
or
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = true
@@ -4708,10 +4741,12 @@ module StdlibPrivate {
override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].AnyDictionaryElement" and
output = "ReturnValue.TupleElement[1]" and
preservesValue = true
// TODO: put `key` into "ReturnValue.TupleElement[0]"
exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
input = "Argument[self].DictionaryElement[" + key + "]" and
output = "ReturnValue.TupleElement[1]" and
preservesValue = true
// TODO: put `key` into "ReturnValue.TupleElement[0]"
)
}
}
@@ -4790,9 +4825,11 @@ module StdlibPrivate {
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].AnyDictionaryElement" and
output = "ReturnValue.ListElement" and
preservesValue = true
exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
input = "Argument[self].DictionaryElement[" + key + "]" and
output = "ReturnValue.ListElement" and
preservesValue = true
)
or
input = "Argument[self]" and
output = "ReturnValue" and
@@ -4839,9 +4876,11 @@ module StdlibPrivate {
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].AnyDictionaryElement" and
output = "ReturnValue.ListElement.TupleElement[1]" and
preservesValue = true
exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
input = "Argument[self].DictionaryElement[" + key + "]" and
output = "ReturnValue.ListElement.TupleElement[1]" and
preservesValue = true
)
or
// TODO: Add the keys to output list
input = "Argument[self]" and

View File

@@ -589,11 +589,11 @@ def test_zip_tuple():
SINK(z[0][0]) # $ flow="SOURCE, l:-7 -> z[0][0]"
SINK(z[0][1]) # $ flow="SOURCE, l:-7 -> z[0][1]"
SINK_F(z[0][2]) # $ SPURIOUS: flow="SOURCE, l:-7 -> z[0][2]"
SINK_F(z[0][2])
SINK_F(z[0][3])
SINK(z[1][0]) # $ flow="SOURCE, l:-11 -> z[1][0]"
SINK_F(z[1][1]) # $ SPURIOUS: flow="SOURCE, l:-11 -> z[1][1]"
SINK(z[1][2]) # $ flow="SOURCE, l:-11 -> z[1][2]"
SINK(z[1][2]) # $ MISSING: flow="SOURCE, l:-11 -> z[1][2]" # Tuple contents are not tracked beyond the first two arguments for performance.
SINK_F(z[1][3])
@expects(4)

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

@@ -362,7 +362,7 @@ def test_load_in_bulk():
# see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#in-bulk
d = TestLoad.objects.in_bulk([1])
for val in d.values():
SINK(val.text) # $ flow="SOURCE, l:-65 -> val.text"
SINK(val.text) # $ MISSING: flow
SINK(d[1].text) # $ flow="SOURCE, l:-66 -> d[1].text"

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

@@ -231,11 +231,11 @@ edges
| hash_extensions.rb:122:5:122:10 | single : Array [element 0] | hash_extensions.rb:125:10:125:15 | single : Array [element 0] | provenance | |
| hash_extensions.rb:122:14:122:26 | call to [] : Array [element 0] | hash_extensions.rb:122:5:122:10 | single : Array [element 0] | provenance | |
| hash_extensions.rb:122:15:122:25 | call to source | hash_extensions.rb:122:14:122:26 | call to [] : Array [element 0] | provenance | |
| hash_extensions.rb:123:5:123:9 | multi : Array [element 0] | hash_extensions.rb:127:10:127:14 | multi : Array [element 0] | provenance | |
| hash_extensions.rb:123:5:123:9 | multi : Array [element 0] | hash_extensions.rb:126:10:126:14 | multi : Array [element 0] | provenance | |
| hash_extensions.rb:123:13:123:38 | call to [] : Array [element 0] | hash_extensions.rb:123:5:123:9 | multi : Array [element 0] | provenance | |
| hash_extensions.rb:123:14:123:24 | call to source | hash_extensions.rb:123:13:123:38 | call to [] : Array [element 0] | provenance | |
| hash_extensions.rb:125:10:125:15 | single : Array [element 0] | hash_extensions.rb:125:10:125:20 | call to sole | provenance | |
| hash_extensions.rb:127:10:127:14 | multi : Array [element 0] | hash_extensions.rb:127:10:127:19 | call to sole | provenance | |
| hash_extensions.rb:126:10:126:14 | multi : Array [element 0] | hash_extensions.rb:126:10:126:19 | call to sole | provenance | |
nodes
| active_support.rb:180:5:180:5 | x : Array [element 0] | semmle.label | x : Array [element 0] |
| active_support.rb:180:9:180:18 | call to [] : Array [element 0] | semmle.label | call to [] : Array [element 0] |
@@ -493,10 +493,11 @@ nodes
| hash_extensions.rb:123:14:123:24 | call to source | semmle.label | call to source |
| hash_extensions.rb:125:10:125:15 | single : Array [element 0] | semmle.label | single : Array [element 0] |
| hash_extensions.rb:125:10:125:20 | call to sole | semmle.label | call to sole |
| hash_extensions.rb:127:10:127:14 | multi : Array [element 0] | semmle.label | multi : Array [element 0] |
| hash_extensions.rb:127:10:127:19 | call to sole | semmle.label | call to sole |
| hash_extensions.rb:126:10:126:14 | multi : Array [element 0] | semmle.label | multi : Array [element 0] |
| hash_extensions.rb:126:10:126:19 | call to sole | semmle.label | call to sole |
subpaths
testFailures
| hash_extensions.rb:126:10:126:19 | call to sole | Unexpected result: hasValueFlow=b |
#select
| active_support.rb:182:10:182:13 | ...[...] | active_support.rb:180:10:180:17 | call to source | active_support.rb:182:10:182:13 | ...[...] | $@ | active_support.rb:180:10:180:17 | call to source | call to source |
| active_support.rb:188:10:188:13 | ...[...] | active_support.rb:186:10:186:18 | call to source | active_support.rb:188:10:188:13 | ...[...] | $@ | active_support.rb:186:10:186:18 | call to source | call to source |
@@ -557,4 +558,4 @@ testFailures
| hash_extensions.rb:115:10:115:39 | ...[...] | hash_extensions.rb:110:21:110:31 | call to source | hash_extensions.rb:115:10:115:39 | ...[...] | $@ | hash_extensions.rb:110:21:110:31 | call to source | call to source |
| hash_extensions.rb:115:10:115:39 | ...[...] | hash_extensions.rb:110:65:110:75 | call to source | hash_extensions.rb:115:10:115:39 | ...[...] | $@ | hash_extensions.rb:110:65:110:75 | call to source | call to source |
| hash_extensions.rb:125:10:125:20 | call to sole | hash_extensions.rb:122:15:122:25 | call to source | hash_extensions.rb:125:10:125:20 | call to sole | $@ | hash_extensions.rb:122:15:122:25 | call to source | call to source |
| hash_extensions.rb:127:10:127:19 | call to sole | hash_extensions.rb:123:14:123:24 | call to source | hash_extensions.rb:127:10:127:19 | call to sole | $@ | hash_extensions.rb:123:14:123:24 | call to source | call to source |
| hash_extensions.rb:126:10:126:19 | call to sole | hash_extensions.rb:123:14:123:24 | call to source | hash_extensions.rb:126:10:126:19 | call to sole | $@ | hash_extensions.rb:123:14:123:24 | call to source | call to source |

View File

@@ -123,8 +123,7 @@ def m_sole
multi = [source("b"), source("c")]
sink(empty.sole)
sink(single.sole) # $ hasValueFlow=a
# TODO: model that 'sole' does not return if the receiver has multiple elements
sink(multi.sole) # $ SPURIOUS: hasValueFlow=b
sink(multi.sole) # TODO: model that 'sole' does not return if the receiver has multiple elements
end
m_sole()

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

@@ -0,0 +1,35 @@
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files")
cc_binary(
name = "codeql_canonical_path.dll",
srcs = [
"canonicalize.cpp",
"canonicalize.h",
"canonicalize_jni.cpp",
],
defines = ["CODEQL_CANONICALIZE_EXPORTS"],
linkopts = ["-lkernel32"],
linkshared = True,
target_compatible_with = ["@platforms//os:windows"],
visibility = ["//visibility:public"],
deps = ["@rules_java//toolchains:jni"],
)
cc_library(
name = "canonicalize",
srcs = ["canonicalize.cpp"],
hdrs = ["canonicalize.h"],
defines = ["CODEQL_CANONICALIZE_EXPORTS"],
linkopts = ["-lkernel32"],
target_compatible_with = ["@platforms//os:windows"],
visibility = ["//visibility:public"],
)
pkg_files(
name = "pkg",
srcs = [":codeql_canonical_path.dll"],
attributes = pkg_attributes(mode = "0755"),
target_compatible_with = ["@platforms//os:windows"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,165 @@
#ifdef _WIN32
#include "canonicalize.h"
#include <windows.h>
#include <string>
#include <unordered_map>
#include <shared_mutex>
#include <random>
namespace {
class PathCache {
public:
static PathCache& instance() {
static PathCache cache;
return cache;
}
const wchar_t* canonicalize(const wchar_t* path) {
std::wstring key(path);
// Fast path: shared (read) lock for cache hit
{
std::shared_lock lock(mutex_);
auto it = cache_.find(key);
if (it != cache_.end()) {
return _wcsdup(it->second.c_str());
}
}
// Slow path: resolve and insert under exclusive lock
std::wstring resolved = resolve(path);
if (resolved.empty()) return nullptr;
std::unique_lock lock(mutex_);
// Check again under exclusive lock (another thread may have inserted)
auto it = cache_.find(key);
if (it != cache_.end()) {
return _wcsdup(it->second.c_str());
}
// Evict a random entry if at capacity (matches C# strategy)
if (cache_.size() >= max_capacity_) {
std::uniform_int_distribution<size_t> dist(0, cache_.size() - 1);
auto evict = cache_.begin();
std::advance(evict, dist(rng_));
cache_.erase(evict);
}
auto inserted = cache_.emplace(std::move(key), std::move(resolved)).first;
return _wcsdup(inserted->second.c_str());
}
private:
PathCache() = default;
static constexpr size_t max_capacity_ = 4096;
std::unordered_map<std::wstring, std::wstring> cache_;
std::shared_mutex mutex_;
std::mt19937 rng_{std::random_device{}()};
static std::wstring resolve(const wchar_t* path) {
HANDLE h = CreateFileW(
path,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
nullptr);
if (h == INVALID_HANDLE_VALUE) {
return resolve_nonexistent(path);
}
std::wstring result = get_final_path(h);
CloseHandle(h);
if (result.empty()) return {};
return strip_prefix(result);
}
static std::wstring get_final_path(HANDLE h) {
wchar_t buf[MAX_PATH];
DWORD len = GetFinalPathNameByHandleW(h, buf, MAX_PATH, FILE_NAME_NORMALIZED);
if (len > 0 && len < MAX_PATH) {
return std::wstring(buf, len);
}
if (len >= MAX_PATH) {
std::wstring big(len + 1, L'\0');
len = GetFinalPathNameByHandleW(h, big.data(), len + 1, FILE_NAME_NORMALIZED);
if (len > 0) return std::wstring(big.data(), len);
}
return {};
}
static std::wstring strip_prefix(const std::wstring& path) {
constexpr std::wstring_view unc_prefix = L"\\\\?\\UNC\\";
constexpr std::wstring_view lp_prefix = L"\\\\?\\";
if (path.starts_with(unc_prefix)) {
return L"\\" + path.substr(unc_prefix.size() - 1);
}
if (path.starts_with(lp_prefix)) {
return std::wstring(path.substr(lp_prefix.size()));
}
return path;
}
// For non-existent files: canonicalize parent, append filename
// (matches C#'s ConstructCanonicalPath)
static std::wstring resolve_nonexistent(const wchar_t* path) {
std::wstring spath(path);
auto sep = spath.find_last_of(L"\\/");
if (sep == std::wstring::npos) return {};
std::wstring parent = spath.substr(0, sep);
std::wstring name = spath.substr(sep + 1);
std::wstring canonical_parent = resolve(parent.c_str());
if (canonical_parent.empty()) return {};
return canonical_parent + L"\\" + name;
}
};
} // namespace
extern "C" {
CODEQL_API const wchar_t* canonicalize_path_w(const wchar_t* path) {
if (!path || !*path) return nullptr;
return PathCache::instance().canonicalize(path);
}
CODEQL_API void canonicalize_free_w(const wchar_t* path) {
free(const_cast<wchar_t*>(path));
}
CODEQL_API const char* canonicalize_path_u8(const char* path) {
if (!path || !*path) return nullptr;
int wlen = MultiByteToWideChar(CP_UTF8, 0, path, -1, nullptr, 0);
if (wlen <= 0) return nullptr;
std::wstring wpath(wlen - 1, L'\0');
MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath.data(), wlen);
const wchar_t* wresult = PathCache::instance().canonicalize(wpath.c_str());
if (!wresult) return nullptr;
int ulen = WideCharToMultiByte(CP_UTF8, 0, wresult, -1, nullptr, 0, nullptr, nullptr);
if (ulen <= 0) { free(const_cast<wchar_t*>(wresult)); return nullptr; }
char* result = static_cast<char*>(malloc(ulen));
WideCharToMultiByte(CP_UTF8, 0, wresult, -1, result, ulen, nullptr, nullptr);
free(const_cast<wchar_t*>(wresult));
return result;
}
CODEQL_API void canonicalize_free_u8(const char* path) {
free(const_cast<char*>(path));
}
} // extern "C"
#endif

View File

@@ -0,0 +1,31 @@
#ifndef CODEQL_CANONICALIZE_H
#define CODEQL_CANONICALIZE_H
#ifdef _WIN32
#ifdef CODEQL_CANONICALIZE_EXPORTS
#define CODEQL_API __declspec(dllexport)
#else
#define CODEQL_API __declspec(dllimport)
#endif
#include <wchar.h>
#ifdef __cplusplus
extern "C" {
#endif
// UTF-16 interface (for JNI / Java / Kotlin)
CODEQL_API const wchar_t* canonicalize_path_w(const wchar_t* path);
CODEQL_API void canonicalize_free_w(const wchar_t* path);
// UTF-8 interface (for Go)
CODEQL_API const char* canonicalize_path_u8(const char* path);
CODEQL_API void canonicalize_free_u8(const char* path);
#ifdef __cplusplus
}
#endif
#endif // _WIN32
#endif // CODEQL_CANONICALIZE_H

View File

@@ -0,0 +1,25 @@
#ifdef _WIN32
#include <jni.h>
#include "canonicalize.h"
extern "C" {
JNIEXPORT jstring JNICALL
Java_com_semmle_util_files_NativeCanonicalizer_nativeCanonicalizePath(
JNIEnv *env, jclass cls, jstring jpath) {
const jchar* path = env->GetStringChars(jpath, nullptr);
const wchar_t* result = canonicalize_path_w(reinterpret_cast<const wchar_t*>(path));
env->ReleaseStringChars(jpath, path);
if (result == nullptr) return nullptr;
jstring jresult = env->NewString(
reinterpret_cast<const jchar*>(result),
static_cast<jsize>(wcslen(result)));
canonicalize_free_w(result);
return jresult;
}
} // extern "C"
#endif

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"