mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge branch 'main' into redsun82/cargo-upgrade-2
This commit is contained in:
@@ -14,6 +14,9 @@ import semmle.code.cpp.ConfigurationTestFile
|
||||
from GlobalVariable gv
|
||||
where
|
||||
gv.getName().length() <= 3 and
|
||||
// We will give an alert for the TemplateVariable, so we don't
|
||||
// need to also give one for each instantiation
|
||||
not gv instanceof VariableTemplateInstantiation and
|
||||
not gv.isStatic() and
|
||||
not gv.getFile() instanceof ConfigurationTestFile // variables in files generated during configuration are likely false positives
|
||||
select gv,
|
||||
|
||||
@@ -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<OverflowDestinationConfig>;
|
||||
|
||||
@@ -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<NonConstFlowConfig>;
|
||||
|
||||
@@ -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<LeapYearCheckConfig>;
|
||||
@@ -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 =
|
||||
|
||||
@@ -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<TaintedPathConfig>;
|
||||
|
||||
@@ -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<ExecTaintConfig>;
|
||||
|
||||
@@ -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<Config>;
|
||||
|
||||
@@ -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<SqlTaintedConfig>;
|
||||
|
||||
@@ -124,6 +124,12 @@ module Config implements DataFlow::ConfigSig {
|
||||
// Block flow if the node is guarded by any <, <= or = operations.
|
||||
node = DataFlow::BarrierGuard<lessThanOrEqual/3>::getABarrierNode()
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(BufferWrite bw | result = bw.getLocation() | isSink(sink, bw, _))
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
@@ -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<Config>;
|
||||
|
||||
@@ -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<Config>;
|
||||
|
||||
@@ -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<UncontrolledArithConfig>;
|
||||
|
||||
@@ -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<Config>;
|
||||
|
||||
@@ -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<TaintedAllocationSizeConfig>;
|
||||
|
||||
@@ -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<Config>;
|
||||
|
||||
@@ -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<VerifyResultConfig>;
|
||||
|
||||
@@ -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<ToBufferConfig>;
|
||||
|
||||
@@ -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<FromSensitiveConfig>;
|
||||
|
||||
@@ -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<FromSensitiveConfig>;
|
||||
@@ -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<ToEncryptionConfig>;
|
||||
@@ -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<FromEncryptionConfig>;
|
||||
|
||||
@@ -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<FromSensitiveConfig>;
|
||||
|
||||
@@ -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<HttpStringToUrlOpenConfig>;
|
||||
|
||||
@@ -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<KeyStrengthFlowConfig>;
|
||||
|
||||
@@ -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<Config>;
|
||||
|
||||
@@ -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<NullAppNameCreateProcessFunctionConfig>;
|
||||
@@ -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 =
|
||||
|
||||
@@ -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<NullDaclConfig>;
|
||||
@@ -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<NonNullDaclConfig>;
|
||||
|
||||
@@ -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<Config>;
|
||||
|
||||
@@ -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<Config>;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/short-global-name` query will no longer give alerts for instantiations of template variables, only for the template itself.
|
||||
@@ -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<ArrayAddressToDerefConfig>;
|
||||
|
||||
@@ -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<DecompressionTaintConfig>;
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
| main.cpp:3:5:3:5 | x | Poor global variable name 'x'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
|
||||
| main.cpp:4:5:4:6 | ys | Poor global variable name 'ys'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
|
||||
| main.cpp:9:5:9:6 | v1 | Poor global variable name 'v1'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
|
||||
| main.cpp:10:5:10:6 | v2 | Poor global variable name 'v2'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
|
||||
| main.cpp:12:5:12:5 | v3 | Poor global variable name 'v3'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
|
||||
| main.cpp:14:5:14:5 | v4 | Poor global variable name 'v4'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
|
||||
| main.cpp:16:5:16:5 | v5 | Poor global variable name 'v5'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo). |
|
||||
|
||||
@@ -5,3 +5,19 @@ int ys[1000000]; // BAD: too short
|
||||
int descriptive_name; // GOOD: sufficient
|
||||
|
||||
static int z; // GOOD: not a global
|
||||
|
||||
int v1; // BAD: too short
|
||||
int v2; // BAD: too short
|
||||
template <typename T>
|
||||
T v3; // BAD: too short
|
||||
template <typename T>
|
||||
T v4; // BAD: too short
|
||||
template <typename T>
|
||||
T v5; // BAD: too short
|
||||
|
||||
void use_some_fs() {
|
||||
v2 = 100;
|
||||
v4<int> = 200;
|
||||
v5<int> = 300;
|
||||
v5<const char *> = "string";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
query: Security/CWE/CWE-313/CleartextSqliteDatabase.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* Added library models for the relevant method calls under `jakarta.servlet.ServletRequest` and `jakarta.servlet.http.HttpServletRequest` as remote flow sources.
|
||||
@@ -4,3 +4,15 @@ extensions:
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", True, "getServletPath", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getHeader", "(String)", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getHeaderNames", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getHeaders", "(String)", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getParameter", "(String)", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getParameterMap", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getParameterNames", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getParameterValues", "(String)", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getPathInfo", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getQueryString", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getRemoteUser", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getRequestURI", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet.http", "HttpServletRequest", False, "getRequestURL", "()", "", "ReturnValue", "remote", "manual"]
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["jakarta.servlet", "ServletRequest", False, "getInputStream", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet", "ServletRequest", False, "getParameter", "(String)", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet", "ServletRequest", False, "getParameterMap", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet", "ServletRequest", False, "getParameterNames", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet", "ServletRequest", False, "getParameterValues", "(String)", "", "ReturnValue", "remote", "manual"]
|
||||
- ["jakarta.servlet", "ServletRequest", False, "getReader", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: sinkModel
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Improved modeling of command-line argument parsing libraries [arg](https://www.npmjs.com/package/arg), [args](https://www.npmjs.com/package/args), [command-line-args](https://www.npmjs.com/package/command-line-args) and [commander](https://www.npmjs.com/package/commander)
|
||||
@@ -87,11 +87,43 @@ private class ArgsParseStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::CallNode call |
|
||||
call = DataFlow::moduleMember("args", "parse").getACall() or
|
||||
call = DataFlow::moduleImport(["yargs-parser", "minimist", "subarg"]).getACall()
|
||||
call =
|
||||
DataFlow::moduleImport(["yargs-parser", "minimist", "subarg", "yargs/yargs", "yargs"])
|
||||
.getACall()
|
||||
|
|
||||
succ = call and
|
||||
pred = call.getArgument(0)
|
||||
)
|
||||
or
|
||||
exists(API::Node commanderNode | commanderNode = commander() |
|
||||
pred = commanderNode.getMember(["parse", "parseAsync"]).getACall().getAnArgument() and
|
||||
succ =
|
||||
[
|
||||
commanderNode.getMember("opts").getACall(), commanderNode.getAMember().asSource(),
|
||||
commander()
|
||||
.getMember("action")
|
||||
.getACall()
|
||||
.getArgument(0)
|
||||
.(DataFlow::FunctionNode)
|
||||
.getAParameter()
|
||||
]
|
||||
)
|
||||
or
|
||||
exists(DataFlow::MethodCallNode methodCall | methodCall = yargs() |
|
||||
pred = methodCall.getReceiver() and
|
||||
succ = methodCall
|
||||
)
|
||||
or
|
||||
exists(DataFlow::CallNode call, DataFlow::Node options |
|
||||
call = DataFlow::moduleImport(["arg", "command-line-args"]).getACall() and
|
||||
succ = call and
|
||||
options = call.getArgument(1) and
|
||||
exists(DataFlow::PropWrite write |
|
||||
write.getBase() = options and
|
||||
write.getPropertyName() = "argv" and
|
||||
pred = write.getRhs()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +147,9 @@ private API::Node commander() {
|
||||
* Either directly imported as a module, or through some chained method call.
|
||||
*/
|
||||
private DataFlow::SourceNode yargs() {
|
||||
result = DataFlow::moduleImport("yargs")
|
||||
result = DataFlow::moduleImport(["yargs", "yargs/yargs"])
|
||||
or
|
||||
result = DataFlow::moduleImport(["yargs", "yargs/yargs"]).getACall()
|
||||
or
|
||||
// script used to generate list of chained methods: https://gist.github.com/erik-krogh/f8afe952c0577f4b563a993e613269ba
|
||||
exists(string method |
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import javascript
|
||||
private import codeql.threatmodels.ThreatModels
|
||||
|
||||
module RegExpInjection {
|
||||
/**
|
||||
@@ -32,19 +33,32 @@ module RegExpInjection {
|
||||
|
||||
/**
|
||||
* An active threat-model source, considered as a flow source.
|
||||
* Excludes environment variables by default - they require the "environment" threat model.
|
||||
*/
|
||||
private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource {
|
||||
ActiveThreatModelSourceAsSource() { not this.isClientSideSource() }
|
||||
ActiveThreatModelSourceAsSource() {
|
||||
not this.isClientSideSource() and
|
||||
not this.(ThreatModelSource).getThreatModel() = "environment"
|
||||
}
|
||||
}
|
||||
|
||||
private import IndirectCommandInjectionCustomizations
|
||||
/**
|
||||
* Environment variables as a source when the "environment" threat model is active.
|
||||
*/
|
||||
private class EnvironmentVariableAsSource extends Source instanceof ThreatModelSource {
|
||||
EnvironmentVariableAsSource() {
|
||||
this.getThreatModel() = "environment" and
|
||||
currentThreatModel("environment")
|
||||
}
|
||||
|
||||
override string describe() { result = "environment variable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A read of `process.env`, `process.argv`, and similar, considered as a flow source for regular
|
||||
* expression injection.
|
||||
* Command line arguments as a source for regular expression injection.
|
||||
*/
|
||||
class ArgvAsSource extends Source instanceof IndirectCommandInjection::Source {
|
||||
override string describe() { result = IndirectCommandInjection::Source.super.describe() }
|
||||
private class CommandLineArgumentAsSource extends Source instanceof CommandLineArguments {
|
||||
override string describe() { result = "command-line argument" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `js/regex-injection` query no longer considers environment variables as sources by default. Environment variables can be re-enabled as sources by setting the threat model to include the "environment" category.
|
||||
@@ -21,6 +21,12 @@
|
||||
| child_process-test.js:75:29:75:31 | cmd | child_process-test.js:73:25:73:31 | req.url | child_process-test.js:75:29:75:31 | cmd | This command line depends on a $@. | child_process-test.js:73:25:73:31 | req.url | user-provided value |
|
||||
| child_process-test.js:83:19:83:36 | req.query.fileName | child_process-test.js:83:19:83:36 | req.query.fileName | child_process-test.js:83:19:83:36 | req.query.fileName | This command line depends on a $@. | child_process-test.js:83:19:83:36 | req.query.fileName | user-provided value |
|
||||
| child_process-test.js:94:11:94:35 | "ping " ... ms.host | child_process-test.js:94:21:94:30 | ctx.params | child_process-test.js:94:11:94:35 | "ping " ... ms.host | This command line depends on a $@. | child_process-test.js:94:21:94:30 | ctx.params | user-provided value |
|
||||
| command-line-libs.js:14:8:14:18 | options.cmd | command-line-libs.js:9:16:9:23 | req.body | command-line-libs.js:14:8:14:18 | options.cmd | This command line depends on a $@. | command-line-libs.js:9:16:9:23 | req.body | user-provided value |
|
||||
| command-line-libs.js:15:8:15:18 | program.cmd | command-line-libs.js:9:16:9:23 | req.body | command-line-libs.js:15:8:15:18 | program.cmd | This command line depends on a $@. | command-line-libs.js:9:16:9:23 | req.body | user-provided value |
|
||||
| command-line-libs.js:21:12:21:17 | script | command-line-libs.js:9:16:9:23 | req.body | command-line-libs.js:21:12:21:17 | script | This command line depends on a $@. | command-line-libs.js:9:16:9:23 | req.body | user-provided value |
|
||||
| command-line-libs.js:29:10:29:24 | parsed['--cmd'] | command-line-libs.js:27:23:27:30 | req.body | command-line-libs.js:29:10:29:24 | parsed['--cmd'] | This command line depends on a $@. | command-line-libs.js:27:23:27:30 | req.body | user-provided value |
|
||||
| command-line-libs.js:37:8:37:18 | options.cmd | command-line-libs.js:35:62:35:69 | req.body | command-line-libs.js:37:8:37:18 | options.cmd | This command line depends on a $@. | command-line-libs.js:35:62:35:69 | req.body | user-provided value |
|
||||
| command-line-libs.js:49:8:49:17 | parsed.cmd | command-line-libs.js:42:16:42:23 | req.body | command-line-libs.js:49:8:49:17 | parsed.cmd | This command line depends on a $@. | command-line-libs.js:42:16:42:23 | req.body | user-provided value |
|
||||
| exec-sh2.js:10:12:10:57 | cp.spaw ... ptions) | exec-sh2.js:14:25:14:31 | req.url | exec-sh2.js:10:40:10:46 | command | This command line depends on a $@. | exec-sh2.js:14:25:14:31 | req.url | user-provided value |
|
||||
| exec-sh.js:15:12:15:61 | cp.spaw ... ptions) | exec-sh.js:19:25:19:31 | req.url | exec-sh.js:15:44:15:50 | command | This command line depends on a $@. | exec-sh.js:19:25:19:31 | req.url | user-provided value |
|
||||
| execSeries.js:14:41:14:47 | command | execSeries.js:18:34:18:40 | req.url | execSeries.js:14:41:14:47 | command | This command line depends on a $@. | execSeries.js:18:34:18:40 | req.url | user-provided value |
|
||||
@@ -116,6 +122,35 @@ edges
|
||||
| child_process-test.js:73:15:73:38 | url.par ... , true) | child_process-test.js:73:9:73:49 | cmd | provenance | |
|
||||
| child_process-test.js:73:25:73:31 | req.url | child_process-test.js:73:15:73:38 | url.par ... , true) | provenance | |
|
||||
| child_process-test.js:94:21:94:30 | ctx.params | child_process-test.js:94:11:94:35 | "ping " ... ms.host | provenance | |
|
||||
| command-line-libs.js:9:9:9:34 | args | command-line-libs.js:12:17:12:20 | args | provenance | |
|
||||
| command-line-libs.js:9:9:9:34 | args | command-line-libs.js:23:29:23:32 | args | provenance | |
|
||||
| command-line-libs.js:9:16:9:23 | req.body | command-line-libs.js:9:9:9:34 | args | provenance | |
|
||||
| command-line-libs.js:12:17:12:20 | args | command-line-libs.js:13:19:13:32 | program.opts() | provenance | |
|
||||
| command-line-libs.js:12:17:12:20 | args | command-line-libs.js:15:8:15:18 | program.cmd | provenance | |
|
||||
| command-line-libs.js:12:17:12:20 | args | command-line-libs.js:20:14:20:19 | script | provenance | |
|
||||
| command-line-libs.js:13:9:13:32 | options | command-line-libs.js:14:8:14:14 | options | provenance | |
|
||||
| command-line-libs.js:13:19:13:32 | program.opts() | command-line-libs.js:13:9:13:32 | options | provenance | |
|
||||
| command-line-libs.js:14:8:14:14 | options | command-line-libs.js:14:8:14:18 | options.cmd | provenance | |
|
||||
| command-line-libs.js:20:14:20:19 | script | command-line-libs.js:21:12:21:17 | script | provenance | |
|
||||
| command-line-libs.js:23:29:23:32 | args | command-line-libs.js:20:14:20:19 | script | provenance | |
|
||||
| command-line-libs.js:27:11:27:41 | argsArray | command-line-libs.js:28:53:28:61 | argsArray | provenance | |
|
||||
| command-line-libs.js:27:23:27:30 | req.body | command-line-libs.js:27:11:27:41 | argsArray | provenance | |
|
||||
| command-line-libs.js:28:11:28:64 | parsed | command-line-libs.js:29:10:29:15 | parsed | provenance | |
|
||||
| command-line-libs.js:28:20:28:64 | arg({ ' ... rray }) | command-line-libs.js:28:11:28:64 | parsed | provenance | |
|
||||
| command-line-libs.js:28:53:28:61 | argsArray | command-line-libs.js:28:20:28:64 | arg({ ' ... rray }) | provenance | |
|
||||
| command-line-libs.js:29:10:29:15 | parsed | command-line-libs.js:29:10:29:24 | parsed['--cmd'] | provenance | |
|
||||
| command-line-libs.js:35:9:35:83 | options | command-line-libs.js:37:8:37:14 | options | provenance | |
|
||||
| command-line-libs.js:35:19:35:83 | command ... \| [] }) | command-line-libs.js:35:9:35:83 | options | provenance | |
|
||||
| command-line-libs.js:35:62:35:69 | req.body | command-line-libs.js:35:19:35:83 | command ... \| [] }) | provenance | |
|
||||
| command-line-libs.js:37:8:37:14 | options | command-line-libs.js:37:8:37:18 | options.cmd | provenance | |
|
||||
| command-line-libs.js:42:9:42:34 | args | command-line-libs.js:43:24:43:27 | args | provenance | |
|
||||
| command-line-libs.js:42:16:42:23 | req.body | command-line-libs.js:42:9:42:34 | args | provenance | |
|
||||
| command-line-libs.js:43:9:47:12 | parsed | command-line-libs.js:49:8:49:13 | parsed | provenance | |
|
||||
| command-line-libs.js:43:18:43:28 | yargs(args) | command-line-libs.js:43:18:47:4 | yargs(a ... ue\\n }) | provenance | |
|
||||
| command-line-libs.js:43:18:47:4 | yargs(a ... ue\\n }) | command-line-libs.js:43:18:47:12 | yargs(a ... parse() | provenance | |
|
||||
| command-line-libs.js:43:18:47:12 | yargs(a ... parse() | command-line-libs.js:43:9:47:12 | parsed | provenance | |
|
||||
| command-line-libs.js:43:24:43:27 | args | command-line-libs.js:43:18:43:28 | yargs(args) | provenance | |
|
||||
| command-line-libs.js:49:8:49:13 | parsed | command-line-libs.js:49:8:49:17 | parsed.cmd | provenance | |
|
||||
| exec-sh2.js:9:17:9:23 | command | exec-sh2.js:10:40:10:46 | command | provenance | |
|
||||
| exec-sh2.js:14:9:14:49 | cmd | exec-sh2.js:15:12:15:14 | cmd | provenance | |
|
||||
| exec-sh2.js:14:15:14:38 | url.par ... , true) | exec-sh2.js:14:9:14:49 | cmd | provenance | |
|
||||
@@ -269,6 +304,38 @@ nodes
|
||||
| child_process-test.js:83:19:83:36 | req.query.fileName | semmle.label | req.query.fileName |
|
||||
| child_process-test.js:94:11:94:35 | "ping " ... ms.host | semmle.label | "ping " ... ms.host |
|
||||
| child_process-test.js:94:21:94:30 | ctx.params | semmle.label | ctx.params |
|
||||
| command-line-libs.js:9:9:9:34 | args | semmle.label | args |
|
||||
| command-line-libs.js:9:16:9:23 | req.body | semmle.label | req.body |
|
||||
| command-line-libs.js:12:17:12:20 | args | semmle.label | args |
|
||||
| command-line-libs.js:13:9:13:32 | options | semmle.label | options |
|
||||
| command-line-libs.js:13:19:13:32 | program.opts() | semmle.label | program.opts() |
|
||||
| command-line-libs.js:14:8:14:14 | options | semmle.label | options |
|
||||
| command-line-libs.js:14:8:14:18 | options.cmd | semmle.label | options.cmd |
|
||||
| command-line-libs.js:15:8:15:18 | program.cmd | semmle.label | program.cmd |
|
||||
| command-line-libs.js:20:14:20:19 | script | semmle.label | script |
|
||||
| command-line-libs.js:21:12:21:17 | script | semmle.label | script |
|
||||
| command-line-libs.js:23:29:23:32 | args | semmle.label | args |
|
||||
| command-line-libs.js:27:11:27:41 | argsArray | semmle.label | argsArray |
|
||||
| command-line-libs.js:27:23:27:30 | req.body | semmle.label | req.body |
|
||||
| command-line-libs.js:28:11:28:64 | parsed | semmle.label | parsed |
|
||||
| command-line-libs.js:28:20:28:64 | arg({ ' ... rray }) | semmle.label | arg({ ' ... rray }) |
|
||||
| command-line-libs.js:28:53:28:61 | argsArray | semmle.label | argsArray |
|
||||
| command-line-libs.js:29:10:29:15 | parsed | semmle.label | parsed |
|
||||
| command-line-libs.js:29:10:29:24 | parsed['--cmd'] | semmle.label | parsed['--cmd'] |
|
||||
| command-line-libs.js:35:9:35:83 | options | semmle.label | options |
|
||||
| command-line-libs.js:35:19:35:83 | command ... \| [] }) | semmle.label | command ... \| [] }) |
|
||||
| command-line-libs.js:35:62:35:69 | req.body | semmle.label | req.body |
|
||||
| command-line-libs.js:37:8:37:14 | options | semmle.label | options |
|
||||
| command-line-libs.js:37:8:37:18 | options.cmd | semmle.label | options.cmd |
|
||||
| command-line-libs.js:42:9:42:34 | args | semmle.label | args |
|
||||
| command-line-libs.js:42:16:42:23 | req.body | semmle.label | req.body |
|
||||
| command-line-libs.js:43:9:47:12 | parsed | semmle.label | parsed |
|
||||
| command-line-libs.js:43:18:43:28 | yargs(args) | semmle.label | yargs(args) |
|
||||
| command-line-libs.js:43:18:47:4 | yargs(a ... ue\\n }) | semmle.label | yargs(a ... ue\\n }) |
|
||||
| command-line-libs.js:43:18:47:12 | yargs(a ... parse() | semmle.label | yargs(a ... parse() |
|
||||
| command-line-libs.js:43:24:43:27 | args | semmle.label | args |
|
||||
| command-line-libs.js:49:8:49:13 | parsed | semmle.label | parsed |
|
||||
| command-line-libs.js:49:8:49:17 | parsed.cmd | semmle.label | parsed.cmd |
|
||||
| exec-sh2.js:9:17:9:23 | command | semmle.label | command |
|
||||
| exec-sh2.js:10:40:10:46 | command | semmle.label | command |
|
||||
| exec-sh2.js:14:9:14:49 | cmd | semmle.label | cmd |
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import express from 'express';
|
||||
import { Command } from 'commander';
|
||||
import { exec } from 'child_process';
|
||||
import arg from 'arg';
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
app.post('/Command', async (req, res) => {
|
||||
const args = req.body.args || []; // $ Source
|
||||
const program = new Command();
|
||||
program.option('--cmd <value>', 'Command to execute');
|
||||
program.parse(args, { from: 'user' });
|
||||
const options = program.opts();
|
||||
exec(options.cmd); // $ Alert
|
||||
exec(program.cmd); // $ Alert
|
||||
|
||||
const program1 = new Command();
|
||||
program1
|
||||
.command('run <script>')
|
||||
.action((script) => {
|
||||
exec(script); // $ Alert
|
||||
});
|
||||
await program1.parseAsync(args);
|
||||
});
|
||||
|
||||
app.post('/arg', (req, res) => {
|
||||
const argsArray = req.body.args || []; // $ Source
|
||||
const parsed = arg({ '--cmd': String }, { argv: argsArray });
|
||||
exec(parsed['--cmd']); // $ Alert
|
||||
});
|
||||
|
||||
app.post('/commandLineArgs', (req, res) => {
|
||||
const commandLineArgs = require('command-line-args');
|
||||
const optionDefinitions = [{ name: 'cmd', type: String }];
|
||||
const options = commandLineArgs(optionDefinitions, { argv: req.body.args || [] }); // $ Source
|
||||
if (!options.cmd) return res.status(400).send({ error: 'Missing --cmd' });
|
||||
exec(options.cmd); // $ Alert
|
||||
});
|
||||
|
||||
app.post('/yargs', (req, res) => {
|
||||
const yargs = require('yargs/yargs');
|
||||
const args = req.body.args || []; // $ Source
|
||||
const parsed = yargs(args).option('cmd', {
|
||||
type: 'string',
|
||||
describe: 'Command to execute',
|
||||
demandOption: true
|
||||
}).parse();
|
||||
|
||||
exec(parsed.cmd); // $ Alert
|
||||
});
|
||||
@@ -14,7 +14,6 @@
|
||||
| RegExpInjection.js:49:14:49:52 | key.spl ... in("-") | RegExpInjection.js:5:13:5:28 | req.param("key") | RegExpInjection.js:49:14:49:52 | key.spl ... in("-") | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value |
|
||||
| RegExpInjection.js:59:14:59:18 | input | RegExpInjection.js:55:39:55:56 | req.param("input") | RegExpInjection.js:59:14:59:18 | input | This regular expression is constructed from a $@. | RegExpInjection.js:55:39:55:56 | req.param("input") | user-provided value |
|
||||
| RegExpInjection.js:82:14:82:55 | "^.*\\.( ... + ")$" | RegExpInjection.js:77:15:77:32 | req.param("input") | RegExpInjection.js:82:14:82:55 | "^.*\\.( ... + ")$" | This regular expression is constructed from a $@. | RegExpInjection.js:77:15:77:32 | req.param("input") | user-provided value |
|
||||
| RegExpInjection.js:86:16:86:50 | `^${pro ... r.app$` | RegExpInjection.js:86:20:86:30 | process.env | RegExpInjection.js:86:16:86:50 | `^${pro ... r.app$` | This regular expression is constructed from a $@. | RegExpInjection.js:86:20:86:30 | process.env | environment variable |
|
||||
| RegExpInjection.js:88:16:88:49 | `^${pro ... r.app$` | RegExpInjection.js:88:20:88:31 | process.argv | RegExpInjection.js:88:16:88:49 | `^${pro ... r.app$` | This regular expression is constructed from a $@. | RegExpInjection.js:88:20:88:31 | process.argv | command-line argument |
|
||||
| RegExpInjection.js:95:14:95:22 | sanitized | RegExpInjection.js:92:15:92:32 | req.param("input") | RegExpInjection.js:95:14:95:22 | sanitized | This regular expression is constructed from a $@. | RegExpInjection.js:92:15:92:32 | req.param("input") | user-provided value |
|
||||
| tst.js:6:16:6:35 | "^"+ data.name + "$" | tst.js:5:16:5:29 | req.query.data | tst.js:6:16:6:35 | "^"+ data.name + "$" | This regular expression is constructed from a $@. | tst.js:5:16:5:29 | req.query.data | user-provided value |
|
||||
@@ -57,7 +56,6 @@ edges
|
||||
| RegExpInjection.js:77:15:77:32 | req.param("input") | RegExpInjection.js:77:7:77:32 | input | provenance | |
|
||||
| RegExpInjection.js:82:25:82:29 | input | RegExpInjection.js:82:25:82:48 | input.r ... g, "\|") | provenance | |
|
||||
| RegExpInjection.js:82:25:82:48 | input.r ... g, "\|") | RegExpInjection.js:82:14:82:55 | "^.*\\.( ... + ")$" | provenance | |
|
||||
| RegExpInjection.js:86:20:86:30 | process.env | RegExpInjection.js:86:16:86:50 | `^${pro ... r.app$` | provenance | |
|
||||
| RegExpInjection.js:88:20:88:31 | process.argv | RegExpInjection.js:88:16:88:49 | `^${pro ... r.app$` | provenance | |
|
||||
| RegExpInjection.js:92:7:92:32 | input | RegExpInjection.js:94:19:94:23 | input | provenance | |
|
||||
| RegExpInjection.js:92:15:92:32 | req.param("input") | RegExpInjection.js:92:7:92:32 | input | provenance | |
|
||||
@@ -109,8 +107,6 @@ nodes
|
||||
| RegExpInjection.js:82:14:82:55 | "^.*\\.( ... + ")$" | semmle.label | "^.*\\.( ... + ")$" |
|
||||
| RegExpInjection.js:82:25:82:29 | input | semmle.label | input |
|
||||
| RegExpInjection.js:82:25:82:48 | input.r ... g, "\|") | semmle.label | input.r ... g, "\|") |
|
||||
| RegExpInjection.js:86:16:86:50 | `^${pro ... r.app$` | semmle.label | `^${pro ... r.app$` |
|
||||
| RegExpInjection.js:86:20:86:30 | process.env | semmle.label | process.env |
|
||||
| RegExpInjection.js:88:16:88:49 | `^${pro ... r.app$` | semmle.label | `^${pro ... r.app$` |
|
||||
| RegExpInjection.js:88:20:88:31 | process.argv | semmle.label | process.argv |
|
||||
| RegExpInjection.js:92:7:92:32 | input | semmle.label | input |
|
||||
@@ -83,7 +83,7 @@ app.get('/has-sanitizer', function(req, res) {
|
||||
});
|
||||
|
||||
app.get("argv", function(req, res) {
|
||||
new RegExp(`^${process.env.HOME}/Foo/bar.app$`); // $ Alert[js/regex-injection]
|
||||
new RegExp(`^${process.env.HOME}/Foo/bar.app$`); // environment variable, should be detected only with threat model enabled.
|
||||
|
||||
new RegExp(`^${process.argv[1]}/Foo/bar.app$`); // $ Alert[js/regex-injection]
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
#select
|
||||
| RegExpInjection.js:6:14:6:48 | `^${pro ... r.app$` | RegExpInjection.js:6:18:6:28 | process.env | RegExpInjection.js:6:14:6:48 | `^${pro ... r.app$` | This regular expression is constructed from a $@. | RegExpInjection.js:6:18:6:28 | process.env | environment variable |
|
||||
| RegExpInjection.js:8:14:8:40 | `^${pro ... }/bin$` | RegExpInjection.js:8:18:8:28 | process.env | RegExpInjection.js:8:14:8:40 | `^${pro ... }/bin$` | This regular expression is constructed from a $@. | RegExpInjection.js:8:18:8:28 | process.env | environment variable |
|
||||
| RegExpInjection.js:11:14:11:19 | envVar | RegExpInjection.js:10:16:10:26 | process.env | RegExpInjection.js:11:14:11:19 | envVar | This regular expression is constructed from a $@. | RegExpInjection.js:10:16:10:26 | process.env | environment variable |
|
||||
| RegExpInjection.js:14:14:14:47 | `^${pro ... r.app$` | RegExpInjection.js:14:18:14:29 | process.argv | RegExpInjection.js:14:14:14:47 | `^${pro ... r.app$` | This regular expression is constructed from a $@. | RegExpInjection.js:14:18:14:29 | process.argv | command-line argument |
|
||||
| RegExpInjection.js:17:14:17:17 | argv | RegExpInjection.js:16:14:16:25 | process.argv | RegExpInjection.js:17:14:17:17 | argv | This regular expression is constructed from a $@. | RegExpInjection.js:16:14:16:25 | process.argv | command-line argument |
|
||||
| RegExpInjection.js:21:14:21:22 | userInput | RegExpInjection.js:20:19:20:36 | req.param("input") | RegExpInjection.js:21:14:21:22 | userInput | This regular expression is constructed from a $@. | RegExpInjection.js:20:19:20:36 | req.param("input") | user-provided value |
|
||||
edges
|
||||
| RegExpInjection.js:6:18:6:28 | process.env | RegExpInjection.js:6:14:6:48 | `^${pro ... r.app$` | provenance | |
|
||||
| RegExpInjection.js:8:18:8:28 | process.env | RegExpInjection.js:8:14:8:40 | `^${pro ... }/bin$` | provenance | |
|
||||
| RegExpInjection.js:10:7:10:35 | envVar | RegExpInjection.js:11:14:11:19 | envVar | provenance | |
|
||||
| RegExpInjection.js:10:16:10:26 | process.env | RegExpInjection.js:10:7:10:35 | envVar | provenance | |
|
||||
| RegExpInjection.js:14:18:14:29 | process.argv | RegExpInjection.js:14:14:14:47 | `^${pro ... r.app$` | provenance | |
|
||||
| RegExpInjection.js:16:7:16:28 | argv | RegExpInjection.js:17:14:17:17 | argv | provenance | |
|
||||
| RegExpInjection.js:16:14:16:25 | process.argv | RegExpInjection.js:16:7:16:28 | argv | provenance | |
|
||||
| RegExpInjection.js:20:7:20:36 | userInput | RegExpInjection.js:21:14:21:22 | userInput | provenance | |
|
||||
| RegExpInjection.js:20:19:20:36 | req.param("input") | RegExpInjection.js:20:7:20:36 | userInput | provenance | |
|
||||
nodes
|
||||
| RegExpInjection.js:6:14:6:48 | `^${pro ... r.app$` | semmle.label | `^${pro ... r.app$` |
|
||||
| RegExpInjection.js:6:18:6:28 | process.env | semmle.label | process.env |
|
||||
| RegExpInjection.js:8:14:8:40 | `^${pro ... }/bin$` | semmle.label | `^${pro ... }/bin$` |
|
||||
| RegExpInjection.js:8:18:8:28 | process.env | semmle.label | process.env |
|
||||
| RegExpInjection.js:10:7:10:35 | envVar | semmle.label | envVar |
|
||||
| RegExpInjection.js:10:16:10:26 | process.env | semmle.label | process.env |
|
||||
| RegExpInjection.js:11:14:11:19 | envVar | semmle.label | envVar |
|
||||
| RegExpInjection.js:14:14:14:47 | `^${pro ... r.app$` | semmle.label | `^${pro ... r.app$` |
|
||||
| RegExpInjection.js:14:18:14:29 | process.argv | semmle.label | process.argv |
|
||||
| RegExpInjection.js:16:7:16:28 | argv | semmle.label | argv |
|
||||
| RegExpInjection.js:16:14:16:25 | process.argv | semmle.label | process.argv |
|
||||
| RegExpInjection.js:17:14:17:17 | argv | semmle.label | argv |
|
||||
| RegExpInjection.js:20:7:20:36 | userInput | semmle.label | userInput |
|
||||
| RegExpInjection.js:20:19:20:36 | req.param("input") | semmle.label | req.param("input") |
|
||||
| RegExpInjection.js:21:14:21:22 | userInput | semmle.label | userInput |
|
||||
subpaths
|
||||
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/threat-models
|
||||
extensible: threatModelConfiguration
|
||||
data:
|
||||
- ["environment", true, 0]
|
||||
@@ -0,0 +1,22 @@
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
|
||||
app.get('/test-environment', function(req, res) {
|
||||
// Environment variables should be detected when "environment" threat model is enabled
|
||||
new RegExp(`^${process.env.HOME}/Foo/bar.app$`); // $ Alert[js/regex-injection]
|
||||
|
||||
new RegExp(`^${process.env.PATH}/bin$`); // $ Alert[js/regex-injection]
|
||||
|
||||
var envVar = process.env.NODE_ENV; // $ Source[js/regex-injection]
|
||||
new RegExp(envVar); // $ Alert[js/regex-injection]
|
||||
|
||||
// Command line arguments should still be detected
|
||||
new RegExp(`^${process.argv[1]}/Foo/bar.app$`); // $ Alert[js/regex-injection]
|
||||
|
||||
var argv = process.argv[2]; // $ Source[js/regex-injection]
|
||||
new RegExp(argv); // $ Alert[js/regex-injection]
|
||||
|
||||
// Regular user input should still be detected
|
||||
var userInput = req.param("input"); // $ Source[js/regex-injection]
|
||||
new RegExp(userInput); // $ Alert[js/regex-injection]
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
query: Security/CWE-730/RegExpInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -26,6 +26,8 @@ private module PossibleTimingAttackAgainstHashConfig implements DataFlow::Config
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ProduceCryptoCall }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof NonConstantTimeComparisonSink }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
}
|
||||
|
||||
module PossibleTimingAttackAgainstHashFlow =
|
||||
@@ -38,4 +40,4 @@ from
|
||||
PossibleTimingAttackAgainstHashFlow::PathNode sink
|
||||
where PossibleTimingAttackAgainstHashFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Possible Timing attack against $@ validation.",
|
||||
source.getNode().(ProduceCryptoCall).getResultType(), "message"
|
||||
source.getNode(), source.getNode().(ProduceCryptoCall).getResultType() + " message"
|
||||
|
||||
@@ -25,6 +25,8 @@ private module TimingAttackAgainstHashConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ProduceCryptoCall }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof NonConstantTimeComparisonSink }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
}
|
||||
|
||||
module TimingAttackAgainstHashFlow = TaintTracking::Global<TimingAttackAgainstHashConfig>;
|
||||
@@ -35,5 +37,5 @@ from TimingAttackAgainstHashFlow::PathNode source, TimingAttackAgainstHashFlow::
|
||||
where
|
||||
TimingAttackAgainstHashFlow::flowPath(source, sink) and
|
||||
sink.getNode().(NonConstantTimeComparisonSink).includesUserInput()
|
||||
select sink.getNode(), source, sink, "Timing attack against $@ validation.",
|
||||
source.getNode().(ProduceCryptoCall).getResultType(), "message"
|
||||
select sink.getNode(), source, sink, "Timing attack against $@ validation.", source.getNode(),
|
||||
source.getNode().(ProduceCryptoCall).getResultType() + " message"
|
||||
|
||||
@@ -10,5 +10,5 @@ nodes
|
||||
| TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | semmle.label | ControlFlowNode for sign() |
|
||||
subpaths
|
||||
#select
|
||||
| TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | Possible Timing attack against $@ validation. | signature | message |
|
||||
| TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | Possible Timing attack against $@ validation. | MAC | message |
|
||||
| TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | Possible Timing attack against $@ validation. | TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | signature message |
|
||||
| TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | Possible Timing attack against $@ validation. | TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | MAC message |
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
edges
|
||||
| TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | provenance | |
|
||||
| TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | provenance | |
|
||||
| TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | provenance | |
|
||||
nodes
|
||||
| TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | semmle.label | ControlFlowNode for signature |
|
||||
| TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | semmle.label | ControlFlowNode for signature |
|
||||
| TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | semmle.label | ControlFlowNode for sign() |
|
||||
subpaths
|
||||
#select
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.ql
|
||||
@@ -53,6 +53,7 @@ private predicate letElsePanic(BlockExpr be) {
|
||||
*/
|
||||
query predicate deadEnd(CfgImpl::Node node) {
|
||||
Consistency::deadEnd(node) and
|
||||
successfullyExtractedFile(node.getLocation().getFile()) and
|
||||
not letElsePanic(node.getAstNode())
|
||||
}
|
||||
|
||||
|
||||
@@ -619,7 +619,7 @@ module PatternTrees {
|
||||
(
|
||||
StandardPatTree.super.succ(pred, succ, c)
|
||||
or
|
||||
pred = this and first(this.getFirstChildNode(), succ) and completionIsValidFor(c, this)
|
||||
pred = this and first(this.getFirstChildTree(), succ) and completionIsValidFor(c, this)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ final class CfgScope = CfgScopeImpl;
|
||||
|
||||
final class AsyncBlockScope extends CfgScopeImpl, AsyncBlockExpr instanceof ExprTrees::AsyncBlockExprTree
|
||||
{
|
||||
override predicate scopeFirst(AstNode first) { first(super.getFirstChildNode(), first) }
|
||||
override predicate scopeFirst(AstNode first) { first(super.getFirstChildTree(), first) }
|
||||
|
||||
override predicate scopeLast(AstNode last, Completion c) {
|
||||
last(super.getLastChildElement(), last, c)
|
||||
last(super.getLastChildTree(), last, c)
|
||||
or
|
||||
last(super.getChildNode(_), last, c) and
|
||||
not c instanceof NormalCompletion
|
||||
@@ -48,7 +48,7 @@ final class CallableScope extends CfgScopeImpl, Callable {
|
||||
}
|
||||
|
||||
override predicate scopeFirst(AstNode first) {
|
||||
first(this.(CallableScopeTree).getFirstChildNode(), first)
|
||||
first(this.(CallableScopeTree).getFirstChildTree(), first)
|
||||
}
|
||||
|
||||
/** Holds if `scope` is exited when `last` finishes with completion `c`. */
|
||||
|
||||
@@ -23,14 +23,18 @@ module Impl {
|
||||
* ```
|
||||
*/
|
||||
class ImplTraitTypeRepr extends Generated::ImplTraitTypeRepr {
|
||||
/** Gets the function for which this impl trait type occurs, if any. */
|
||||
Function getFunction() {
|
||||
this.getParentNode*() = [result.getRetType().getTypeRepr(), result.getAParam().getTypeRepr()]
|
||||
pragma[nomagic]
|
||||
private TypeRepr getFunctionTypeRepr(Function f) {
|
||||
this.getParentNode*() = result and
|
||||
result = [f.getRetType().getTypeRepr(), f.getAParam().getTypeRepr()]
|
||||
}
|
||||
|
||||
/** Gets the function for which this impl trait type occurs, if any. */
|
||||
Function getFunction() { exists(this.getFunctionTypeRepr(result)) }
|
||||
|
||||
/** Holds if this impl trait type occurs in the return type of a function. */
|
||||
predicate isInReturnPos() {
|
||||
this.getParentNode*() = this.getFunction().getRetType().getTypeRepr()
|
||||
exists(Function f | f.getRetType().getTypeRepr() = this.getFunctionTypeRepr(f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2519,7 +2519,7 @@ pub mod pattern_matching_experimental {
|
||||
}
|
||||
|
||||
pub mod exec {
|
||||
// a *greatly* simplified model of `MySqlConnection.execute` in SQLX
|
||||
// a highly simplified model of `MySqlConnection.execute` in SQLx
|
||||
|
||||
trait Connection {}
|
||||
|
||||
@@ -2555,6 +2555,54 @@ pub mod exec {
|
||||
}
|
||||
}
|
||||
|
||||
pub mod path_buf {
|
||||
// a highly simplified model of `PathBuf::canonicalize`
|
||||
|
||||
pub struct Path {
|
||||
}
|
||||
|
||||
impl Path {
|
||||
pub const fn new() -> Path {
|
||||
Path { }
|
||||
}
|
||||
|
||||
pub fn canonicalize(&self) -> Result<PathBuf, ()> {
|
||||
Ok(PathBuf::new()) // $ target=new
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PathBuf {
|
||||
}
|
||||
|
||||
impl PathBuf {
|
||||
pub const fn new() -> PathBuf {
|
||||
PathBuf { }
|
||||
}
|
||||
}
|
||||
|
||||
// `PathBuf` provides `canonicalize` via `Deref`:
|
||||
impl std::ops::Deref for PathBuf {
|
||||
type Target = Path;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Path {
|
||||
// (very much not a real implementation)
|
||||
static path : Path = Path::new(); // $ target=new
|
||||
&path
|
||||
}
|
||||
}
|
||||
|
||||
pub fn f() {
|
||||
let path1 = Path::new(); // $ target=new type=path1:Path
|
||||
let path2 = path1.canonicalize(); // $ target=canonicalize
|
||||
let path3 = path2.unwrap(); // $ target=unwrap type=path3:PathBuf
|
||||
|
||||
let pathbuf1 = PathBuf::new(); // $ target=new type=pathbuf1:PathBuf
|
||||
let pathbuf2 = pathbuf1.canonicalize(); // $ MISSING: target=canonicalize
|
||||
let pathbuf3 = pathbuf2.unwrap(); // $ MISSING: target=unwrap type=pathbuf3:PathBuf
|
||||
}
|
||||
}
|
||||
|
||||
mod closure;
|
||||
mod dereference;
|
||||
mod dyn_type;
|
||||
@@ -2587,6 +2635,7 @@ fn main() {
|
||||
method_determined_by_argument_type::f(); // $ target=f
|
||||
tuples::f(); // $ target=f
|
||||
exec::f(); // $ target=f
|
||||
path_buf::f(); // $ target=f
|
||||
dereference::test(); // $ target=test
|
||||
pattern_matching::test_all_patterns(); // $ target=test_all_patterns
|
||||
pattern_matching_experimental::box_patterns(); // $ target=box_patterns
|
||||
|
||||
@@ -4950,11 +4950,49 @@ inferType
|
||||
| main.rs:2554:44:2554:44 | c | | main.rs:2541:5:2541:29 | MySqlConnection |
|
||||
| main.rs:2554:47:2554:67 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
|
||||
| main.rs:2554:47:2554:67 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
|
||||
| main.rs:2564:5:2564:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2565:5:2565:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2565:20:2565:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2565:41:2565:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2581:5:2581:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future |
|
||||
| main.rs:2565:36:2567:9 | { ... } | | main.rs:2561:5:2562:5 | Path |
|
||||
| main.rs:2566:13:2566:20 | Path {...} | | main.rs:2561:5:2562:5 | Path |
|
||||
| main.rs:2569:29:2569:33 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:2569:29:2569:33 | SelfParam | &T | main.rs:2561:5:2562:5 | Path |
|
||||
| main.rs:2569:59:2571:9 | { ... } | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2569:59:2571:9 | { ... } | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2569:59:2571:9 | { ... } | T | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2570:13:2570:30 | Ok(...) | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2570:13:2570:30 | Ok(...) | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2570:13:2570:30 | Ok(...) | T | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2570:16:2570:29 | ...::new(...) | | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2578:39:2580:9 | { ... } | | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2579:13:2579:23 | PathBuf {...} | | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2588:18:2588:22 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:2588:18:2588:22 | SelfParam | &T | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2588:34:2592:9 | { ... } | | file://:0:0:0:0 | & |
|
||||
| main.rs:2588:34:2592:9 | { ... } | &T | main.rs:2561:5:2562:5 | Path |
|
||||
| main.rs:2590:34:2590:44 | ...::new(...) | | main.rs:2561:5:2562:5 | Path |
|
||||
| main.rs:2591:13:2591:17 | &path | | file://:0:0:0:0 | & |
|
||||
| main.rs:2591:13:2591:17 | &path | &T | main.rs:2561:5:2562:5 | Path |
|
||||
| main.rs:2591:14:2591:17 | path | | main.rs:2561:5:2562:5 | Path |
|
||||
| main.rs:2596:13:2596:17 | path1 | | main.rs:2561:5:2562:5 | Path |
|
||||
| main.rs:2596:21:2596:31 | ...::new(...) | | main.rs:2561:5:2562:5 | Path |
|
||||
| main.rs:2597:13:2597:17 | path2 | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2597:13:2597:17 | path2 | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2597:13:2597:17 | path2 | T | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2597:21:2597:25 | path1 | | main.rs:2561:5:2562:5 | Path |
|
||||
| main.rs:2597:21:2597:40 | path1.canonicalize() | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2597:21:2597:40 | path1.canonicalize() | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2597:21:2597:40 | path1.canonicalize() | T | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2598:13:2598:17 | path3 | | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2598:21:2598:25 | path2 | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2598:21:2598:25 | path2 | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2598:21:2598:25 | path2 | T | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2598:21:2598:34 | path2.unwrap() | | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2600:13:2600:20 | pathbuf1 | | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2600:24:2600:37 | ...::new(...) | | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2601:24:2601:31 | pathbuf1 | | main.rs:2574:5:2575:5 | PathBuf |
|
||||
| main.rs:2612:5:2612:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2613:5:2613:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2613:20:2613:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2613:41:2613:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2629:5:2629:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future |
|
||||
| pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option |
|
||||
| pattern_matching.rs:13:26:133:1 | { ... } | T | file://:0:0:0:0 | () |
|
||||
| pattern_matching.rs:14:9:14:13 | value | | {EXTERNAL LOCATION} | Option |
|
||||
|
||||
@@ -261,32 +261,44 @@ module MakeWithSplitting<
|
||||
/** Gets the `i`th child element, in order of evaluation. */
|
||||
abstract AstNode getChildNode(int i);
|
||||
|
||||
private AstNode getChildNodeRanked(int i) {
|
||||
result = rank[i + 1](AstNode child, int j | child = this.getChildNode(j) | child order by j)
|
||||
private ControlFlowTree getChildTreeRanked(int i) {
|
||||
result =
|
||||
rank[i + 1](ControlFlowTree child, int j | child = this.getChildNode(j) | child order by j)
|
||||
}
|
||||
|
||||
/** Gets the first child node of this element. */
|
||||
final AstNode getFirstChildNode() { result = this.getChildNodeRanked(0) }
|
||||
deprecated final AstNode getFirstChildNode() { result = this.getChildTreeRanked(0) }
|
||||
|
||||
/** Gets the first child node of this element. */
|
||||
final ControlFlowTree getFirstChildTree() { result = this.getChildTreeRanked(0) }
|
||||
|
||||
/** Gets the last child node of this node. */
|
||||
final AstNode getLastChildElement() {
|
||||
deprecated final AstNode getLastChildElement() {
|
||||
exists(int last |
|
||||
result = this.getChildNodeRanked(last) and
|
||||
not exists(this.getChildNodeRanked(last + 1))
|
||||
result = this.getChildTreeRanked(last) and
|
||||
not exists(this.getChildTreeRanked(last + 1))
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the last child node of this node. */
|
||||
final ControlFlowTree getLastChildTree() {
|
||||
exists(int last |
|
||||
result = this.getChildTreeRanked(last) and
|
||||
not exists(this.getChildTreeRanked(last + 1))
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this element has no children. */
|
||||
predicate isLeafElement() { not exists(this.getFirstChildNode()) }
|
||||
predicate isLeafElement() { not exists(this.getFirstChildTree()) }
|
||||
|
||||
override predicate propagatesAbnormal(AstNode child) { child = this.getChildNode(_) }
|
||||
|
||||
pragma[nomagic]
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
exists(int i |
|
||||
last(this.getChildNodeRanked(i), pred, c) and
|
||||
last(this.getChildTreeRanked(i), pred, c) and
|
||||
completionIsNormal(c) and
|
||||
first(this.getChildNodeRanked(i + 1), succ)
|
||||
first(this.getChildTreeRanked(i + 1), succ)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -294,7 +306,7 @@ module MakeWithSplitting<
|
||||
/** A standard element that is executed in pre-order. */
|
||||
abstract class StandardPreOrderTree extends StandardTree, PreOrderTree {
|
||||
override predicate last(AstNode last, Completion c) {
|
||||
last(this.getLastChildElement(), last, c)
|
||||
last(this.getLastChildTree(), last, c)
|
||||
or
|
||||
this.isLeafElement() and
|
||||
completionIsValidFor(c, this) and
|
||||
@@ -305,7 +317,7 @@ module MakeWithSplitting<
|
||||
StandardTree.super.succ(pred, succ, c)
|
||||
or
|
||||
pred = this and
|
||||
first(this.getFirstChildNode(), succ) and
|
||||
first(this.getFirstChildTree(), succ) and
|
||||
completionIsSimple(c)
|
||||
}
|
||||
}
|
||||
@@ -313,16 +325,16 @@ module MakeWithSplitting<
|
||||
/** A standard element that is executed in post-order. */
|
||||
abstract class StandardPostOrderTree extends StandardTree, PostOrderTree {
|
||||
override predicate first(AstNode first) {
|
||||
first(this.getFirstChildNode(), first)
|
||||
first(this.getFirstChildTree(), first)
|
||||
or
|
||||
not exists(this.getFirstChildNode()) and
|
||||
not exists(this.getFirstChildTree()) and
|
||||
first = this
|
||||
}
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
StandardTree.super.succ(pred, succ, c)
|
||||
or
|
||||
last(this.getLastChildElement(), pred, c) and
|
||||
last(this.getLastChildTree(), pred, c) and
|
||||
succ = this and
|
||||
completionIsNormal(c)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user