diff --git a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql index 54c6d1e7a966..59a93c9f1b2c 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql @@ -12,8 +12,12 @@ */ import cpp -import semmle.code.cpp.security.TaintTracking -import TaintedWithPath +import semmle.code.cpp.ir.dataflow.TaintTracking +import semmle.code.cpp.security.FlowSources +import semmle.code.cpp.controlflow.IRGuards +import semmle.code.cpp.ir.ValueNumbering +import DataFlow::PathGraph +import semmle.code.cpp.ir.IR /** * Holds if `alloc` is an allocation, and `tainted` is a child of it that is a @@ -25,21 +29,107 @@ predicate allocSink(Expr alloc, Expr tainted) { tainted.getUnspecifiedType() instanceof IntegralType } -class TaintedAllocationSizeConfiguration extends TaintTrackingConfiguration { - override predicate isSink(Element tainted) { allocSink(_, tainted) } +class TaintedAllocationSizeConfiguration extends TaintTracking::Configuration { + TaintedAllocationSizeConfiguration() { this = "TaintedAllocationSizeConfiguration" } + + override predicate isSource(DataFlow::Node source) { + source instanceof RemoteFlowSource or source instanceof LocalFlowSource + } + + override predicate isSink(DataFlow::Node sink) { allocSink(_, sink.asExpr()) } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + guard instanceof UpperBoundGuard + or + guard instanceof EqualityGuard + } + + override predicate isSanitizer(DataFlow::Node node) { + node.asInstruction() instanceof BoundedVariableRead + } +} + +class UpperBoundGuard extends DataFlow::BarrierGuard { + UpperBoundGuard() { this.comparesLt(_, _, _, _, _) } + + override predicate checks(Instruction i, boolean b) { this.comparesLt(i.getAUse(), _, _, _, b) } +} + +class EqualityGuard extends DataFlow::BarrierGuard { + EqualityGuard() { this.comparesEq(_, _, _, _, _) } + + override predicate checks(Instruction i, boolean b) { + this.comparesEq(i.getAUse(), _, _, true, b) + } +} + +private predicate readsVariable(LoadInstruction load, Variable var) { + load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var +} + +/** + * A variable that has any kind of upper-bound check anywhere in the program. This is + * biased towards being inclusive because there are a lot of valid ways of doing an + * upper bounds checks if we don't consider where it occurs, for example: + * ``` + * if (x < 10) { sink(x); } + * + * if (10 > y) { sink(y); } + * + * if (z > 10) { z = 10; } + * sink(z); + * ``` + */ +// TODO: This coarse overapproximation, ported from the old taint tracking +// library, could be replaced with an actual semantic check that a particular +// variable _access_ is guarded by an upper-bound check. We probably don't want +// to do this right away since it could expose a lot of FPs that were +// previously suppressed by this predicate by coincidence. +private predicate hasUpperBoundsCheck(Variable var) { + exists(RelationalOperation oper, VariableAccess access | + oper.getAnOperand() = access and + access.getTarget() = var and + // Comparing to 0 is not an upper bound check + not oper.getAnOperand().getValue() = "0" + ) +} + +/** + * A read of a variable that has an upper-bound check somewhere in the + * program. + */ +class BoundedVariableRead extends LoadInstruction { + BoundedVariableRead() { + exists(Variable checkedVar | + readsVariable(this, checkedVar) and + hasUpperBoundsCheck(checkedVar) + ) + } } predicate taintedAllocSize( - Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause + Expr source, Expr alloc, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode, + string taintCause ) { - isUserInput(source, taintCause) and - exists(Expr tainted | + exists(Expr tainted, DataFlow::Node rawSourceNode, TaintedAllocationSizeConfiguration config | allocSink(alloc, tainted) and - taintedWithPath(source, tainted, sourceNode, sinkNode) + ( + rawSourceNode.asExpr() = source or + rawSourceNode.asDefiningArgument() = source + ) and + sourceNode.getNode() = rawSourceNode and + config.hasFlowPath(sourceNode, sinkNode) and + tainted = sinkNode.getNode().(DataFlow::ExprNode).getConvertedExpr() and + ( + taintCause = rawSourceNode.(RemoteFlowSource).getSourceType() or + taintCause = rawSourceNode.(LocalFlowSource).getSourceType() + ) ) } -from Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause +from + Expr source, Expr alloc, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode, + string taintCause where taintedAllocSize(source, alloc, sourceNode, sinkNode, taintCause) select alloc, sourceNode, sinkNode, "This allocation size is derived from $@ and might overflow", source, "user input (" + taintCause + ")" diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll index d1cafb28f1c1..a779f4d170bf 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll @@ -18,7 +18,7 @@ Instruction callInput(CallInstruction call, FunctionInput input) { or // A value pointed to by a positional argument exists(ReadSideEffectInstruction read | - result = read and + result = read.getSideEffectOperand().getAnyDef() and read.getPrimaryInstruction() = call and input.isParameterDeref(read.getIndex()) ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index 2290bab05713..52650e3988c1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -67,6 +67,22 @@ private predicate localInstructionTaintStep(Instruction nodeFrom, Instruction no or t instanceof ArrayType ) + or + // Until we have from through indirections across calls, we'll take flow out + // of the parameter and into its indirection. + exists(IRFunction f, Parameter parameter | + nodeFrom = getInitializeParameter(f, parameter) and + nodeTo = getInitializeIndirection(f, parameter) + ) + or + // Until we have flow through indirections across calls, we'll take flow out + // of the indirection and into the argument. + // When we get proper flow through indirections across calls, this code can be + // moved to `adjusedSink` or possibly into the `DataFlow::ExprNode` class. + exists(ReadSideEffectInstruction read | + read.getAnOperand().(SideEffectOperand).getAnyDef() = nodeFrom and + read.getArgumentDef() = nodeTo + ) } /** @@ -135,3 +151,15 @@ predicate modeledInstructionTaintStep(Instruction instrIn, Instruction instrOut) modelMidIn.isParameter(indexMid) ) } + +pragma[noinline] +private InitializeIndirectionInstruction getInitializeIndirection(IRFunction f, Parameter p) { + result.getParameter() = p and + result.getEnclosingIRFunction() = f +} + +pragma[noinline] +private InitializeParameterInstruction getInitializeParameter(IRFunction f, Parameter p) { + result.getParameter() = p and + result.getEnclosingIRFunction() = f +} \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index 82ae1fdc4f0a..32b7b172efc9 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -1,6 +1,7 @@ private import implementations.Allocation private import implementations.Deallocation private import implementations.Fread +private import implementations.Getenv private import implementations.Gets private import implementations.IdentityFunction private import implementations.Inet diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll new file mode 100644 index 000000000000..764a7dab5dca --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll @@ -0,0 +1,22 @@ +/** + * Provides an implementation class modelling the POSIX function `getenv`. + */ +import cpp +import semmle.code.cpp.models.interfaces.FlowSource + +/** + * The POSIX function `getenv`. + */ +class Getenv extends LocalFlowFunction { + Getenv() { + this.hasGlobalName("getenv") + } + + override predicate hasLocalFlowSource (FunctionOutput output, string description) { + ( + output.isReturnValueDeref() or + output.isReturnValue() + ) and + description = "an environment variable" + } +} \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll index 2c9effaff7cb..8952d7499428 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll @@ -11,7 +11,7 @@ import FunctionInputsAndOutputs import semmle.code.cpp.models.Models /** - * A library function which returns data read from a network connection. + * A library function which returns data that may be read from a network connection. */ abstract class RemoteFlowFunction extends Function { /** @@ -19,3 +19,13 @@ abstract class RemoteFlowFunction extends Function { */ abstract predicate hasRemoteFlowSource(FunctionOutput output, string description); } + +/** + * A library function which returns data that is directly controlled by a user. + */ +abstract class LocalFlowFunction extends Function { + /** + * Holds if data described by `description` flows from `output` of a call to this function. + */ + abstract predicate hasLocalFlowSource(FunctionOutput output, string description); +} \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll index eff40572c025..ed4a31263bef 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll @@ -13,10 +13,16 @@ abstract class RemoteFlowSource extends DataFlow::Node { abstract string getSourceType(); } -private class TaintedReturnSource extends RemoteFlowSource { +/** A data flow source of local user input. */ +abstract class LocalFlowSource extends DataFlow::Node { +/** Gets a string that describes the type of this local flow source. */ + abstract string getSourceType(); +} + +private class RemoteReturnSource extends RemoteFlowSource { string sourceType; - TaintedReturnSource() { + RemoteReturnSource() { exists(RemoteFlowFunction func, CallInstruction instr, FunctionOutput output | asInstruction() = instr and instr.getStaticCallTarget() = func and @@ -28,10 +34,10 @@ private class TaintedReturnSource extends RemoteFlowSource { override string getSourceType() { result = sourceType } } -private class TaintedParameterSource extends RemoteFlowSource { +private class RemoteParameterSource extends RemoteFlowSource { string sourceType; - TaintedParameterSource() { + RemoteParameterSource() { exists(RemoteFlowFunction func, WriteSideEffectInstruction instr, FunctionOutput output | asInstruction() = instr and instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() = func and @@ -42,3 +48,45 @@ private class TaintedParameterSource extends RemoteFlowSource { override string getSourceType() { result = sourceType } } + +private class LocalReturnSource extends LocalFlowSource { + string sourceType; + + LocalReturnSource() { + exists(LocalFlowFunction func, CallInstruction instr, FunctionOutput output | + asInstruction() = instr and + instr.getStaticCallTarget() = func and + func.hasLocalFlowSource(output, sourceType) and + output.isReturnValue() + ) + } + + override string getSourceType() { result = sourceType } +} + +private class LocalParameterSource extends LocalFlowSource { + string sourceType; + + LocalParameterSource() { + exists(LocalFlowFunction func, WriteSideEffectInstruction instr, FunctionOutput output | + asInstruction() = instr and + instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() = func and + func.hasLocalFlowSource(output, sourceType) and + output.isParameterDeref(instr.getIndex()) + ) + } + + override string getSourceType() { result = sourceType } +} + +private class ArgvSource extends LocalFlowSource { + ArgvSource() { + exists(Parameter argv | + argv.hasName("argv") and + argv.getFunction().hasGlobalName("main") and + this.asExpr() = argv.getAnAccess() + ) + } + + override string getSourceType() { result = "a command line argument" } +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index fa0807f204e8..66d4589cad08 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -27,21 +27,14 @@ | taint.cpp:112:7:112:13 | taint.cpp:106:12:106:17 | IR only | | taint.cpp:130:7:130:9 | taint.cpp:127:8:127:13 | IR only | | taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only | -| taint.cpp:173:8:173:13 | taint.cpp:164:19:164:24 | AST only | -| taint.cpp:181:8:181:9 | taint.cpp:185:11:185:16 | AST only | -| taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only | | taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only | | taint.cpp:229:3:229:6 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:233:8:233:8 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:244:3:244:6 | taint.cpp:223:10:223:15 | AST only | -| taint.cpp:256:8:256:8 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:261:7:261:7 | taint.cpp:258:7:258:12 | AST only | | taint.cpp:351:7:351:7 | taint.cpp:330:6:330:11 | AST only | | taint.cpp:352:7:352:7 | taint.cpp:330:6:330:11 | AST only | -| taint.cpp:372:7:372:7 | taint.cpp:365:24:365:29 | AST only | -| taint.cpp:374:7:374:7 | taint.cpp:365:24:365:29 | AST only | -| taint.cpp:391:7:391:7 | taint.cpp:385:27:385:32 | AST only | | taint.cpp:423:7:423:7 | taint.cpp:422:14:422:19 | AST only | | taint.cpp:424:9:424:17 | taint.cpp:422:14:422:19 | AST only | | taint.cpp:429:7:429:7 | taint.cpp:428:13:428:18 | IR only | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected index 41176c5caa20..ae6c53e560e5 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected @@ -16,17 +16,25 @@ | taint.cpp:151:7:151:12 | call to select | taint.cpp:151:20:151:25 | call to source | | taint.cpp:167:8:167:13 | call to source | taint.cpp:167:8:167:13 | call to source | | taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source | +| taint.cpp:173:8:173:13 | array to pointer conversion | taint.cpp:164:19:164:24 | call to source | +| taint.cpp:181:8:181:9 | * ... | taint.cpp:185:11:185:16 | call to source | +| taint.cpp:195:7:195:7 | x | taint.cpp:192:23:192:28 | source | | taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source | | taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source | | taint.cpp:216:7:216:7 | y | taint.cpp:207:6:207:11 | call to source | | taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source | +| taint.cpp:256:8:256:8 | (reference dereference) | taint.cpp:223:10:223:15 | call to source | +| taint.cpp:256:8:256:8 | a | taint.cpp:223:10:223:15 | call to source | | taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source | | taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source | | taint.cpp:290:7:290:7 | x | taint.cpp:275:6:275:11 | call to source | | taint.cpp:291:7:291:7 | y | taint.cpp:275:6:275:11 | call to source | | taint.cpp:337:7:337:7 | t | taint.cpp:330:6:330:11 | call to source | | taint.cpp:350:7:350:7 | t | taint.cpp:330:6:330:11 | call to source | +| taint.cpp:372:7:372:7 | a | taint.cpp:365:24:365:29 | source | +| taint.cpp:374:7:374:7 | c | taint.cpp:365:24:365:29 | source | | taint.cpp:382:7:382:7 | a | taint.cpp:377:23:377:28 | source | +| taint.cpp:391:7:391:7 | a | taint.cpp:385:27:385:32 | source | | taint.cpp:429:7:429:7 | b | taint.cpp:428:13:428:18 | call to source | | taint.cpp:430:9:430:14 | member | taint.cpp:428:13:428:18 | call to source | | taint.cpp:465:7:465:7 | x | taint.cpp:462:6:462:11 | call to source | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index 8aa79b5bb6d9..40a4994a03ee 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -1,189 +1,104 @@ edges +| field_conflation.c:29:22:29:27 | call to getenv | field_conflation.c:30:10:30:25 | Chi | +| field_conflation.c:30:10:30:25 | Chi | field_conflation.c:36:15:36:17 | taint_array output argument | +| field_conflation.c:36:15:36:17 | taint_array output argument | field_conflation.c:37:10:37:13 | (unsigned long)... | +| field_conflation.c:36:15:36:17 | taint_array output argument | field_conflation.c:37:13:37:13 | x | +| field_conflation.c:36:15:36:17 | taint_array output argument | field_conflation.c:37:13:37:13 | x | +| field_conflation.c:37:13:37:13 | x | field_conflation.c:37:10:37:13 | (unsigned long)... | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | (size_t)... | -| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | (size_t)... | -| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | -| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | -| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | -| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | -| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | -| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | -| test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | -| test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | -| test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | | test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | | test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | (size_t)... | -| test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | (size_t)... | -| test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | | test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | -| test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | -| test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | -| test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | -| test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | | test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | -| test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | -| test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | -| test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | -| test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | +| test.cpp:75:25:75:29 | start | test.cpp:79:18:79:28 | ... - ... | +| test.cpp:75:38:75:40 | end | test.cpp:79:18:79:28 | ... - ... | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:100:17:100:22 | array to pointer conversion | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:101:17:101:22 | array to pointer conversion | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:101:25:101:39 | ... + ... | +| test.cpp:100:17:100:22 | array to pointer conversion | test.cpp:100:17:100:22 | processData1 output argument | +| test.cpp:100:17:100:22 | processData1 output argument | test.cpp:101:17:101:22 | array to pointer conversion | +| test.cpp:100:17:100:22 | processData1 output argument | test.cpp:101:25:101:39 | ... + ... | +| test.cpp:101:17:101:22 | array to pointer conversion | test.cpp:75:25:75:29 | start | +| test.cpp:101:25:101:39 | ... + ... | test.cpp:75:38:75:40 | end | | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | -| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | -| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:41 | ... * ... | -| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:41 | ... * ... | -| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... | | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... | -| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:27 | ... * ... | -| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:27 | ... * ... | -| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... | -| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... | -| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:28 | ... * ... | -| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:28 | ... * ... | -| test.cpp:201:9:201:42 | Store | test.cpp:231:9:231:24 | call to get_tainted_size | | test.cpp:201:9:201:42 | Store | test.cpp:231:9:231:24 | call to get_tainted_size | | test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:42 | Store | -| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:42 | Store | -| test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s | | test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s | | test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s | -| test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s | | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | (size_t)... | | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | -| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | | test.cpp:227:24:227:29 | call to getenv | test.cpp:235:11:235:20 | (size_t)... | | test.cpp:227:24:227:29 | call to getenv | test.cpp:237:10:237:19 | (size_t)... | -| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | (size_t)... | -| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size | -| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size | -| test.cpp:227:24:227:37 | (const char *)... | test.cpp:235:11:235:20 | (size_t)... | -| test.cpp:227:24:227:37 | (const char *)... | test.cpp:237:10:237:19 | (size_t)... | | test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s | | test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s | -| test.cpp:241:2:241:32 | Chi | test.cpp:279:17:279:20 | get_size output argument | -| test.cpp:241:2:241:32 | Chi | test.cpp:295:18:295:21 | get_size output argument | -| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi | -| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | -| test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | -| test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | -| test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | | test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | -| test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | -| test.cpp:309:19:309:32 | (const char *)... | test.cpp:314:10:314:27 | ... * ... | -| test.cpp:309:19:309:32 | (const char *)... | test.cpp:314:10:314:27 | ... * ... | nodes -| test.cpp:39:21:39:24 | argv | semmle.label | argv | +| field_conflation.c:29:22:29:27 | call to getenv | semmle.label | call to getenv | +| field_conflation.c:30:10:30:25 | Chi | semmle.label | Chi | +| field_conflation.c:36:15:36:17 | taint_array output argument | semmle.label | taint_array output argument | +| field_conflation.c:37:10:37:13 | (unsigned long)... | semmle.label | (unsigned long)... | +| field_conflation.c:37:13:37:13 | x | semmle.label | x | +| field_conflation.c:37:13:37:13 | x | semmle.label | x | | test.cpp:39:21:39:24 | argv | semmle.label | argv | | test.cpp:42:38:42:44 | (size_t)... | semmle.label | (size_t)... | -| test.cpp:42:38:42:44 | (size_t)... | semmle.label | (size_t)... | -| test.cpp:42:38:42:44 | tainted | semmle.label | tainted | | test.cpp:42:38:42:44 | tainted | semmle.label | tainted | -| test.cpp:42:38:42:44 | tainted | semmle.label | tainted | -| test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... | | test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... | -| test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... | -| test.cpp:45:38:45:63 | ... + ... | semmle.label | ... + ... | | test.cpp:45:38:45:63 | ... + ... | semmle.label | ... + ... | -| test.cpp:45:38:45:63 | ... + ... | semmle.label | ... + ... | -| test.cpp:48:32:48:35 | (size_t)... | semmle.label | (size_t)... | | test.cpp:48:32:48:35 | (size_t)... | semmle.label | (size_t)... | | test.cpp:48:32:48:35 | size | semmle.label | size | -| test.cpp:48:32:48:35 | size | semmle.label | size | -| test.cpp:48:32:48:35 | size | semmle.label | size | | test.cpp:49:26:49:29 | size | semmle.label | size | -| test.cpp:49:26:49:29 | size | semmle.label | size | -| test.cpp:49:26:49:29 | size | semmle.label | size | -| test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... | -| test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... | | test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... | +| test.cpp:75:25:75:29 | start | semmle.label | start | +| test.cpp:75:38:75:40 | end | semmle.label | end | +| test.cpp:79:18:79:28 | ... - ... | semmle.label | ... - ... | +| test.cpp:97:18:97:23 | fread output argument | semmle.label | fread output argument | +| test.cpp:100:17:100:22 | array to pointer conversion | semmle.label | array to pointer conversion | +| test.cpp:100:17:100:22 | processData1 output argument | semmle.label | processData1 output argument | +| test.cpp:101:17:101:22 | array to pointer conversion | semmle.label | array to pointer conversion | +| test.cpp:101:25:101:39 | ... + ... | semmle.label | ... + ... | | test.cpp:123:18:123:23 | call to getenv | semmle.label | call to getenv | -| test.cpp:123:18:123:31 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... | -| test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... | | test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... | | test.cpp:132:19:132:24 | call to getenv | semmle.label | call to getenv | -| test.cpp:132:19:132:32 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... | | test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:138:19:138:24 | call to getenv | semmle.label | call to getenv | -| test.cpp:138:19:138:32 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... | | test.cpp:201:9:201:42 | Store | semmle.label | Store | | test.cpp:201:14:201:19 | call to getenv | semmle.label | call to getenv | -| test.cpp:201:14:201:27 | (const char *)... | semmle.label | (const char *)... | | test.cpp:214:23:214:23 | s | semmle.label | s | | test.cpp:215:21:215:21 | s | semmle.label | s | -| test.cpp:215:21:215:21 | s | semmle.label | s | -| test.cpp:215:21:215:21 | s | semmle.label | s | | test.cpp:220:21:220:21 | s | semmle.label | s | | test.cpp:221:21:221:21 | s | semmle.label | s | -| test.cpp:221:21:221:21 | s | semmle.label | s | -| test.cpp:221:21:221:21 | s | semmle.label | s | | test.cpp:227:24:227:29 | call to getenv | semmle.label | call to getenv | -| test.cpp:227:24:227:37 | (const char *)... | semmle.label | (const char *)... | | test.cpp:229:9:229:18 | (size_t)... | semmle.label | (size_t)... | -| test.cpp:229:9:229:18 | (size_t)... | semmle.label | (size_t)... | -| test.cpp:229:9:229:18 | local_size | semmle.label | local_size | | test.cpp:229:9:229:18 | local_size | semmle.label | local_size | -| test.cpp:229:9:229:18 | local_size | semmle.label | local_size | -| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | -| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | | test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | | test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... | | test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... | -| test.cpp:241:2:241:32 | Chi | semmle.label | Chi | -| test.cpp:241:18:241:23 | call to getenv | semmle.label | call to getenv | -| test.cpp:241:18:241:31 | (const char *)... | semmle.label | (const char *)... | | test.cpp:249:20:249:25 | call to getenv | semmle.label | call to getenv | -| test.cpp:249:20:249:33 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | -| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | -| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:301:19:301:24 | call to getenv | semmle.label | call to getenv | -| test.cpp:301:19:301:32 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | | test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | | test.cpp:309:19:309:24 | call to getenv | semmle.label | call to getenv | -| test.cpp:309:19:309:32 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | | test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | #select -| test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:45:31:45:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:48:25:48:30 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:49:17:49:30 | new[] | test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:52:21:52:27 | call to realloc | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:127:17:127:22 | call to malloc | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:123:18:123:23 | call to getenv | user input (getenv) | -| test.cpp:134:3:134:8 | call to malloc | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:132:19:132:24 | call to getenv | user input (getenv) | -| test.cpp:142:4:142:9 | call to malloc | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:138:19:138:24 | call to getenv | user input (getenv) | -| test.cpp:215:14:215:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:215:21:215:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | -| test.cpp:221:14:221:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:221:21:221:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | -| test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | -| test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) | -| test.cpp:253:4:253:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | -| test.cpp:281:4:281:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:281:11:281:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | -| test.cpp:298:3:298:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:298:10:298:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | -| test.cpp:305:4:305:9 | call to malloc | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:301:19:301:24 | call to getenv | user input (getenv) | -| test.cpp:314:3:314:8 | call to malloc | test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:309:19:309:24 | call to getenv | user input (getenv) | +| field_conflation.c:37:3:37:8 | call to malloc | field_conflation.c:29:22:29:27 | call to getenv | field_conflation.c:37:13:37:13 | x | This allocation size is derived from $@ and might overflow | field_conflation.c:29:22:29:27 | call to getenv | user input (an environment variable) | +| test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (a command line argument) | +| test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (a command line argument) | +| test.cpp:45:31:45:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (a command line argument) | +| test.cpp:48:25:48:30 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (a command line argument) | +| test.cpp:49:17:49:30 | new[] | test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (a command line argument) | +| test.cpp:52:21:52:27 | call to realloc | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (a command line argument) | +| test.cpp:79:9:79:29 | new[] | test.cpp:97:18:97:23 | fread output argument | test.cpp:79:18:79:28 | ... - ... | This allocation size is derived from $@ and might overflow | test.cpp:97:18:97:23 | buffer | user input (String read by fread) | +| test.cpp:127:17:127:22 | call to malloc | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:123:18:123:23 | call to getenv | user input (an environment variable) | +| test.cpp:134:3:134:8 | call to malloc | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:132:19:132:24 | call to getenv | user input (an environment variable) | +| test.cpp:215:14:215:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:215:21:215:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (an environment variable) | +| test.cpp:221:14:221:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:221:21:221:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (an environment variable) | +| test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (an environment variable) | +| test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (an environment variable) | +| test.cpp:253:4:253:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (an environment variable) | +| test.cpp:305:4:305:9 | call to malloc | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:301:19:301:24 | call to getenv | user input (an environment variable) | +| test.cpp:314:3:314:8 | call to malloc | test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:309:19:309:24 | call to getenv | user input (an environment variable) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c index 9a69a420a796..baa0b7837856 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c @@ -8,7 +8,7 @@ struct XY { int y; }; -void taint_array(struct XY *xyp) { +void taint_field(struct XY *xyp) { int tainted = atoi(getenv("VAR")); xyp->y = tainted; } @@ -16,6 +16,23 @@ void taint_array(struct XY *xyp) { void test_conflated_fields3(void) { struct XY xy; xy.x = 4; - taint_array(&xy); + taint_field(&xy); malloc(xy.x); // not tainted } + +struct ContainsArray { + int arr[16]; + int x; +}; + +void taint_array(struct ContainsArray *ca, int offset) { + int tainted = atoi(getenv("VAR")); + memcpy(ca->arr + offset, &tainted, sizeof(int)); +} + +void test_conflated_fields4(int arbitrary) { + struct ContainsArray ca; + ca.x = 4; + taint_array(&ca, arbitrary); + malloc(ca.x); // not tainted [FALSE POSITIVE] +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp index 0683f7211e3d..943bc3b1214a 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp @@ -76,7 +76,7 @@ void processData2(char *start, char *end) { char *copy; - copy = new char[end - start]; // GOOD + copy = new char[end - start]; // GOOD [FALSE POSITIVE] // ...