mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
Merge pull request #20073 from d10c/d10c/diff-informed-phase-3-cpp
C++: Diff-informed queries: phase 3 (non-trivial locations)
This commit is contained in:
@@ -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>;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user