Skip to content

Commit

Permalink
Moderize dataflow configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
jketema committed Dec 1, 2023
1 parent d74222a commit 6594237
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@
import cpp
import codingstandards.c.cert
import codingstandards.cpp.dataflow.DataFlow
import DataFlow::PathGraph
import NonArrayPointerToArrayIndexingExprFlow::PathGraph

/**
* A data-flow configuration that tracks flow from an `AddressOfExpr` of a variable
* of `PointerType` that is not also an `ArrayType` to a `PointerArithmeticOrArrayExpr`
*/
class NonArrayPointerToArrayIndexingExprConfig extends DataFlow::Configuration {
NonArrayPointerToArrayIndexingExprConfig() { this = "ArrayToArrayIndexConfig" }

override predicate isSource(DataFlow::Node source) {
module NonArrayPointerToArrayIndexingExprConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(AddressOfExpr ao, Type t |
source.asExpr() = ao and
not ao.getOperand() instanceof ArrayExpr and
Expand All @@ -35,15 +33,15 @@ class NonArrayPointerToArrayIndexingExprConfig extends DataFlow::Configuration {
)
}

override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(PointerArithmeticOrArrayExpr ae |
sink.asExpr() = ae.getPointerOperand() and
not sink.asExpr() instanceof Literal and
not ae.isNonPointerOperandZero()
)
}

override predicate isBarrierOut(DataFlow::Node node) {
predicate isBarrierOut(DataFlow::Node node) {
// the default interprocedural data-flow model flows through any field or array assignment
// expressions to the qualifier (array base, pointer dereferenced, or qualifier) instead of the
// individual element or field that the assignment modifies. this default behaviour causes
Expand All @@ -63,6 +61,9 @@ class NonArrayPointerToArrayIndexingExprConfig extends DataFlow::Configuration {
}
}

module NonArrayPointerToArrayIndexingExprFlow =
DataFlow::Global<NonArrayPointerToArrayIndexingExprConfig>;

class PointerArithmeticOrArrayExpr extends Expr {
Expr operand;

Expand Down Expand Up @@ -101,9 +102,11 @@ class PointerArithmeticOrArrayExpr extends Expr {
predicate isNonPointerOperandZero() { operand.(Literal).getValue().toInt() = 0 }
}

from DataFlow::PathNode source, DataFlow::PathNode sink
from
NonArrayPointerToArrayIndexingExprFlow::PathNode source,
NonArrayPointerToArrayIndexingExprFlow::PathNode sink
where
not isExcluded(sink.getNode().asExpr(),
InvalidMemory2Package::doNotUsePointerArithmeticOnNonArrayObjectPointersQuery()) and
any(NonArrayPointerToArrayIndexingExprConfig cfg).hasFlowPath(source, sink)
NonArrayPointerToArrayIndexingExprFlow::flowPath(source, sink)
select sink, source, sink, "Pointer arithmetic on non-array object pointer."
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import cpp
import codingstandards.c.cert
import codingstandards.c.Pointers
import codingstandards.cpp.dataflow.TaintTracking
import DataFlow::PathGraph
import ScaledIntegerPointerArithmeticFlow::PathGraph

/**
* An expression which invokes the `offsetof` macro or `__builtin_offsetof` operation.
Expand Down Expand Up @@ -69,12 +69,10 @@ class ScaledIntegerExpr extends Expr {
* A data-flow configuration modeling data-flow from a `ScaledIntegerExpr` to a
* `PointerArithmeticExpr` where the pointer does not point to a 1-byte type.
*/
class ScaledIntegerPointerArithmeticConfig extends DataFlow::Configuration {
ScaledIntegerPointerArithmeticConfig() { this = "ScaledIntegerPointerArithmeticConfig" }
module ScaledIntegerPointerArithmeticConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ScaledIntegerExpr }

override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ScaledIntegerExpr }

override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(PointerArithmeticExpr pa |
// exclude pointers to 1-byte types as they do not scale
pa.getPointer().getFullyConverted().getType().(DerivedType).getBaseType().getSize() != 1 and
Expand All @@ -83,9 +81,13 @@ class ScaledIntegerPointerArithmeticConfig extends DataFlow::Configuration {
}
}

from ScaledIntegerPointerArithmeticConfig config, DataFlow::PathNode src, DataFlow::PathNode sink
module ScaledIntegerPointerArithmeticFlow = DataFlow::Global<ScaledIntegerPointerArithmeticConfig>;

from
ScaledIntegerPointerArithmeticFlow::PathNode src,
ScaledIntegerPointerArithmeticFlow::PathNode sink
where
not isExcluded(sink.getNode().asExpr(),
Pointers2Package::doNotAddOrSubtractAScaledIntegerToAPointerQuery()) and
config.hasFlowPath(src, sink)
ScaledIntegerPointerArithmeticFlow::flowPath(src, sink)
select sink, src, sink, "Scaled integer used in pointer arithmetic."
16 changes: 8 additions & 8 deletions c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ import codingstandards.cpp.Concurrency
import codingstandards.cpp.dataflow.TaintTracking
import codingstandards.cpp.dataflow.DataFlow

class TssCreateToTssDeleteDataFlowConfiguration extends DataFlow::Configuration {
TssCreateToTssDeleteDataFlowConfiguration() { this = "TssCreateToTssDeleteDataFlowConfiguration" }

override predicate isSource(DataFlow::Node node) {
module TssCreateToTssDeleteConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
exists(TSSCreateFunctionCall tsc, Expr e |
// the only requirement of the source is that at some point
// it refers to the key of a create statement
Expand All @@ -30,7 +28,7 @@ class TssCreateToTssDeleteDataFlowConfiguration extends DataFlow::Configuration
)
}

override predicate isSink(DataFlow::Node node) {
predicate isSink(DataFlow::Node node) {
exists(TSSDeleteFunctionCall tsd, Expr e |
// the only requirement of a sink is that at some point
// it references the key of a delete call.
Expand All @@ -40,15 +38,17 @@ class TssCreateToTssDeleteDataFlowConfiguration extends DataFlow::Configuration
}
}

module TssCreateToTssDeleteFlow = DataFlow::Global<TssCreateToTssDeleteConfig>;

from TSSCreateFunctionCall tcfc
where
not isExcluded(tcfc, Concurrency4Package::cleanUpThreadSpecificStorageQuery()) and
// all calls to `tss_create` must be bookended by calls to tss_delete
// even if a thread is not created.
not exists(TssCreateToTssDeleteDataFlowConfiguration config |
config.hasFlow(DataFlow::definitionByReferenceNodeFromArgument(tcfc.getKey()), _)
not (
TssCreateToTssDeleteFlow::flow(DataFlow::definitionByReferenceNodeFromArgument(tcfc.getKey()), _)
or
config.hasFlow(DataFlow::exprNode(tcfc.getKey()), _)
TssCreateToTssDeleteFlow::flow(DataFlow::exprNode(tcfc.getKey()), _)
)
or
// if a thread is created, we must check additional items
Expand Down

0 comments on commit 6594237

Please sign in to comment.