diff --git a/config/identical-files.json b/config/identical-files.json index 579a22379e84..b066c443d9fd 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -234,12 +234,14 @@ "CryptoAlgorithms Python/JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll", "python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll", - "ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll" + "ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll", + "rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll" ], "CryptoAlgorithmNames Python/JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll", "python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll", - "ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll" + "ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll", + "rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll" ], "SensitiveDataHeuristics Python/JS": [ "javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll", @@ -254,7 +256,8 @@ "Concepts Python/Ruby/JS": [ "python/ql/lib/semmle/python/internal/ConceptsShared.qll", "ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll", - "javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll" + "javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll", + "rust/ql/lib/codeql/rust/internal/ConceptsShared.qll" ], "ApiGraphModels": [ "javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll", diff --git a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll index cc5a8d6c3355..7a6307898ef5 100644 --- a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll @@ -954,9 +954,18 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) expr.(C11GenericExpr).getAssociationExpr(n) = ele and pred = "getAssociationExpr(" + n + ")" ) or - expr.(Call).getQualifier() = ele and pred = "getQualifier()" - or - exists(int n | expr.(Call).getArgument(n) = ele and pred = "getArgument(" + n.toString() + ")") + // OverloadedArrayExpr::getArrayBase/0 also considers qualifiers, and is already handled below. + not expr.(OverloadedArrayExpr).getArrayBase() = expr.(Call).getQualifier() and + expr.(Call).getQualifier() = ele and + pred = "getQualifier()" + or + // OverloadedArrayExpr::getArrayBase/0 and OverloadedArrayExpr::getArrayOffset/0 also consider arguments, and are already handled below. + exists(int n, Expr arg | expr.(Call).getArgument(n) = arg | + not expr.(OverloadedArrayExpr).getArrayBase() = arg and + not expr.(OverloadedArrayExpr).getArrayOffset() = arg and + arg = ele and + pred = "getArgument(" + n.toString() + ")" + ) or expr.(ExprCall).getExpr() = ele and pred = "getExpr()" or @@ -964,7 +973,7 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) or expr.(OverloadedArrayExpr).getArrayOffset() = ele and pred = "getArrayOffset()" or - // OverloadedPointerDereferenceExpr::getExpr/0 also considers qualifiers, which are already handled above for all Call classes. + // OverloadedPointerDereferenceExpr::getExpr/0 also considers qualifiers, and is already handled above for all Call classes. not expr.(OverloadedPointerDereferenceExpr).getQualifier() = expr.(OverloadedPointerDereferenceExpr).getExpr() and expr.(OverloadedPointerDereferenceExpr).getExpr() = ele and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll index 7fd66ba84414..41e1a4c3082d 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll @@ -422,16 +422,22 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { * has the given `value`. */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { - exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | + exists(IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and succBlock = succ.getBlock() and - predBlock.getSuccessor(kind) = succBlock and ( - ( - key = "semmle.label" and - if predBlock.getBackEdgeSuccessor(kind) = succBlock - then value = kind.toString() + " (back edge)" - else value = kind.toString() + key = "semmle.label" and + exists(string kinds | + kinds = + strictconcat(EdgeKind k | + predBlock.getSuccessor(k) = succBlock + | + k.toString(), "|" order by k.toString() + ) + | + if predBlock.getBackEdgeSuccessor(_) = succBlock + then value = kinds + " (back edge)" + else value = kinds ) or key = "semmle.order" and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/PrintIR.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/PrintIR.qll index 7fd66ba84414..41e1a4c3082d 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/PrintIR.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/PrintIR.qll @@ -422,16 +422,22 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { * has the given `value`. */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { - exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | + exists(IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and succBlock = succ.getBlock() and - predBlock.getSuccessor(kind) = succBlock and ( - ( - key = "semmle.label" and - if predBlock.getBackEdgeSuccessor(kind) = succBlock - then value = kind.toString() + " (back edge)" - else value = kind.toString() + key = "semmle.label" and + exists(string kinds | + kinds = + strictconcat(EdgeKind k | + predBlock.getSuccessor(k) = succBlock + | + k.toString(), "|" order by k.toString() + ) + | + if predBlock.getBackEdgeSuccessor(_) = succBlock + then value = kinds + " (back edge)" + else value = kinds ) or key = "semmle.order" and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll index 7fd66ba84414..41e1a4c3082d 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll @@ -422,16 +422,22 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { * has the given `value`. */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { - exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | + exists(IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and succBlock = succ.getBlock() and - predBlock.getSuccessor(kind) = succBlock and ( - ( - key = "semmle.label" and - if predBlock.getBackEdgeSuccessor(kind) = succBlock - then value = kind.toString() + " (back edge)" - else value = kind.toString() + key = "semmle.label" and + exists(string kinds | + kinds = + strictconcat(EdgeKind k | + predBlock.getSuccessor(k) = succBlock + | + k.toString(), "|" order by k.toString() + ) + | + if predBlock.getBackEdgeSuccessor(_) = succBlock + then value = kinds + " (back edge)" + else value = kinds ) or key = "semmle.order" and diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index d4f9c4f96c61..ea242065ac17 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -24086,6 +24086,38 @@ ir.cpp: # 2717| ValueCategory = prvalue # 2717| getThen(): [BlockStmt] { ... } # 2718| getStmt(16): [ReturnStmt] return ... +# 2720| [CopyAssignmentOperator] WithBracketOperator& WithBracketOperator::operator=(WithBracketOperator const&) +# 2720| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [LValueReferenceType] const WithBracketOperator & +# 2720| [MoveAssignmentOperator] WithBracketOperator& WithBracketOperator::operator=(WithBracketOperator&&) +# 2720| : +#-----| getParameter(0): [Parameter] (unnamed parameter 0) +#-----| Type = [RValueReferenceType] WithBracketOperator && +# 2721| [ConstMemberFunction] char const& WithBracketOperator::operator[](int) const +# 2721| : +# 2721| getParameter(0): [Parameter] pos +# 2721| Type = [IntType] int +# 2724| [TopLevelFunction] char UseBracketOperator(WithBracketOperator const, int) +# 2724| : +# 2724| getParameter(0): [Parameter] x +# 2724| Type = [SpecifiedType] const WithBracketOperator +# 2724| getParameter(1): [Parameter] i +# 2724| Type = [IntType] int +# 2724| getEntryPoint(): [BlockStmt] { ... } +# 2725| getStmt(0): [ReturnStmt] return ... +# 2725| getExpr(): [OverloadedArrayExpr] call to operator[] +# 2725| Type = [LValueReferenceType] const char & +# 2725| ValueCategory = prvalue +# 2725| getArrayBase(): [VariableAccess] x +# 2725| Type = [SpecifiedType] const WithBracketOperator +# 2725| ValueCategory = lvalue +# 2725| getArrayOffset(): [VariableAccess] i +# 2725| Type = [IntType] int +# 2725| ValueCategory = prvalue(load) +# 2725| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference) +# 2725| Type = [PlainCharType] char +# 2725| ValueCategory = prvalue(load) many-defs-per-use.cpp: # 34| [TopLevelFunction] void many_defs_per_use() # 34| : diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected index 224ac9a0ed9b..4f340042cb9a 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -19713,6 +19713,33 @@ ir.cpp: # 2698| v2698_10(void) = AliasedUse : m2698_3 # 2698| v2698_11(void) = ExitFunction : +# 2724| char UseBracketOperator(WithBracketOperator const, int) +# 2724| Block 0 +# 2724| v2724_1(void) = EnterFunction : +# 2724| m2724_2(unknown) = AliasedDefinition : +# 2724| m2724_3(unknown) = InitializeNonLocal : +# 2724| m2724_4(unknown) = Chi : total:m2724_2, partial:m2724_3 +# 2724| r2724_5(glval) = VariableAddress[x] : +# 2724| m2724_6(WithBracketOperator) = InitializeParameter[x] : &:r2724_5 +# 2724| m2724_7(unknown) = Chi : total:m2724_4, partial:m2724_6 +# 2724| r2724_8(glval) = VariableAddress[i] : +# 2724| m2724_9(int) = InitializeParameter[i] : &:r2724_8 +# 2725| r2725_1(glval) = VariableAddress[#return] : +# 2725| r2725_2(glval) = VariableAddress[x] : +# 2725| r2725_3(glval) = FunctionAddress[operator[]] : +# 2725| r2725_4(glval) = VariableAddress[i] : +# 2725| r2725_5(int) = Load[i] : &:r2725_4, m2724_9 +# 2725| r2725_6(char &) = Call[operator[]] : func:r2725_3, this:r2725_2, 0:r2725_5 +# 2725| m2725_7(unknown) = ^CallSideEffect : ~m2724_7 +# 2725| m2725_8(unknown) = Chi : total:m2724_7, partial:m2725_7 +# 2725| v2725_9(void) = ^IndirectReadSideEffect[-1] : &:r2725_2, ~m2725_8 +# 2725| r2725_10(char) = Load[?] : &:r2725_6, ~m2725_8 +# 2725| m2725_11(char) = Store[#return] : &:r2725_1, r2725_10 +# 2724| r2724_10(glval) = VariableAddress[#return] : +# 2724| v2724_11(void) = ReturnValue : &:r2724_10, m2725_11 +# 2724| v2724_12(void) = AliasedUse : ~m2725_8 +# 2724| v2724_13(void) = ExitFunction : + many-defs-per-use.cpp: # 34| void many_defs_per_use() # 34| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index bb4698ea7e23..67db690dc54b 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -2717,4 +2717,12 @@ void branch_on_integral_in_cpp(int x1, int x2) { if(!x_1_and_2) {} } +struct WithBracketOperator { + const char& operator[](int pos) const; +}; + +char UseBracketOperator(const WithBracketOperator x, int i) { + return x[i]; +} + // semmle-extractor-options: -std=c++20 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 8600049dd225..31faa22d9fcd 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18031,6 +18031,30 @@ ir.cpp: # 2698| v2698_9(void) = AliasedUse : ~m? # 2698| v2698_10(void) = ExitFunction : +# 2724| char UseBracketOperator(WithBracketOperator const, int) +# 2724| Block 0 +# 2724| v2724_1(void) = EnterFunction : +# 2724| mu2724_2(unknown) = AliasedDefinition : +# 2724| mu2724_3(unknown) = InitializeNonLocal : +# 2724| r2724_4(glval) = VariableAddress[x] : +# 2724| mu2724_5(WithBracketOperator) = InitializeParameter[x] : &:r2724_4 +# 2724| r2724_6(glval) = VariableAddress[i] : +# 2724| mu2724_7(int) = InitializeParameter[i] : &:r2724_6 +# 2725| r2725_1(glval) = VariableAddress[#return] : +# 2725| r2725_2(glval) = VariableAddress[x] : +# 2725| r2725_3(glval) = FunctionAddress[operator[]] : +# 2725| r2725_4(glval) = VariableAddress[i] : +# 2725| r2725_5(int) = Load[i] : &:r2725_4, ~m? +# 2725| r2725_6(char &) = Call[operator[]] : func:r2725_3, this:r2725_2, 0:r2725_5 +# 2725| mu2725_7(unknown) = ^CallSideEffect : ~m? +# 2725| v2725_8(void) = ^IndirectReadSideEffect[-1] : &:r2725_2, ~m? +# 2725| r2725_9(char) = Load[?] : &:r2725_6, ~m? +# 2725| mu2725_10(char) = Store[#return] : &:r2725_1, r2725_9 +# 2724| r2724_8(glval) = VariableAddress[#return] : +# 2724| v2724_9(void) = ReturnValue : &:r2724_8, ~m? +# 2724| v2724_10(void) = AliasedUse : ~m? +# 2724| v2724_11(void) = ExitFunction : + many-defs-per-use.cpp: # 34| void many_defs_per_use() # 34| Block 0 diff --git a/csharp/.config/dotnet-tools.json b/csharp/.config/dotnet-tools.json index 16d0d2fef4f7..f6b7213de593 100644 --- a/csharp/.config/dotnet-tools.json +++ b/csharp/.config/dotnet-tools.json @@ -3,10 +3,10 @@ "isRoot": true, "tools": { "paket": { - "version": "9.0.1", + "version": "9.0.2", "commands": [ "paket" ] } } -} \ No newline at end of file +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs index d0c0af6b768b..393e37579b71 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs @@ -604,6 +604,16 @@ private bool IsFeedReachable(string feed, int timeoutMilliSeconds, int tryCount, { httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, _) => { + if (chain is null || cert is null) + { + var msg = cert is null && chain is null + ? "certificate and chain" + : chain is null + ? "chain" + : "certificate"; + logger.LogWarning($"Dependabot proxy certificate validation failed due to missing {msg}"); + return false; + } chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; chain.ChainPolicy.CustomTrustStore.Add(this.dependabotProxy.Certificate); return chain.Build(cert); diff --git a/csharp/paket.lock b/csharp/paket.lock index 1d8e48895b34..795b9d0cfe1b 100644 --- a/csharp/paket.lock +++ b/csharp/paket.lock @@ -12,12 +12,12 @@ NUGET MSBuild.StructuredLogger (>= 2.2.243) System.Buffers (>= 4.6) Humanizer.Core (2.14.1) - MessagePack (3.0.3) - MessagePack.Annotations (>= 3.0.3) - MessagePackAnalyzer (>= 3.0.3) + MessagePack (3.0.300) + MessagePack.Annotations (>= 3.0.300) + MessagePackAnalyzer (>= 3.0.300) Microsoft.NET.StringTools (>= 17.11.4) - MessagePack.Annotations (3.0.3) - MessagePackAnalyzer (3.0.3) + MessagePack.Annotations (3.0.300) + MessagePackAnalyzer (3.0.300) Microsoft.Bcl.AsyncInterfaces (9.0) Microsoft.Build (17.12.6) Microsoft.Build.Framework (>= 17.12.6) diff --git a/csharp/paket.main.bzl b/csharp/paket.main.bzl index 4887b7c333ff..e87f635dee0d 100644 --- a/csharp/paket.main.bzl +++ b/csharp/paket.main.bzl @@ -9,9 +9,9 @@ def main(): packages = [ {"name": "Basic.CompilerLog.Util", "id": "Basic.CompilerLog.Util", "version": "0.9.4", "sha512": "sha512-VJMBSOOcdPD6ihA5k1gnVkDbH9GCABmx1055fFikEImT2dFp4yZhN7zMd8PW14tIb3BXIieP557n8xE+J2Y8Dw==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "net462": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "net47": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "net471": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "net472": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "net48": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "net5.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "net6.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "net7.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "net8.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "net9.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "netcoreapp2.1": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "netcoreapp2.2": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "netcoreapp3.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "netcoreapp3.1": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"], "netstandard2.1": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool", "System.Buffers"]}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Humanizer.Core", "id": "Humanizer.Core", "version": "2.14.1", "sha512": "sha512-yzqGU/HKNLZ9Uvr6kvSc3wYV/S5O/IvklIUW5WF7MuivGLY8wS5IZnLPkt7D1KW8Et2Enl0I3Lzg2vGWM24Xsw==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, - {"name": "MessagePack", "id": "MessagePack", "version": "3.0.3", "sha512": "sha512-rFOP00M8dZRRVVjg11M79hU9lhMziIkmqIc9CQ9QhK0R+us1mmpuEGwvnFupqN4F3zYEEoAM36SAdVC+i+mw+Q==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net462": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net47": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net471": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net472": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Memory", "System.Runtime.CompilerServices.Unsafe", "System.Threading.Tasks.Extensions"], "net48": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Memory", "System.Runtime.CompilerServices.Unsafe", "System.Threading.Tasks.Extensions"], "net5.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"], "net6.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"], "net7.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"], "net8.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools"], "net9.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.1": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.2": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp3.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"], "netcoreapp3.1": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netstandard2.1": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"]}, "targeting_pack_overrides": [], "framework_list": []}, - {"name": "MessagePack.Annotations", "id": "MessagePack.Annotations", "version": "3.0.3", "sha512": "sha512-LYOfElsnLTHsEs7VRd07mBiQjJos15mst8jP0v0zRx+t1OgUMUbbmQx6yO2fOww7vCyaX7vwXsoNuVJSdJdHPA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, - {"name": "MessagePackAnalyzer", "id": "MessagePackAnalyzer", "version": "3.0.3", "sha512": "sha512-gsMDGQbQv5dwGGKo2N6mC4TvIVaqKHqowgtqOMcVDLPnYUFdCViW2A+sssnBXJLR4m+zbFVHI7EBSR86svG+AQ==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, + {"name": "MessagePack", "id": "MessagePack", "version": "3.0.300", "sha512": "sha512-5Mdl6CrQcxVVLawvqebPLALFdIMgWOnEGxxFvXWjJ/8KGyyhbfKMusj34Wv1AwE+uE9VAb+McVxtR9HDZIUwuA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net462": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net47": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net471": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net472": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Memory", "System.Runtime.CompilerServices.Unsafe", "System.Threading.Tasks.Extensions"], "net48": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Memory", "System.Runtime.CompilerServices.Unsafe", "System.Threading.Tasks.Extensions"], "net5.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"], "net6.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"], "net7.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"], "net8.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools"], "net9.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.1": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.2": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp3.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"], "netcoreapp3.1": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.Bcl.AsyncInterfaces", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Threading.Tasks.Extensions", "System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netstandard2.1": ["MessagePackAnalyzer", "MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable"]}, "targeting_pack_overrides": [], "framework_list": []}, + {"name": "MessagePack.Annotations", "id": "MessagePack.Annotations", "version": "3.0.300", "sha512": "sha512-Jh9+7EsDtDSEciX8RfXHWxtRlC94wvCmmv+sFzGdzPF4fAp7OAGFktzViPBHMkCxrSh3hmM7jGUB7yMyUmzRCA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, + {"name": "MessagePackAnalyzer", "id": "MessagePackAnalyzer", "version": "3.0.300", "sha512": "sha512-Ad0UHGpotoXZYkBjJgO5Z1aTJz5YIsFGVrxc75OiHO/fNKSRKFiM1X2E1WTB5h7pk3uDzqXfh0M5fEEQVZ8FiQ==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.Bcl.AsyncInterfaces", "id": "Microsoft.Bcl.AsyncInterfaces", "version": "9.0.0", "sha512": "sha512-bYp2ksSR5uB6xqOa4NyD2gBOeFrc2n8FAWoh781MNMDcPjk1ysD7DNpv7r7sQOXfdFJT6F/syX7fN4lmUsn+RQ==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["System.Threading.Tasks.Extensions"], "net462": ["System.Threading.Tasks.Extensions"], "net47": ["System.Threading.Tasks.Extensions"], "net471": ["System.Threading.Tasks.Extensions"], "net472": ["System.Threading.Tasks.Extensions"], "net48": ["System.Threading.Tasks.Extensions"], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["System.Threading.Tasks.Extensions"], "netcoreapp2.1": ["System.Threading.Tasks.Extensions"], "netcoreapp2.2": ["System.Threading.Tasks.Extensions"], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["System.Threading.Tasks.Extensions"], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.Build", "id": "Microsoft.Build", "version": "17.12.6", "sha512": "sha512-YEiL5xKowbwnr52YroALNHg8YurjLyFTlhv3USrswhubuxN2ldY1TmQpBKQ4K28UgWJV9BxTVXY9/CecMNDeOA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Memory", "System.Reflection.MetadataLoadContext", "System.Reflection.Metadata", "System.Runtime.CompilerServices.Unsafe"], "net48": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Memory", "System.Reflection.MetadataLoadContext", "System.Reflection.Metadata", "System.Runtime.CompilerServices.Unsafe"], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Configuration.ConfigurationManager", "System.Reflection.MetadataLoadContext", "System.Collections.Immutable", "System.Reflection.Metadata"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.Build.Framework", "id": "Microsoft.Build.Framework", "version": "17.12.6", "sha512": "sha512-UjfxnrQN9BPVtO0Kvv2FB5dpN2CX5snc7coq5vVQdbCV6kdSpI/r+GZTLvU/5BTT8y8bvIUqoocxRR674N6bWg==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net462": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net47": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net471": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net472": ["System.Runtime.CompilerServices.Unsafe"], "net48": ["System.Runtime.CompilerServices.Unsafe"], "net5.0": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net6.0": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net7.0": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net8.0": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.1": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.2": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp3.0": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp3.1": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"], "netstandard2.1": ["System.Memory", "System.Runtime.CompilerServices.Unsafe"]}, "targeting_pack_overrides": [], "framework_list": []}, diff --git a/csharp/ql/integration-tests/all-platforms/cshtml_standalone_flowsteps/global.json b/csharp/ql/integration-tests/all-platforms/cshtml_standalone_flowsteps/global.json index d68ee8382ed0..76474f06d044 100644 --- a/csharp/ql/integration-tests/all-platforms/cshtml_standalone_flowsteps/global.json +++ b/csharp/ql/integration-tests/all-platforms/cshtml_standalone_flowsteps/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.300" + "version": "9.0.100" } } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index c711096cfb5e..e17bff759159 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -424,7 +424,11 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall { Callable getATarget(boolean static) { result = dc.getADynamicTarget().getUnboundDeclaration() and static = false or - result = dc.getAStaticTarget().getUnboundDeclaration() and static = true + result = dc.getAStaticTarget().getUnboundDeclaration() and + static = true and + // In reflection calls, _all_ methods with matching names and arities are considered + // static targets, so we need to exclude them + not dc.isReflection() } override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll index 790f055ef56a..1b27871d1ef6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll @@ -52,7 +52,21 @@ class DispatchCall extends Internal::TDispatchCall { } /** Holds if this call uses reflection. */ - predicate isReflection() { this instanceof Internal::TDispatchReflectionCall } + predicate isReflection() { + this instanceof Internal::TDispatchReflectionCall + or + this instanceof Internal::TDispatchDynamicElementAccess + or + this instanceof Internal::TDispatchDynamicMemberAccess + or + this instanceof Internal::TDispatchDynamicMethodCall + or + this instanceof Internal::TDispatchDynamicOperatorCall + or + this instanceof Internal::TDispatchDynamicEventAccess + or + this instanceof Internal::TDispatchDynamicObjectCreation + } } /** Internal implementation details. */ diff --git a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index e6ba8485eeee..e3c7ed6e5d9e 100644 --- a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -104,31 +104,6 @@ module ControlFlow { /** A node in the expression-level control-flow graph. */ class Node extends TNode { - /** Gets the statement containing this node, if any. */ - Stmt getEnclosingStmt() { - result = this.asStmt() or - result = this.asExpr().getEnclosingStmt() - } - - /** Gets the immediately enclosing callable whose body contains this node. */ - Callable getEnclosingCallable() { - this = TExitNode(result) or - result = this.asStmt().getEnclosingCallable() or - result = this.asExpr().getEnclosingCallable() - } - - /** Gets the statement this `Node` corresponds to, if any. */ - Stmt asStmt() { this = TStmtNode(result) } - - /** Gets the expression this `Node` corresponds to, if any. */ - Expr asExpr() { this = TExprNode(result) } - - /** Gets the call this `Node` corresponds to, if any. */ - Call asCall() { - result = this.asExpr() or - result = this.asStmt() - } - /** Gets an immediate successor of this node. */ Node getASuccessor() { result = succ(this) } @@ -147,34 +122,88 @@ module ControlFlow { /** Gets the basic block that contains this node. */ BasicBlock getBasicBlock() { result.getANode() = this } - /** Gets a textual representation of this element. */ - string toString() { - result = this.asExpr().toString() - or - result = this.asStmt().toString() - or - result = "Exit" and this instanceof ExitNode + /** Gets the statement containing this node, if any. */ + Stmt getEnclosingStmt() { none() } + + /** Gets the immediately enclosing callable whose body contains this node. */ + Callable getEnclosingCallable() { none() } + + /** Gets the statement this `Node` corresponds to, if any. */ + Stmt asStmt() { this = TStmtNode(result) } + + /** Gets the expression this `Node` corresponds to, if any. */ + Expr asExpr() { this = TExprNode(result) } + + /** Gets the call this `Node` corresponds to, if any. */ + Call asCall() { + result = this.asExpr() or + result = this.asStmt() } + /** Gets a textual representation of this element. */ + string toString() { none() } + /** Gets the source location for this element. */ - Location getLocation() { - result = this.asExpr().getLocation() or - result = this.asStmt().getLocation() or - result = this.(ExitNode).getEnclosingCallable().getLocation() - } + Location getLocation() { none() } /** * Gets the most appropriate AST node for this control flow node, if any. */ - ExprParent getAstNode() { - result = this.asExpr() or - result = this.asStmt() or - this = TExitNode(result) - } + ExprParent getAstNode() { none() } + } + + /** A control-flow node that represents the evaluation of an expression. */ + class ExprNode extends Node, TExprNode { + Expr e; + + ExprNode() { this = TExprNode(e) } + + override Stmt getEnclosingStmt() { result = e.getEnclosingStmt() } + + override Callable getEnclosingCallable() { result = e.getEnclosingCallable() } + + override ExprParent getAstNode() { result = e } + + /** Gets a textual representation of this element. */ + override string toString() { result = e.toString() } + + /** Gets the source location for this element. */ + override Location getLocation() { result = e.getLocation() } + } + + /** A control-flow node that represents a statement. */ + class StmtNode extends Node, TStmtNode { + Stmt s; + + StmtNode() { this = TStmtNode(s) } + + override Stmt getEnclosingStmt() { result = s } + + override Callable getEnclosingCallable() { result = s.getEnclosingCallable() } + + override ExprParent getAstNode() { result = s } + + override string toString() { result = s.toString() } + + override Location getLocation() { result = s.getLocation() } } /** A control flow node indicating the termination of a callable. */ - class ExitNode extends Node, TExitNode { } + class ExitNode extends Node, TExitNode { + Callable c; + + ExitNode() { this = TExitNode(c) } + + override Callable getEnclosingCallable() { result = c } + + override ExprParent getAstNode() { result = c } + + /** Gets a textual representation of this element. */ + override string toString() { result = "Exit" } + + /** Gets the source location for this element. */ + override Location getLocation() { result = c.getLocation() } + } } class ControlFlowNode = ControlFlow::Node; diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll index 135f830e47dc..1b13e4ebb17e 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, @@ -40,7 +40,7 @@ module Cryptography { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ DataFlow::Node getInitialization() { result = super.getInitialization() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ @@ -61,14 +61,14 @@ module Cryptography { /** Provides classes for modeling new applications of a cryptographic algorithms. */ module CryptographicOperation { /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CryptographicOperation` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ abstract DataFlow::Node getInitialization(); /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ @@ -118,14 +118,14 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `Http::Client::Request::Range` instead. */ class Request extends DataFlow::Node instanceof Request::Range { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } @@ -150,14 +150,14 @@ module Http { /** Provides a class for modeling new HTTP requests. */ module Request { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `Http::Client::Request` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ abstract DataFlow::Node getAUrlPart(); diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll index 135f830e47dc..1b13e4ebb17e 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, @@ -40,7 +40,7 @@ module Cryptography { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ DataFlow::Node getInitialization() { result = super.getInitialization() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ @@ -61,14 +61,14 @@ module Cryptography { /** Provides classes for modeling new applications of a cryptographic algorithms. */ module CryptographicOperation { /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CryptographicOperation` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ abstract DataFlow::Node getInitialization(); /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ @@ -118,14 +118,14 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `Http::Client::Request::Range` instead. */ class Request extends DataFlow::Node instanceof Request::Range { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } @@ -150,14 +150,14 @@ module Http { /** Provides a class for modeling new HTTP requests. */ module Request { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `Http::Client::Request` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ abstract DataFlow::Node getAUrlPart(); diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll index 135f830e47dc..1b13e4ebb17e 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, @@ -40,7 +40,7 @@ module Cryptography { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ DataFlow::Node getInitialization() { result = super.getInitialization() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ @@ -61,14 +61,14 @@ module Cryptography { /** Provides classes for modeling new applications of a cryptographic algorithms. */ module CryptographicOperation { /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CryptographicOperation` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ abstract DataFlow::Node getInitialization(); /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ @@ -118,14 +118,14 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `Http::Client::Request::Range` instead. */ class Request extends DataFlow::Node instanceof Request::Range { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } @@ -150,14 +150,14 @@ module Http { /** Provides a class for modeling new HTTP requests. */ module Request { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `Http::Client::Request` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ abstract DataFlow::Node getAUrlPart(); diff --git a/rust/ql/lib/codeql/rust/Concepts.qll b/rust/ql/lib/codeql/rust/Concepts.qll index 7e3ec0990ce3..51d601070000 100644 --- a/rust/ql/lib/codeql/rust/Concepts.qll +++ b/rust/ql/lib/codeql/rust/Concepts.qll @@ -105,7 +105,7 @@ module RemoteSource { } /** - * A data-flow node that constructs a SQL statement (for later execution). + * A data flow node that constructs a SQL statement (for later execution). * * Often, it is worthy of an alert if a SQL statement is constructed such that * executing it would be a security risk. @@ -122,7 +122,7 @@ final class SqlConstruction = SqlConstruction::Range; */ module SqlConstruction { /** - * A data-flow node that constructs a SQL statement. + * A data flow node that constructs a SQL statement. */ abstract class Range extends DataFlow::Node { /** @@ -133,7 +133,7 @@ module SqlConstruction { } /** - * A data-flow node that constructs and executes SQL statements. + * A data flow node that constructs and executes SQL statements. * * If the context of interest is such that merely constructing a SQL statement * would be valuable to report, consider also using `SqlConstruction`. @@ -148,7 +148,7 @@ final class SqlExecution = SqlExecution::Range; */ module SqlExecution { /** - * A data-flow node that executes SQL statements. + * A data flow node that executes SQL statements. */ abstract class Range extends DataFlow::Node { /** @@ -159,7 +159,7 @@ module SqlExecution { } /** - * A data-flow node that performs SQL sanitization. + * A data flow node that performs SQL sanitization. */ final class SqlSanitization = SqlSanitization::Range; @@ -168,7 +168,28 @@ final class SqlSanitization = SqlSanitization::Range; */ module SqlSanitization { /** - * A data-flow node that performs SQL sanitization. + * A data flow node that performs SQL sanitization. */ abstract class Range extends DataFlow::Node { } } + +/** + * Provides models for cryptographic things. + */ +module Cryptography { + private import codeql.rust.internal.ConceptsShared::Cryptography as SC + + final class CryptographicOperation = SC::CryptographicOperation; + + class EncryptionAlgorithm = SC::EncryptionAlgorithm; + + class HashingAlgorithm = SC::HashingAlgorithm; + + class PasswordHashingAlgorithm = SC::PasswordHashingAlgorithm; + + module CryptographicOperation = SC::CryptographicOperation; + + class BlockMode = SC::BlockMode; + + class CryptographicAlgorithm = SC::CryptographicAlgorithm; +} diff --git a/rust/ql/lib/codeql/rust/Frameworks.qll b/rust/ql/lib/codeql/rust/Frameworks.qll index 0c6fc573d0fb..483056888ec6 100644 --- a/rust/ql/lib/codeql/rust/Frameworks.qll +++ b/rust/ql/lib/codeql/rust/Frameworks.qll @@ -3,5 +3,6 @@ */ private import codeql.rust.frameworks.Reqwest +private import codeql.rust.frameworks.RustCrypto private import codeql.rust.frameworks.stdlib.Env private import codeql.rust.frameworks.Sqlx diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index 068429ce09b0..955aa52f6871 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -330,7 +330,7 @@ module Node { override ReturnKind getKind() { result = rk } } - /** A data-flow node that represents the output of a call. */ + /** A data flow node that represents the output of a call. */ abstract class OutNode extends Node { /** Gets the underlying call for this node. */ abstract DataFlowCall getCall(ReturnKind kind); diff --git a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll new file mode 100644 index 000000000000..9dd40004766a --- /dev/null +++ b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll @@ -0,0 +1,57 @@ +/** + * Provides modeling for the `RustCrypto` family of crates (`cipher`, `digest` etc). + */ + +private import rust +private import codeql.rust.Concepts +private import codeql.rust.dataflow.DataFlow + +bindingset[algorithmName] +private string simplifyAlgorithmName(string algorithmName) { + // the cipher library gives triple-DES names like "TdesEee2" and "TdesEde2" + if algorithmName.matches("Tdes%") then result = "3des" else result = algorithmName +} + +/** + * An operation that initializes a cipher through the `cipher::KeyInit` or + * `cipher::KeyIvInit` trait, for example `Des::new` or `cbc::Encryptor::new`. + */ +class StreamCipherInit extends Cryptography::CryptographicOperation::Range { + string algorithmName; + + StreamCipherInit() { + // a call to `cipher::KeyInit::new`, `cipher::KeyInit::new_from_slice`, + // `cipher::KeyIvInit::new`, `cipher::KeyIvInit::new_from_slices` or `rc2::Rc2::new_with_eff_key_len`. + exists(PathExpr p, string rawAlgorithmName | + this.asExpr().getExpr().(CallExpr).getFunction() = p and + p.getResolvedCrateOrigin().matches("%/RustCrypto%") and + p.getPath().getPart().getNameRef().getText() = + ["new", "new_from_slice", "new_from_slices", "new_with_eff_key_len"] and + ( + rawAlgorithmName = p.getPath().getQualifier().getPart().getNameRef().getText() or + rawAlgorithmName = + p.getPath() + .getQualifier() + .getPart() + .getGenericArgList() + .getGenericArg(0) + .(TypeArg) + .getTypeRepr() + .(PathTypeRepr) + .getPath() + .getPart() + .getNameRef() + .getText() + ) and + algorithmName = simplifyAlgorithmName(rawAlgorithmName) + ) + } + + override DataFlow::Node getInitialization() { result = this } + + override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(algorithmName) } + + override DataFlow::Node getAnInput() { none() } + + override Cryptography::BlockMode getBlockMode() { result = "" } +} diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll b/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll new file mode 100644 index 000000000000..341f3ade509f --- /dev/null +++ b/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll @@ -0,0 +1,7 @@ +/** + * This file contains imports required for the Rust version of `ConceptsShared.qll`. + * Since they are language-specific, they can't be placed directly in that file, as it is shared between languages. + */ + +import codeql.rust.dataflow.DataFlow::DataFlow as DataFlow +import codeql.rust.security.CryptoAlgorithms as CryptoAlgorithms diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll new file mode 100644 index 000000000000..1b13e4ebb17e --- /dev/null +++ b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll @@ -0,0 +1,181 @@ +/** + * Provides Concepts which are shared across languages. + * + * Each language has a language specific `Concepts.qll` file that can import the + * shared concepts from this file. A language can either re-export the concept directly, + * or can add additional member-predicates that are needed for that language. + * + * Moving forward, `Concepts.qll` will be the staging ground for brand new concepts from + * each language, but we will maintain a discipline of moving those concepts to + * `ConceptsShared.qll` ASAP. + */ + +private import ConceptsImports + +/** + * Provides models for cryptographic concepts. + * + * Note: The `CryptographicAlgorithm` class currently doesn't take weak keys into + * consideration for the `isWeak` member predicate. So RSA is always considered + * secure, although using a low number of bits will actually make it insecure. We plan + * to improve our libraries in the future to more precisely capture this aspect. + */ +module Cryptography { + class CryptographicAlgorithm = CryptoAlgorithms::CryptographicAlgorithm; + + class EncryptionAlgorithm = CryptoAlgorithms::EncryptionAlgorithm; + + class HashingAlgorithm = CryptoAlgorithms::HashingAlgorithm; + + class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; + + /** + * A data flow node that is an application of a cryptographic algorithm. For example, + * encryption, decryption, signature-validation. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CryptographicOperation::Range` instead. + */ + class CryptographicOperation extends DataFlow::Node instanceof CryptographicOperation::Range { + /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ + CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } + + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ + DataFlow::Node getInitialization() { result = super.getInitialization() } + + /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ + DataFlow::Node getAnInput() { result = super.getAnInput() } + + /** + * Gets the block mode used to perform this cryptographic operation. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. + */ + BlockMode getBlockMode() { result = super.getBlockMode() } + } + + /** Provides classes for modeling new applications of a cryptographic algorithms. */ + module CryptographicOperation { + /** + * A data flow node that is an application of a cryptographic algorithm. For example, + * encryption, decryption, signature-validation. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `CryptographicOperation` instead. + */ + abstract class Range extends DataFlow::Node { + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ + abstract DataFlow::Node getInitialization(); + + /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ + abstract CryptographicAlgorithm getAlgorithm(); + + /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ + abstract DataFlow::Node getAnInput(); + + /** + * Gets the block mode used to perform this cryptographic operation. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. + */ + abstract BlockMode getBlockMode(); + } + } + + /** + * A cryptographic block cipher mode of operation. This can be used to encrypt + * data of arbitrary length using a block encryption algorithm. + */ + class BlockMode extends string { + BlockMode() { + this = + [ + "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", + "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final + "EAX" // https://en.wikipedia.org/wiki/EAX_mode + ] + } + + /** Holds if this block mode is considered to be insecure. */ + predicate isWeak() { this = "ECB" } + + /** Holds if the given string appears to match this block mode. */ + bindingset[s] + predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } + } +} + +/** Provides classes for modeling HTTP-related APIs. */ +module Http { + /** Provides classes for modeling HTTP clients. */ + module Client { + /** + * A data flow node that makes an outgoing HTTP request. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `Http::Client::Request::Range` instead. + */ + class Request extends DataFlow::Node instanceof Request::Range { + /** + * Gets a data flow node that contributes to the URL of the request. + * Depending on the framework, a request may have multiple nodes which contribute to the URL. + */ + DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } + + /** Gets a string that identifies the framework used for this request. */ + string getFramework() { result = super.getFramework() } + + /** + * Holds if this request is made using a mode that disables SSL/TLS + * certificate validation, where `disablingNode` represents the point at + * which the validation was disabled, and `argumentOrigin` represents the origin + * of the argument that disabled the validation (which could be the same node as + * `disablingNode`). + */ + predicate disablesCertificateValidation( + DataFlow::Node disablingNode, DataFlow::Node argumentOrigin + ) { + super.disablesCertificateValidation(disablingNode, argumentOrigin) + } + } + + /** Provides a class for modeling new HTTP requests. */ + module Request { + /** + * A data flow node that makes an outgoing HTTP request. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `Http::Client::Request` instead. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets a data flow node that contributes to the URL of the request. + * Depending on the framework, a request may have multiple nodes which contribute to the URL. + */ + abstract DataFlow::Node getAUrlPart(); + + /** Gets a string that identifies the framework used for this request. */ + abstract string getFramework(); + + /** + * Holds if this request is made using a mode that disables SSL/TLS + * certificate validation, where `disablingNode` represents the point at + * which the validation was disabled, and `argumentOrigin` represents the origin + * of the argument that disabled the validation (which could be the same node as + * `disablingNode`). + */ + abstract predicate disablesCertificateValidation( + DataFlow::Node disablingNode, DataFlow::Node argumentOrigin + ); + } + } + } +} diff --git a/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll b/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll new file mode 100644 index 000000000000..7176c666c573 --- /dev/null +++ b/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll @@ -0,0 +1,117 @@ +/** + * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. + * + * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). + */ + +private import internal.CryptoAlgorithmNames + +/** + * A cryptographic algorithm. + */ +private newtype TCryptographicAlgorithm = + MkHashingAlgorithm(string name, boolean isWeak) { + isStrongHashingAlgorithm(name) and isWeak = false + or + isWeakHashingAlgorithm(name) and isWeak = true + } or + MkEncryptionAlgorithm(string name, boolean isWeak) { + isStrongEncryptionAlgorithm(name) and isWeak = false + or + isWeakEncryptionAlgorithm(name) and isWeak = true + } or + MkPasswordHashingAlgorithm(string name, boolean isWeak) { + isStrongPasswordHashingAlgorithm(name) and isWeak = false + or + isWeakPasswordHashingAlgorithm(name) and isWeak = true + } + +/** + * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. + * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. + * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. + */ +bindingset[name] +private CryptographicAlgorithm getBestAlgorithmForName(string name) { + result = + max(CryptographicAlgorithm algorithm | + algorithm.getName() = + [ + name.toUpperCase(), // the full name + name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces + name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores + ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces + | + algorithm order by algorithm.getName().length() + ) +} + +/** + * A cryptographic algorithm. + */ +abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { + /** Gets a textual representation of this element. */ + string toString() { result = this.getName() } + + /** + * Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores). + */ + abstract string getName(); + + /** + * Holds if the name of this algorithm is the most specific match for `name`. + * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. + */ + bindingset[name] + predicate matchesName(string name) { this = getBestAlgorithmForName(name) } + + /** + * Holds if this algorithm is weak. + */ + abstract predicate isWeak(); +} + +/** + * A hashing algorithm such as `MD5` or `SHA512`. + */ +class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} + +/** + * An encryption algorithm such as `DES` or `AES512`. + */ +class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } + + /** Holds if this algorithm is a stream cipher. */ + predicate isStreamCipher() { isStreamCipher(name) } +} + +/** + * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. + */ +class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} diff --git a/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll b/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll new file mode 100644 index 000000000000..8bb63d97876a --- /dev/null +++ b/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll @@ -0,0 +1,84 @@ +/** + * Names of cryptographic algorithms, separated into strong and weak variants. + * + * The names are normalized: upper-case, no spaces, dashes or underscores. + * + * The names are inspired by the names used in real world crypto libraries. + * + * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). + */ + +/** + * Holds if `name` corresponds to a strong hashing algorithm. + */ +predicate isStrongHashingAlgorithm(string name) { + name = + [ + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 + // and https://www.blake2.net/ + "BLAKE2", "BLAKE2B", "BLAKE2S", + // see https://github.com/BLAKE3-team/BLAKE3 + "BLAKE3", + // + "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", + "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 + "SHAKE128", "SHAKE256", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 + "SM3", + // see https://security.stackexchange.com/a/216297 + "WHIRLPOOL", + ] +} + +/** + * Holds if `name` corresponds to a weak hashing algorithm. + */ +predicate isWeakHashingAlgorithm(string name) { + name = + [ + "HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160", + "RIPEMD320", "SHA0", "SHA1" + ] +} + +/** + * Holds if `name` corresponds to a strong encryption algorithm. + */ +predicate isStrongEncryptionAlgorithm(string name) { + name = + [ + "AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512", + "ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192", + "CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89", + "IDEA", "RABBIT", "RSA", "SEED", "SM4" + ] +} + +/** + * Holds if `name` corresponds to a weak encryption algorithm. + */ +predicate isWeakEncryptionAlgorithm(string name) { + name = + [ + "DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", + "ARCFOUR", "ARC5", "RC5" + ] +} + +/** + * Holds if `name` corresponds to a strong password hashing algorithm. + */ +predicate isStrongPasswordHashingAlgorithm(string name) { + name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"] +} + +/** + * Holds if `name` corresponds to a weak password hashing algorithm. + */ +predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" } + +/** + * Holds if `name` corresponds to a stream cipher. + */ +predicate isStreamCipher(string name) { name = ["CHACHA", "RC4", "ARC4", "ARCFOUR", "RABBIT"] } diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp new file mode 100644 index 000000000000..e24222e09fc5 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp @@ -0,0 +1,62 @@ + + + +

+ Using broken or weak cryptographic algorithms can leave data + vulnerable to being decrypted or forged by an attacker. +

+ +

+ Many cryptographic algorithms provided by cryptography + libraries are known to be weak, or flawed. Using such an + algorithm means that encrypted or hashed data is less + secure than it appears to be. +

+ +

+ This query alerts on any use of a weak cryptographic algorithm, that is + not a hashing algorithm. Use of broken or weak cryptographic hash + functions are handled by the + rust/weak-sensitive-data-hashing query. +

+ +
+ + +

+ Ensure that you use a strong, modern cryptographic + algorithm, such as AES-128 or RSA-2048. +

+ +
+ + +

+ The following code uses the des crate from the + RustCrypto family to encrypt some secret data. The + DES algorithm is old and considered very weak. +

+ + + +

+ Instead, we should use a strong modern algorithm. In this + case, we have selected the 256-bit version of the AES + algorithm. +

+ + + +
+ + +
  • NIST, FIPS 140 Annex A: Approved Security Functions.
  • +
  • NIST, SP 800-131A Revision 2: Transitioning the Use of Cryptographic Algorithms and Key Lengths.
  • +
  • OWASP: Cryptographic Storage Cheat Sheet - Algorithms. +
  • +
    + +
    diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql new file mode 100644 index 000000000000..3d777b08539c --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql @@ -0,0 +1,25 @@ +/** + * @name Use of a broken or weak cryptographic algorithm + * @description Using broken or weak cryptographic algorithms can compromise security. + * @kind problem + * @problem.severity warning + * @security-severity 7.5 + * @precision high + * @id rust/weak-cryptographic-algorithm + * @tags security + * external/cwe/cwe-327 + */ + +import rust +import codeql.rust.Concepts + +from Cryptography::CryptographicOperation operation, string msgPrefix +where + exists(Cryptography::EncryptionAlgorithm algorithm | algorithm = operation.getAlgorithm() | + algorithm.isWeak() and + msgPrefix = "The cryptographic algorithm " + algorithm.getName() + ) + or + operation.getBlockMode().isWeak() and msgPrefix = "The block mode " + operation.getBlockMode() +select operation, "$@ is broken or weak, and should not be used.", operation.getInitialization(), + msgPrefix diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmBad.rs b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmBad.rs new file mode 100644 index 000000000000..3e86462c62a2 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmBad.rs @@ -0,0 +1,2 @@ +let des_cipher = cbc::Encryptor::::new(key.into(), iv.into()); // BAD: weak encryption +let encryption_result = des_cipher.encrypt_padded_mut::(data, data_len); diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmGood.rs b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmGood.rs new file mode 100644 index 000000000000..6cafbc69bf7d --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmGood.rs @@ -0,0 +1,2 @@ +let aes_cipher = cbc::Encryptor::::new(key.into(), iv.into()); // GOOD: strong encryption +let encryption_result = aes_cipher.encrypt_padded_mut::(data, data_len); diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected new file mode 100644 index 000000000000..f1395ff39ec0 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected @@ -0,0 +1,21 @@ +| test_cipher.rs:20:27:20:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:20:27:20:48 | ...::new(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:23:27:23:60 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:23:27:23:60 | ...::new_from_slice(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:26:27:26:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:26:27:26:48 | ...::new(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:29:27:29:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:29:27:29:48 | ...::new(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:59:23:59:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:59:23:59:42 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:63:23:63:47 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:63:23:63:47 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:67:23:67:46 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:67:23:67:46 | ...::new_from_slice(...) | The cryptographic algorithm DES | +| test_cipher.rs:71:23:71:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:71:23:71:42 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:75:27:75:46 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:75:27:75:46 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:80:24:80:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:80:24:80:48 | ...::new(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:84:24:84:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:84:24:84:48 | ...::new(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:88:24:88:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:88:24:88:48 | ...::new(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:92:24:92:52 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:92:24:92:52 | ...::new_from_slice(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:97:23:97:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:97:23:97:42 | ...::new(...) | The cryptographic algorithm RC2 | +| test_cipher.rs:101:23:101:46 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:101:23:101:46 | ...::new_from_slice(...) | The cryptographic algorithm RC2 | +| test_cipher.rs:105:23:105:56 | ...::new_with_eff_key_len(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:105:23:105:56 | ...::new_with_eff_key_len(...) | The cryptographic algorithm RC2 | +| test_cipher.rs:110:23:110:50 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:110:23:110:50 | ...::new(...) | The cryptographic algorithm RC5 | +| test_cipher.rs:114:23:114:55 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:114:23:114:55 | ...::new_from_slice(...) | The cryptographic algorithm RC5 | +| test_cipher.rs:132:23:132:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:132:23:132:76 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:138:23:138:76 | ...::new_from_slices(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:138:23:138:76 | ...::new_from_slices(...) | The cryptographic algorithm DES | +| test_cipher.rs:141:23:141:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:141:23:141:76 | ...::new(...) | The cryptographic algorithm DES | diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.qlref b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.qlref new file mode 100644 index 000000000000..6b7ff78b567a --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.qlref @@ -0,0 +1,2 @@ +query: queries/security/CWE-327/BrokenCryptoAlgorithm.ql +postprocess: utils/InlineExpectationsTestQuery.ql \ No newline at end of file diff --git a/rust/ql/test/query-tests/security/CWE-327/options.yml b/rust/ql/test/query-tests/security/CWE-327/options.yml new file mode 100644 index 000000000000..5a3cf0cab12e --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/options.yml @@ -0,0 +1,10 @@ +qltest_cargo_check: true +qltest_dependencies: + - cipher = { version = "0.4.4" } + - rc4 = { version = "0.1.0" } + - rabbit = { version = "0.4.1" } + - aes = { version = "0.8.4" } + - des = { version = "0.8.1" } + - rc2 = { version = "0.8.1" } + - rc5 = { version = "0.0.1" } + - cbc = { version = "0.1.2" } diff --git a/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs new file mode 100644 index 000000000000..0cf20c4c2782 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs @@ -0,0 +1,143 @@ + +use cipher::{consts::*, StreamCipher, KeyInit, KeyIvInit, BlockEncrypt, BlockDecrypt, BlockEncryptMut, BlockDecryptMut}; +use rc4::{Rc4}; +use rabbit::{Rabbit, RabbitKeyOnly}; +use aes::{Aes128, Aes192Enc, Aes256Dec}; +use des::{Des, TdesEde2, TdesEde3, TdesEee2, TdesEee3}; +use rc2::{Rc2}; +use rc5::{RC5_16_16_8, RC5_32_16_16}; + +// --- tests --- + +fn test_stream_cipher( + key128: &[u8;16], iv128: &[u8;16], plaintext: &str +) { + let mut data = plaintext.as_bytes().to_vec(); + + // rc4 (broken) + let rc4_key = rc4::Key::::from_slice(key128); + + let mut rc4_cipher1 = Rc4::<_>::new(rc4_key); // $ Alert[rust/weak-cryptographic-algorithm] + rc4_cipher1.apply_keystream(&mut data); + + let mut rc4_cipher2 = Rc4::::new_from_slice(key128).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] + rc4_cipher2.apply_keystream(&mut data); + + let mut rc4_cipher3 = Rc4::<_>::new(rc4_key); // $ Alert[rust/weak-cryptographic-algorithm] + let _ = rc4_cipher3.try_apply_keystream(&mut data); + + let mut rc4_cipher4 = Rc4::<_>::new(rc4_key); // $ Alert[rust/weak-cryptographic-algorithm] + let _ = rc4_cipher4.apply_keystream_b2b(plaintext.as_bytes(), &mut data); + + // rabbit + let rabbit_key = rabbit::Key::from_slice(key128); + let rabbit_iv = rabbit::Iv::from_slice(iv128); + + let mut rabbit_cipher1 = RabbitKeyOnly::new(rabbit_key); + rabbit_cipher1.apply_keystream(&mut data); + + let mut rabbit_cipher2 = Rabbit::new(rabbit_key, rabbit_iv); + rabbit_cipher2.apply_keystream(&mut data); +} + +fn test_block_cipher( + key: &[u8], key128: &[u8;16], key192: &[u8;24], key256: &[u8;32], + data: &mut [u8], input: &[u8], block128: &mut [u8;16] +) { + // aes + let aes_cipher1 = Aes128::new(key128.into()); + aes_cipher1.encrypt_block(block128.into()); + aes_cipher1.decrypt_block(block128.into()); + + let aes_cipher2 = Aes192Enc::new_from_slice(key192).unwrap(); + aes_cipher2.encrypt_block(block128.into()); + + let aes_cipher3 = Aes256Dec::new(key256.into()); + aes_cipher3.decrypt_block(block128.into()); + + // des (broken) + let des_cipher1 = Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + des_cipher1.encrypt_block(data.into()); + des_cipher1.decrypt_block(data.into()); + + let des_cipher2 = des::Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + des_cipher2.encrypt_block(data.into()); + des_cipher2.decrypt_block(data.into()); + + let des_cipher3 = Des::new_from_slice(key).expect("fail"); // $ Alert[rust/weak-cryptographic-algorithm] + des_cipher3.encrypt_block(data.into()); + des_cipher3.decrypt_block(data.into()); + + let des_cipher4 = Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + des_cipher4.encrypt_block_b2b(input.into(), data.into()); + des_cipher4.decrypt_block_b2b(input.into(), data.into()); + + let mut des_cipher5 = Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + des_cipher5.encrypt_block_mut(data.into()); + des_cipher5.decrypt_block_mut(data.into()); + + // triple des (broken) + let tdes_cipher1 = TdesEde2::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + tdes_cipher1.encrypt_block(data.into()); + tdes_cipher1.decrypt_block(data.into()); + + let tdes_cipher2 = TdesEde3::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + tdes_cipher2.encrypt_block(data.into()); + tdes_cipher2.decrypt_block(data.into()); + + let tdes_cipher3 = TdesEee2::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + tdes_cipher3.encrypt_block(data.into()); + tdes_cipher3.decrypt_block(data.into()); + + let tdes_cipher4 = TdesEee3::new_from_slice(key).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] + tdes_cipher4.encrypt_block(data.into()); + tdes_cipher4.decrypt_block(data.into()); + + // rc2 (broken) + let rc2_cipher1 = Rc2::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + rc2_cipher1.encrypt_block(data.into()); + rc2_cipher1.decrypt_block(data.into()); + + let rc2_cipher2 = Rc2::new_from_slice(key).expect("fail"); // $ Alert[rust/weak-cryptographic-algorithm] + rc2_cipher2.encrypt_block(data.into()); + rc2_cipher2.decrypt_block(data.into()); + + let rc2_cipher3 = Rc2::new_with_eff_key_len(key, 64); // $ Alert[rust/weak-cryptographic-algorithm] + rc2_cipher3.encrypt_block(data.into()); + rc2_cipher3.decrypt_block(data.into()); + + // rc5 (broken) + let rc5_cipher1 = RC5_16_16_8::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + rc5_cipher1.encrypt_block(data.into()); + rc5_cipher1.decrypt_block(data.into()); + + let rc5_cipher2 = RC5_32_16_16::new_from_slice(key).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] + rc5_cipher2.encrypt_block(data.into()); + rc5_cipher2.decrypt_block(data.into()); +} + +type MyDesEncryptor = cbc::Encryptor; + +fn test_cbc( + key: &[u8], key128: &[u8;16], iv: &[u8], iv128: &[u8;16], + input: &[u8], data: &mut [u8] +) { + let data_len = data.len(); + + // aes + let aes_cipher1 = cbc::Encryptor::::new(key128.into(), iv128.into()); + _ = aes_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); + + // des (broken) + let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); + + let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher2.encrypt_padded_mut::(data, data_len).unwrap(); + + let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher3.encrypt_padded_mut::(data, data_len).unwrap(); + + let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher4.encrypt_padded_b2b_mut::(input, data).unwrap(); +} diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll index e50efcb5532b..1373345423f7 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll @@ -1440,13 +1440,12 @@ module MakeImpl Lang> { pragma[nomagic] private predicate flowThroughOutOfCall( - DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow + DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow ) { exists(ReturnKindExt kind | PrevStage::callEdgeReturn(call, _, ret, kind, out, allowsFieldFlow) and PrevStage::callMayFlowThroughRev(call) and - PrevStage::returnMayFlowThrough(ret, kind) and - matchesCall(ccc, call) + PrevStage::returnMayFlowThrough(ret, kind) ) } @@ -1568,9 +1567,9 @@ module MakeImpl Lang> { apa = getApprox(ap) or // flow through a callable - exists(DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow | - fwdFlowThrough(call, cc, state, ccc, summaryCtx, t, ap, stored, ret) and - flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow) and + exists(DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow | + fwdFlowThrough(call, cc, state, summaryCtx, t, ap, stored, ret) and + flowThroughOutOfCall(call, ret, node, allowsFieldFlow) and apa = getApprox(ap) and not inBarrier(node, state) and if allowsFieldFlow = false then ap instanceof ApNil else any() @@ -2098,10 +2097,10 @@ module MakeImpl Lang> { pragma[nomagic] private predicate fwdFlowThrough( - DataFlowCall call, Cc cc, FlowState state, CcCall ccc, SummaryCtx summaryCtx, Typ t, - Ap ap, TypOption stored, RetNodeEx ret + DataFlowCall call, Cc cc, FlowState state, SummaryCtx summaryCtx, Typ t, Ap ap, + TypOption stored, RetNodeEx ret ) { - fwdFlowThrough0(call, _, cc, state, ccc, summaryCtx, t, ap, stored, ret, _) + fwdFlowThrough0(call, _, cc, state, _, summaryCtx, t, ap, stored, ret, _) } pragma[nomagic] @@ -2156,7 +2155,7 @@ module MakeImpl Lang> { exists(DataFlowCall call, boolean allowsFieldFlow | returnFlowsThrough0(call, state, ccc, ap, ret, TSummaryCtxSome(p, _, argT, argAp, argStored)) and - flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow) and + flowThroughOutOfCall(call, ret, _, allowsFieldFlow) and pos = ret.getReturnPosition() and if allowsFieldFlow = false then ap instanceof ApNil else any() ) @@ -3155,12 +3154,11 @@ module MakeImpl Lang> { pragma[nomagic] private predicate fwdFlowThroughStep1( PathNodeImpl pn1, PathNodeImpl pn2, PathNodeImpl pn3, DataFlowCall call, Cc cc, - FlowState state, CcCall ccc, SummaryCtx summaryCtx, Typ t, Ap ap, TypOption stored, - RetNodeEx ret + FlowState state, SummaryCtx summaryCtx, Typ t, Ap ap, TypOption stored, RetNodeEx ret ) { exists( FlowState state0, ArgNodeEx arg, SummaryCtxSome innerSummaryCtx, ParamNodeEx p, - Typ innerArgT, Ap innerArgAp, TypOption innerArgStored + Typ innerArgT, Ap innerArgAp, TypOption innerArgStored, CcCall ccc | fwdFlowThroughStep0(call, arg, cc, state, ccc, summaryCtx, t, ap, stored, ret, innerSummaryCtx) and @@ -3178,10 +3176,9 @@ module MakeImpl Lang> { PathNodeImpl pn1, PathNodeImpl pn2, PathNodeImpl pn3, NodeEx node, Cc cc, FlowState state, SummaryCtx summaryCtx, Typ t, Ap ap, TypOption stored ) { - exists(DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow | - fwdFlowThroughStep1(pn1, pn2, pn3, call, cc, state, ccc, summaryCtx, t, ap, stored, - ret) and - flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow) and + exists(DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow | + fwdFlowThroughStep1(pn1, pn2, pn3, call, cc, state, summaryCtx, t, ap, stored, ret) and + flowThroughOutOfCall(call, ret, node, allowsFieldFlow) and not inBarrier(node, state) and if allowsFieldFlow = false then ap instanceof ApNil else any() )