diff --git a/cpp/ql/src/Critical/OverflowDestination.ql b/cpp/ql/src/Critical/OverflowDestination.ql index 4cfaaf8981b3..df14cafd1527 100644 --- a/cpp/ql/src/Critical/OverflowDestination.ql +++ b/cpp/ql/src/Critical/OverflowDestination.ql @@ -82,6 +82,16 @@ module OverflowDestinationConfig implements DataFlow::ConfigSig { nodeIsBarrierEqualityCandidate(node, access, checkedVar) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(FunctionCall fc | result = fc.getLocation() | + sourceSized(fc, sink.asIndirectConvertedExpr()) + ) + } } module OverflowDestination = TaintTracking::Global; diff --git a/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql b/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql index 62c3c98e197c..34817ff92295 100644 --- a/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql +++ b/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql @@ -168,6 +168,19 @@ module NonConstFlowConfig implements DataFlow::ConfigSig { cannotContainString(t) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + result = sink.getLocation() + or + exists(FormattingFunctionCall call, Expr formatString | result = call.getLocation() | + isSinkImpl(sink, formatString) and + call.getArgument(call.getFormatParameterIndex()) = formatString + ) + } } module NonConstFlow = TaintTracking::Global; diff --git a/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll b/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll index 3cff86412e49..863fd1e61203 100644 --- a/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll +++ b/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll @@ -215,6 +215,10 @@ private module LeapYearCheckConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node sink) { exists(ChecksForLeapYearFunctionCall fc | sink.asExpr() = fc.getAnArgument()) } + + predicate observeDiffInformedIncrementalMode() { + none() // only used negatively in UncheckedLeapYearAfterYearModification.ql + } } module LeapYearCheckFlow = DataFlow::Global; @@ -285,6 +289,14 @@ private module PossibleYearArithmeticOperationCheckConfig implements DataFlow::C aexpr.getLValue() = fa ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { + result = source.asExpr().getLocation() + } + + Location getASelectedSinkLocation(DataFlow::Node sink) { result = sink.asExpr().getLocation() } } module PossibleYearArithmeticOperationCheckFlow = diff --git a/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll b/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll index f0876800874c..5bc4ac2e2288 100644 --- a/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll +++ b/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll @@ -51,6 +51,10 @@ private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig { } predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode } + + predicate observeDiffInformedIncrementalMode() { + none() // risky since used in library: normal use in UntrustedDataToExternalApi.ql; used via ExternalApiUsedWithUntrustedData (no location) in CountUntrustedDataToExternalAPI.ql + } } module UntrustedDataToExternalApiFlow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIsSpecific.qll b/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIsSpecific.qll index d094439951f2..e0a037efd144 100644 --- a/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIsSpecific.qll +++ b/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIsSpecific.qll @@ -46,6 +46,10 @@ private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode } + + predicate observeDiffInformedIncrementalMode() { + none() // risky since used in library: normal use in IRUntrustedDataToExternalApi.ql; used via ExternalApiUsedWithUntrustedData (no location) in IRCountUntrustedDataToExternalAPI.ql + } } module UntrustedDataToExternalApiFlow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql index 94a9cacf9f49..1a15f6c3a152 100644 --- a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql +++ b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql @@ -93,6 +93,12 @@ module TaintedPathConfig implements DataFlow::ConfigSig { // make sinks barriers so that we only report the closest instance isSink(node) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + result = sink.asIndirectArgument().getLocation() + } } module TaintedPath = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql b/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql index a609724937aa..1098656f7a20 100644 --- a/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql +++ b/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql @@ -150,6 +150,17 @@ module ExecTaintConfig implements DataFlow::StateConfigSig { predicate isBarrierOut(DataFlow::Node node) { isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(DataFlow::Node concatResult, Expr command, ExecState state | + result = [concatResult.getLocation(), command.getLocation()] and + isSink(sink, state) and + isSinkImpl(sink, command, _) and + concatResult = state.getOutgoingNode() + ) + } } module ExecTaint = TaintTracking::GlobalWithState; diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql index 9b27e95fd658..994aba733d23 100644 --- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql +++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql @@ -39,6 +39,12 @@ module Config implements DataFlow::ConfigSig { or node.asCertainDefinition().getUnspecifiedType() instanceof ArithmeticType } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { + exists(QueryString query | result = query.getLocation() | query = source.asIndirectExpr()) + } } module Flow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql index 0ea4ce2e95f4..5a823b8672c5 100644 --- a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql +++ b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql @@ -54,6 +54,12 @@ module SqlTaintedConfig implements DataFlow::ConfigSig { sql.barrierSqlArgument(input, _) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(Expr taintedArg | result = taintedArg.getLocation() | taintedArg = asSinkExpr(sink)) + } } module SqlTainted = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql b/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql index ec3543c19928..2cce72bc2ae8 100644 --- a/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql +++ b/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql @@ -124,6 +124,12 @@ module Config implements DataFlow::ConfigSig { // Block flow if the node is guarded by any <, <= or = operations. node = DataFlow::BarrierGuard::getABarrierNode() } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(BufferWrite bw | result = bw.getLocation() | isSink(sink, bw, _)) + } } module Flow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-170/ImproperNullTerminationTainted.ql b/cpp/ql/src/Security/CWE/CWE-170/ImproperNullTerminationTainted.ql index 9b595657fce9..2f051776dbe2 100644 --- a/cpp/ql/src/Security/CWE/CWE-170/ImproperNullTerminationTainted.ql +++ b/cpp/ql/src/Security/CWE/CWE-170/ImproperNullTerminationTainted.ql @@ -43,6 +43,12 @@ private module Config implements DataFlow::ConfigSig { } predicate isSink(DataFlow::Node sink) { isSink(sink, _) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(VariableAccess va | result = va.getLocation() | isSink(sink, va)) + } } module Flow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql index c9efaf9f6952..86806c0b7762 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql @@ -106,6 +106,12 @@ module Config implements DataFlow::ConfigSig { not iTo instanceof PointerArithmeticInstruction ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(Expr e | result = e.getLocation() | isSink(sink, _, e)) + } } module Flow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql index 54c3b013471a..64705f078c69 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql @@ -120,6 +120,12 @@ module UncontrolledArithConfig implements DataFlow::ConfigSig { // block unintended flow to pointers node.asExpr().getUnspecifiedType() instanceof PointerType } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { + result = getExpr(source).getLocation() + } } module UncontrolledArith = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql index 15fd2cbca15f..50cef092600b 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql @@ -113,6 +113,12 @@ module Config implements DataFlow::ConfigSig { not iTo instanceof PointerArithmeticInstruction ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(VariableAccess va | result = va.getLocation() | isSink(sink, va, _)) + } } module Flow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql index 6307ddf5fe63..0149f483cc12 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql @@ -91,6 +91,12 @@ module TaintedAllocationSizeConfig implements DataFlow::ConfigSig { // to duplicate results) any(HeuristicAllocationFunction f).getAParameter() = node.asParameter() } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(Expr alloc | result = alloc.getLocation() | allocSink(alloc, sink)) + } } module TaintedAllocationSize = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql b/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql index ada0180668e0..74386b30bbab 100644 --- a/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql +++ b/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql @@ -72,6 +72,12 @@ module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { isSource(source, _) } predicate isSink(DataFlow::Node sink) { isSink(sink, _) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(Expr condition | result = condition.getLocation() | isSink(sink, condition)) + } } module Flow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.ql b/cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.ql index 8a3c2f3664d6..379c20f51baf 100644 --- a/cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.ql +++ b/cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.ql @@ -31,6 +31,14 @@ module VerifyResultConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node sink) { exists(GuardCondition guard | guard.getAChild*() = sink.asExpr()) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(GuardCondition guard | result = guard.getLocation() | + guard.comparesEq(sink.asExpr(), _, 0, false, _) + ) + } } module VerifyResult = DataFlow::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql b/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql index f2754c5811f0..c671ad5af7f2 100644 --- a/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql +++ b/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql @@ -47,6 +47,12 @@ module ToBufferConfig implements DataFlow::ConfigSig { } predicate isSink(DataFlow::Node sink) { isSinkImpl(sink, _) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(SensitiveBufferWrite w | result = w.getLocation() | isSinkImpl(sink, w)) + } } module ToBufferFlow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql b/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql index c04ceae7adad..6aff19ceb4af 100644 --- a/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql +++ b/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql @@ -31,6 +31,16 @@ module FromSensitiveConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node node) { node.asExpr().getUnspecifiedType() instanceof IntegralType } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node sourceNode) { + exists(SensitiveExpr source | result = source.getLocation() | isSourceImpl(sourceNode, source)) + } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(FileWrite w | result = w.getLocation() | isSinkImpl(sink, w, _)) + } } module FromSensitiveFlow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-311/CleartextTransmission.ql b/cpp/ql/src/Security/CWE/CWE-311/CleartextTransmission.ql index 09db3f216029..10bb10d6a2bb 100644 --- a/cpp/ql/src/Security/CWE/CWE-311/CleartextTransmission.ql +++ b/cpp/ql/src/Security/CWE/CWE-311/CleartextTransmission.ql @@ -245,6 +245,14 @@ module FromSensitiveConfig implements DataFlow::ConfigSig { // sources to not get path duplication. isSource(node) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(NetworkSendRecv networkSendRecv | result = networkSendRecv.getLocation() | + isSinkSendRecv(sink, networkSendRecv) + ) + } } module FromSensitiveFlow = TaintTracking::Global; @@ -266,6 +274,10 @@ module ToEncryptionConfig implements DataFlow::ConfigSig { // sources to not get path duplication. isSource(node) } + + predicate observeDiffInformedIncrementalMode() { + none() // only used negatively + } } module ToEncryptionFlow = TaintTracking::Global; @@ -281,6 +293,10 @@ module FromEncryptionConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node node) { node.asExpr().getUnspecifiedType() instanceof IntegralType } + + predicate observeDiffInformedIncrementalMode() { + none() // only used negatively + } } module FromEncryptionFlow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql b/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql index 0c060befeff5..a6f567600f9d 100644 --- a/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql +++ b/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql @@ -123,6 +123,20 @@ module FromSensitiveConfig implements DataFlow::ConfigSig { content.(DataFlow::FieldContent).getField() = getRecField(t.stripType()) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { + exists(SensitiveExpr sensitive | result = sensitive.getLocation() | + isSourceImpl(source, sensitive) + ) + } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(SqliteFunctionCall sqliteCall | result = sqliteCall.getLocation() | + isSinkImpl(sink, sqliteCall, _) + ) + } } module FromSensitiveFlow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-319/UseOfHttp.ql b/cpp/ql/src/Security/CWE/CWE-319/UseOfHttp.ql index 423ed57dd98f..d12340035bde 100644 --- a/cpp/ql/src/Security/CWE/CWE-319/UseOfHttp.ql +++ b/cpp/ql/src/Security/CWE/CWE-319/UseOfHttp.ql @@ -87,6 +87,14 @@ module HttpStringToUrlOpenConfig implements DataFlow::ConfigSig { sink.asIndirectExpr() = fc.getArgument(3) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { + result = source.asIndirectExpr().getLocation() + } + + Location getASelectedSinkLocation(DataFlow::Node sink) { none() } } module HttpStringToUrlOpen = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-326/InsufficientKeySize.ql b/cpp/ql/src/Security/CWE/CWE-326/InsufficientKeySize.ql index 3cc10b7ad19c..9f75475854dc 100644 --- a/cpp/ql/src/Security/CWE/CWE-326/InsufficientKeySize.ql +++ b/cpp/ql/src/Security/CWE/CWE-326/InsufficientKeySize.ql @@ -44,6 +44,12 @@ module KeyStrengthFlowConfig implements DataFlow::ConfigSig { exists(getMinimumKeyStrength(name, param)) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(FunctionCall fc | result = fc.getLocation() | sink.asExpr() = fc.getArgument(_)) + } } module KeyStrengthFlow = DataFlow::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql b/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql index 11d628c1affa..c386cb1da4d8 100644 --- a/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql +++ b/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql @@ -145,6 +145,18 @@ module Config implements DataFlow::StateConfigSig { // ``` result instanceof DataFlow::FeatureHasSinkCallContext } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(DataFlow::Node mid, FlowState state | result = mid.getLocation() | + destroyedToBeginSink(sink) and + isSink(sink, state) and + state = Config::DestroyedToBegin(mid) + ) + } } module Flow = DataFlow::GlobalWithState; diff --git a/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql b/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql index 2703f819b546..f0851b7d8075 100644 --- a/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql +++ b/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql @@ -62,6 +62,16 @@ module NullAppNameCreateProcessFunctionConfig implements DataFlow::ConfigSig { val = call.getArgument(call.getApplicationNameArgumentId()) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(CreateProcessFunctionCall call | result = call.getLocation() | + sink.asExpr() = call.getArgument(call.getApplicationNameArgumentId()) + ) + } } module NullAppNameCreateProcessFunction = DataFlow::Global; @@ -82,6 +92,16 @@ module QuotedCommandInCreateProcessFunctionConfig implements DataFlow::ConfigSig val = call.getArgument(call.getCommandLineArgumentId()) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(CreateProcessFunctionCall call | result = call.getLocation() | + sink.asExpr() = call.getArgument(call.getCommandLineArgumentId()) + ) + } } module QuotedCommandInCreateProcessFunction = diff --git a/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql b/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql index 5ed30e19bb32..a0096f410c51 100644 --- a/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql +++ b/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql @@ -37,6 +37,16 @@ module NullDaclConfig implements DataFlow::ConfigSig { val = call.getArgument(2) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(SetSecurityDescriptorDaclFunctionCall call | result = call.getLocation() | + sink.asExpr() = call.getArgument(2) + ) + } } module NullDaclFlow = DataFlow::Global; @@ -68,6 +78,10 @@ module NonNullDaclConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node sink) { exists(SetSecurityDescriptorDaclFunctionCall call | sink.asExpr() = call.getArgument(2)) } + + predicate observeDiffInformedIncrementalMode() { + none() // only used negatively + } } module NonNullDaclFlow = DataFlow::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql b/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql index 7eaa5df849d4..171fbd26dd93 100644 --- a/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql +++ b/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql @@ -65,6 +65,16 @@ module Config implements DataFlow::ConfigSig { iFrom1 != iFrom2 ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + result = sink.getLocation() + or + exists(Expr raise | result = raise.getLocation() | + sensitiveCondition([sink.asExpr(), sink.asIndirectExpr()], raise) + ) + } } module Flow = TaintTracking::Global; diff --git a/cpp/ql/src/Security/CWE/CWE-843/TypeConfusion.ql b/cpp/ql/src/Security/CWE/CWE-843/TypeConfusion.ql index acfd27cc45ba..4ca30c3e916a 100644 --- a/cpp/ql/src/Security/CWE/CWE-843/TypeConfusion.ql +++ b/cpp/ql/src/Security/CWE/CWE-843/TypeConfusion.ql @@ -178,6 +178,10 @@ module Config implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(UnsafeCast cast).getUnconverted() } int fieldFlowBranchLimit() { result = 0 } + + predicate observeDiffInformedIncrementalMode() { + none() // used both positively and negatively + } } module Flow = DataFlow::Global; diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql index c38a012b27bf..b7b2de6000ae 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql @@ -183,6 +183,20 @@ module ArrayAddressToDerefConfig implements DataFlow::StateConfigSig { pointerArithOverflow(pai, _) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { + exists(Variable v | result = v.getLocation() | isSourceImpl(source, v)) + } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(PointerArithmeticInstruction pai, Instruction deref | + result = [pai, deref].getLocation() and + isInvalidPointerDerefSink2(sink, deref, _) and + isSink(sink, ArrayAddressToDerefConfig::TOverflowArithmetic(pai)) + ) + } } module ArrayAddressToDerefFlow = DataFlow::GlobalWithState; diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-409/DecompressionBombs.ql b/cpp/ql/src/experimental/Security/CWE/CWE-409/DecompressionBombs.ql index bfa11e65b067..fbeb4cde5fd1 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-409/DecompressionBombs.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-409/DecompressionBombs.ql @@ -28,6 +28,14 @@ module DecompressionTaintConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(DecompressionFlowStep s).isAdditionalFlowStep(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + exists(FunctionCall fc | result = [sink.getLocation(), fc.getLocation()] | isSink(fc, sink)) + } } module DecompressionTaint = TaintTracking::Global; diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-020/CountUntrustedDataToExternalAPI.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-020/CountUntrustedDataToExternalAPI.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-020/CountUntrustedDataToExternalAPI.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-020/CountUntrustedDataToExternalAPI.qlref new file mode 100644 index 000000000000..082405f9e404 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-020/CountUntrustedDataToExternalAPI.qlref @@ -0,0 +1,4 @@ +query: Security/CWE/CWE-020/CountUntrustedDataToExternalAPI.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-020/ExternalAPISinkExample.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-020/ExternalAPISinkExample.cpp new file mode 100644 index 000000000000..471ed26cb259 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-020/ExternalAPISinkExample.cpp @@ -0,0 +1,18 @@ +typedef unsigned long size_t; +typedef size_t FILE; + +char *strcat(char *s1, const char *s2); +char *fgets(char *s, int n, FILE *stream); +char *fputs(const char *s, FILE *stream); + +void do_get(FILE* request, FILE* response) { + char page[1024]; + fgets(page, 1024, request); + + char buffer[1024]; + strcat(buffer, "The page \""); + strcat(buffer, page); + strcat(buffer, "\" was not found."); + + fputs(buffer, response); +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-020/ExternalAPITaintStepExample.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-020/ExternalAPITaintStepExample.cpp new file mode 100644 index 000000000000..1641ce3baa0d --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-020/ExternalAPITaintStepExample.cpp @@ -0,0 +1,18 @@ +typedef unsigned long size_t; +typedef size_t FILE; + +char *strcat(char *s1, const char *s2); +char *fgets(char *s, int n, FILE *stream); +char *fputs(const char *s, FILE *stream); + +void do_get(FILE* request, FILE* response) { + char user_id[1024]; + fgets(user_id, 1024, request); + + char buffer[1024]; + strcat(buffer, "SELECT * FROM user WHERE user_id='"); + strcat(buffer, user_id); + strcat(buffer, "'"); + + // ... +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRCountUntrustedDataToExternalAPI.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRCountUntrustedDataToExternalAPI.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRCountUntrustedDataToExternalAPI.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRCountUntrustedDataToExternalAPI.qlref new file mode 100644 index 000000000000..81155a9a6375 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRCountUntrustedDataToExternalAPI.qlref @@ -0,0 +1,4 @@ +query: Security/CWE/CWE-020/IRCountUntrustedDataToExternalAPI.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.expected new file mode 100644 index 000000000000..58f42bec0c84 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.expected @@ -0,0 +1,4 @@ +#select +edges +nodes +subpaths diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.qlref new file mode 100644 index 000000000000..826e00a0263f --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.qlref @@ -0,0 +1,4 @@ +query: Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-020/UntrustedDataToExternalAPI.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-020/UntrustedDataToExternalAPI.expected new file mode 100644 index 000000000000..58f42bec0c84 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-020/UntrustedDataToExternalAPI.expected @@ -0,0 +1,4 @@ +#select +edges +nodes +subpaths diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-020/UntrustedDataToExternalAPI.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-020/UntrustedDataToExternalAPI.qlref new file mode 100644 index 000000000000..a4c937bd3d8a --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-020/UntrustedDataToExternalAPI.qlref @@ -0,0 +1,4 @@ +query: Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-313/CleartextSqliteDatabase.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-313/CleartextSqliteDatabase.cpp new file mode 100644 index 000000000000..57298515793b --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-313/CleartextSqliteDatabase.cpp @@ -0,0 +1,121 @@ +typedef unsigned long size_t; +typedef struct sqlite3 sqlite3; +typedef struct sqlite3_stmt sqlite3_stmt; +typedef struct sqlite3_str sqlite3_str; + +int snprintf(char *str, size_t size, const char *format, ...); +int sqlite3_open(const char *filename, sqlite3 **ppDb); +int sqlite3_close(sqlite3*); +int sqlite3_exec(sqlite3*, const char *sql, int (*callback)(void*,int,char**,char**), void *, char **errmsg); +int sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail); +int sqlite3_step(sqlite3_stmt*); +int sqlite3_finalize(sqlite3_stmt*); +int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); +sqlite3_str* sqlite3_str_new(sqlite3*); +void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...); +char* sqlite3_str_finish(sqlite3_str*); + +#define SQLITE_TRANSIENT ((void(*)(void*))-1) + +// Simulate a sensitive value +const char* getSensitivePassword() { + return "super_secret_password"; +} + +void storePasswordCleartext(sqlite3* db, const char* password) { + // BAD: Storing sensitive data in cleartext + char sql[256]; + // Unsafe: no escaping, for test purposes only + snprintf(sql, sizeof(sql), "INSERT INTO users(password) VALUES('%s');", password); // $ Source + char* errMsg = 0; + sqlite3_exec(db, sql, 0, 0, &errMsg); // $ Alert +} + +void storePasswordWithPrepare(sqlite3* db, const char* password) { + // BAD: Storing sensitive data in cleartext using sqlite3_prepare + char sql[256]; + snprintf(sql, sizeof(sql), "INSERT INTO users(password) VALUES('%s');", password); // $ Source + sqlite3_stmt* stmt = 0; + sqlite3_prepare_v2(db, sql, -1, &stmt, 0); // $ Alert + sqlite3_step(stmt); + sqlite3_finalize(stmt); +} + +void storePasswordWithBind(sqlite3* db, const char* password) { + // BAD: Storing sensitive data in cleartext using sqlite3_bind_text + const char* sql = "INSERT INTO users(password) VALUES(?);"; + sqlite3_stmt* stmt = 0; + sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT); // $ Alert + sqlite3_step(stmt); + sqlite3_finalize(stmt); +} + +void storePasswordWithAppendf(sqlite3_str* pStr, const char* password) { + // BAD: Storing sensitive data in cleartext using sqlite3_str_appendf + sqlite3_str_appendf(pStr, "INSERT INTO users(password) VALUES('%s');", password); // $ Alert +} + +// Example sanitizer: hashes the sensitive value before storage +void hashSensitiveValue(const char* input, char* output, size_t outSize) { + // Dummy hash for illustration (not cryptographically secure) + unsigned int hash = 5381; + for (const char* p = input; *p; ++p) + hash = ((hash << 5) + hash) + (unsigned char)(*p); + snprintf(output, outSize, "%u", hash); +} + +void storeSanitizedPasswordCleartext(sqlite3* db, const char* password) { + // GOOD: Sanitizing sensitive data before storage + char hashed[64]; + hashSensitiveValue(password, hashed, sizeof(hashed)); + char sql[256]; + snprintf(sql, sizeof(sql), "INSERT INTO users(password) VALUES('%s');", hashed); + char* errMsg = 0; + sqlite3_exec(db, sql, 0, 0, &errMsg); +} + +void storeSanitizedPasswordWithBind(sqlite3* db, const char* password) { + // GOOD: Sanitizing sensitive data before storage with bind + char hashed[64]; + hashSensitiveValue(password, hashed, sizeof(hashed)); + const char* sql = "INSERT INTO users(password) VALUES(?);"; + sqlite3_stmt* stmt = 0; + sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + sqlite3_bind_text(stmt, 1, hashed, -1, SQLITE_TRANSIENT); + sqlite3_step(stmt); + sqlite3_finalize(stmt); +} + +void storeSanitizedPasswordWithAppendf(sqlite3_str* pStr, const char* password) { + // GOOD: Sanitizing sensitive data before storage with appendf + char hashed[64]; + hashSensitiveValue(password, hashed, sizeof(hashed)); + sqlite3_str_appendf(pStr, "INSERT INTO users(password) VALUES('%s');", hashed); +} + +int main() { + sqlite3* db = 0; + sqlite3_open(":memory:", &db); + + // Create table + const char* createTableSQL = "CREATE TABLE users(id INTEGER PRIMARY KEY, password TEXT);"; + sqlite3_exec(db, createTableSQL, 0, 0, 0); + + const char* sensitive = getSensitivePassword(); + + storePasswordCleartext(db, sensitive); + storePasswordWithPrepare(db, sensitive); + storePasswordWithBind(db, sensitive); + storeSanitizedPasswordCleartext(db, sensitive); + storeSanitizedPasswordWithBind(db, sensitive); + + // If sqlite3_str is available + sqlite3_str* pStr = sqlite3_str_new(db); + storePasswordWithAppendf(pStr, sensitive); + storeSanitizedPasswordWithAppendf(pStr, sensitive); + sqlite3_str_finish(pStr); + + sqlite3_close(db); + return 0; +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-313/CleartextSqliteDatabase.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-313/CleartextSqliteDatabase.expected new file mode 100644 index 000000000000..89a7a2c58265 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-313/CleartextSqliteDatabase.expected @@ -0,0 +1,16 @@ +#select +| CleartextSqliteDatabase.cpp:31:5:31:16 | call to sqlite3_exec | CleartextSqliteDatabase.cpp:29:77:29:84 | password | CleartextSqliteDatabase.cpp:31:22:31:24 | *sql | This SQLite call may store $@ in a non-encrypted SQLite database. | CleartextSqliteDatabase.cpp:29:77:29:84 | password | sensitive information | +| CleartextSqliteDatabase.cpp:39:5:39:22 | call to sqlite3_prepare_v2 | CleartextSqliteDatabase.cpp:37:77:37:84 | password | CleartextSqliteDatabase.cpp:39:28:39:30 | *sql | This SQLite call may store $@ in a non-encrypted SQLite database. | CleartextSqliteDatabase.cpp:37:77:37:84 | password | sensitive information | +| CleartextSqliteDatabase.cpp:49:5:49:21 | call to sqlite3_bind_text | CleartextSqliteDatabase.cpp:49:32:49:39 | password | CleartextSqliteDatabase.cpp:49:32:49:39 | password | This SQLite call may store $@ in a non-encrypted SQLite database. | CleartextSqliteDatabase.cpp:49:32:49:39 | password | sensitive information | +| CleartextSqliteDatabase.cpp:56:5:56:23 | call to sqlite3_str_appendf | CleartextSqliteDatabase.cpp:56:76:56:83 | password | CleartextSqliteDatabase.cpp:56:76:56:83 | password | This SQLite call may store $@ in a non-encrypted SQLite database. | CleartextSqliteDatabase.cpp:56:76:56:83 | password | sensitive information | +edges +| CleartextSqliteDatabase.cpp:29:77:29:84 | password | CleartextSqliteDatabase.cpp:31:22:31:24 | *sql | provenance | TaintFunction | +| CleartextSqliteDatabase.cpp:37:77:37:84 | password | CleartextSqliteDatabase.cpp:39:28:39:30 | *sql | provenance | TaintFunction | +nodes +| CleartextSqliteDatabase.cpp:29:77:29:84 | password | semmle.label | password | +| CleartextSqliteDatabase.cpp:31:22:31:24 | *sql | semmle.label | *sql | +| CleartextSqliteDatabase.cpp:37:77:37:84 | password | semmle.label | password | +| CleartextSqliteDatabase.cpp:39:28:39:30 | *sql | semmle.label | *sql | +| CleartextSqliteDatabase.cpp:49:32:49:39 | password | semmle.label | password | +| CleartextSqliteDatabase.cpp:56:76:56:83 | password | semmle.label | password | +subpaths diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-313/CleartextSqliteDatabase.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-313/CleartextSqliteDatabase.qlref new file mode 100644 index 000000000000..d5adb06122dd --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-313/CleartextSqliteDatabase.qlref @@ -0,0 +1,4 @@ +query: Security/CWE/CWE-313/CleartextSqliteDatabase.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql