Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
owen-mc authored Nov 22, 2023
2 parents 9e5a80a + 98ddbe0 commit a130c0f
Show file tree
Hide file tree
Showing 1,886 changed files with 47,256 additions and 3,582 deletions.
2 changes: 2 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
/swift/ @github/codeql-swift
/misc/codegen/ @github/codeql-swift
/java/kotlin-extractor/ @github/codeql-kotlin
/java/ql/test-kotlin1/ @github/codeql-kotlin
/java/ql/test-kotlin2/ @github/codeql-kotlin

# ML-powered queries
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
Expand Down
2 changes: 1 addition & 1 deletion codeql-workspace.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
provide:
- "*/ql/src/qlpack.yml"
- "*/ql/lib/qlpack.yml"
- "*/ql/test/qlpack.yml"
- "*/ql/test*/qlpack.yml"
- "*/ql/examples/qlpack.yml"
- "*/ql/consistency-queries/qlpack.yml"
- "*/ql/automodel/src/qlpack.yml"
Expand Down
14 changes: 14 additions & 0 deletions cpp/ql/lib/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
## 0.12.0

### Breaking Changes

* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.

### Minor Analysis Improvements

* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
* Added models for `strlcpy` and `strlcat`.
* Added models for the `sprintf` variants from the `StrSafe.h` header.
* Added SQL API models for `ODBC`.
* Added taint models for `realloc` and related functions.

## 0.11.0

### Breaking Changes
Expand Down
4 changes: 0 additions & 4 deletions cpp/ql/lib/change-notes/2023-10-30-realloc-flow.md

This file was deleted.

This file was deleted.

4 changes: 0 additions & 4 deletions cpp/ql/lib/change-notes/2023-11-08-strsafe-models.md

This file was deleted.

4 changes: 0 additions & 4 deletions cpp/ql/lib/change-notes/2023-11-10-strlcpy-strlcat-models.md

This file was deleted.

13 changes: 13 additions & 0 deletions cpp/ql/lib/change-notes/released/0.12.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## 0.12.0

### Breaking Changes

* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.

### Minor Analysis Improvements

* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
* Added models for `strlcpy` and `strlcat`.
* Added models for the `sprintf` variants from the `StrSafe.h` header.
* Added SQL API models for `ODBC`.
* Added taint models for `realloc` and related functions.
2 changes: 1 addition & 1 deletion cpp/ql/lib/codeql-pack.release.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.11.0
lastReleaseVersion: 0.12.0
2 changes: 1 addition & 1 deletion cpp/ql/lib/qlpack.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.11.1-dev
version: 0.12.1-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,24 @@ class GlobalLikeVariable extends Variable {
}
}

/**
* Returns the smallest indirection for the type `t`.
*
* For most types this is `1`, but for `ArrayType`s (which are allocated on
* the stack) this is `0`
*/
int getMinIndirectionsForType(Type t) {
if t.getUnspecifiedType() instanceof Cpp::ArrayType then result = 0 else result = 1
}

private int getMinIndirectionForGlobalUse(Ssa::GlobalUse use) {
result = getMinIndirectionsForType(use.getUnspecifiedType())
}

private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
result = getMinIndirectionsForType(def.getUnspecifiedType())
}

/**
* Holds if data can flow from `node1` to `node2` in a way that loses the
* calling context. For example, this would happen with flow through a
Expand All @@ -656,7 +674,7 @@ predicate jumpStep(Node n1, Node n2) {
v = globalUse.getVariable() and
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
globalUse.getIndirection() = 1 and
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
v = n2.asVariable()
or
v = n2.asIndirectVariable(globalUse.getIndirection())
Expand All @@ -666,7 +684,7 @@ predicate jumpStep(Node n1, Node n2) {
v = globalDef.getVariable() and
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
globalDef.getIndirection() = 1 and
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
v = n1.asVariable()
or
v = n1.asIndirectVariable(globalDef.getIndirection())
Expand Down
94 changes: 78 additions & 16 deletions cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ cached
private newtype TIRDataFlowNode =
TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
TVariableNode(Variable var, int indirectionIndex) {
indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
indirectionIndex =
[getMinIndirectionsForType(var.getUnspecifiedType()) .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
} or
TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) {
indirectionIndex =
Expand Down Expand Up @@ -346,15 +347,17 @@ class Node extends TIRDataFlowNode {
* Gets the variable corresponding to this node, if any. This can be used for
* modeling flow in and out of global variables.
*/
Variable asVariable() { this = TVariableNode(result, 1) }
Variable asVariable() {
this = TVariableNode(result, getMinIndirectionsForType(result.getUnspecifiedType()))
}

/**
* Gets the `indirectionIndex`'th indirection of this node's underlying variable, if any.
*
* This can be used for modeling flow in and out of global variables.
*/
Variable asIndirectVariable(int indirectionIndex) {
indirectionIndex > 1 and
indirectionIndex > getMinIndirectionsForType(result.getUnspecifiedType()) and
this = TVariableNode(result, indirectionIndex)
}

Expand Down Expand Up @@ -1273,31 +1276,90 @@ abstract private class IndirectExprNodeBase extends Node {
}
}

private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
{
IndirectOperandIndirectExprNode() {
/** A signature for converting an indirect node to an expression. */
private signature module IndirectNodeToIndirectExprSig {
/** The indirect node class to be converted to an expression */
class IndirectNode;

/**
* Holds if the indirect expression at indirection index `indirectionIndex`
* of `node` is `e`. The integer `n` specifies how many conversions has been
* applied to `node`.
*/
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
}

/**
* A module that implements the logic for deciding whether an indirect node
* should be an `IndirectExprNode`.
*/
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
import Sig

/**
* This predicate shifts the indirection index by one when `conv` is a
* `ReferenceDereferenceExpr`.
*
* This is necessary because `ReferenceDereferenceExpr` is a conversion
* in the AST, but appears as a `LoadInstruction` in the IR.
*/
bindingset[e, indirectionIndex]
private predicate adjustForReference(
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
) {
conv.(ReferenceDereferenceExpr).getExpr() = e and
adjustedIndirectionIndex = indirectionIndex - 1
or
not conv instanceof ReferenceDereferenceExpr and
conv = e and
adjustedIndirectionIndex = indirectionIndex
}

/** Holds if `node` should be an `IndirectExprNode`. */
predicate charpred(IndirectNode node) {
exists(Expr e, int n, int indirectionIndex |
indirectExprNodeShouldBeIndirectOperand(this, e, n, indirectionIndex) and
not indirectExprNodeShouldBeIndirectOperand(_, e, n + 1, indirectionIndex)
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
not exists(Expr conv, int adjustedIndirectionIndex |
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
indirectNodeHasIndirectExpr(_, conv, n + 1, adjustedIndirectionIndex)
)
)
}
}

private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectOperand;

predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
}

module IndirectOperandToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;

private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
{
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }

final override Expr getConvertedExpr(int n, int index) {
indirectExprNodeShouldBeIndirectOperand(this, result, n, index)
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}

private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectInstruction;

predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
}

module IndirectInstructionToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;

private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
{
IndirectInstructionIndirectExprNode() {
exists(Expr e, int n, int indirectionIndex |
indirectExprNodeShouldBeIndirectInstruction(this, e, n, indirectionIndex) and
not indirectExprNodeShouldBeIndirectInstruction(_, e, n + 1, indirectionIndex)
)
}
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }

final override Expr getConvertedExpr(int n, int index) {
indirectExprNodeShouldBeIndirectInstruction(this, result, n, index)
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ private module SourceVariables {
then result = base.getType()
else result = getTypeImpl(base.getType(), ind - 1)
}

/** Gets the location of this variable. */
Location getLocation() { result = this.getBaseVariable().getLocation() }
}
}

Expand Down Expand Up @@ -869,7 +872,7 @@ private predicate sourceVariableIsGlobal(
)
}

private module SsaInput implements SsaImplCommon::InputSig {
private module SsaInput implements SsaImplCommon::InputSig<Location> {
import InputSigCommon
import SourceVariables

Expand Down Expand Up @@ -1092,7 +1095,7 @@ class Def extends DefOrUse {
predicate isCertain() { defOrUse.isCertain() }
}

private module SsaImpl = SsaImplCommon::Make<SsaInput>;
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;

class PhiNode extends SsaImpl::DefinitionExt {
PhiNode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,9 @@ abstract private class AbstractBaseSourceVariable extends TBaseSourceVariable {
/** Gets a textual representation of this element. */
abstract string toString();

/** Gets the location of this variable. */
abstract Location getLocation();

/** Gets the type of this base source variable. */
final DataFlowType getType() { this.getLanguageType().hasUnspecifiedType(result, _) }

Expand All @@ -395,6 +398,8 @@ class BaseIRVariable extends AbstractBaseSourceVariable, TBaseIRVariable {

override string toString() { result = var.toString() }

override Location getLocation() { result = var.getLocation() }

override CppType getLanguageType() { result = var.getLanguageType() }
}

Expand All @@ -407,6 +412,8 @@ class BaseCallVariable extends AbstractBaseSourceVariable, TBaseCallVariable {

override string toString() { result = call.toString() }

override Location getLocation() { result = call.getLocation() }

override CppType getLanguageType() { result = getResultLanguageType(call) }
}

Expand Down Expand Up @@ -872,7 +879,7 @@ private module Cached {
upper = countIndirectionsForCppType(type) and
ind = ind0 + [lower .. upper] and
indirectionIndex = ind - (ind0 + lower) and
(if type.hasType(any(Cpp::ArrayType arrayType), true) then lower = 0 else lower = 1)
lower = getMinIndirectionsForType(any(Type t | type.hasUnspecifiedType(t, _)))
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ private class FinalParameterUse extends UseImpl, TFinalParameterUse {
override predicate isCertain() { any() }
}

private module SsaInput implements SsaImplCommon::InputSig {
private module SsaInput implements SsaImplCommon::InputSig<Location> {
import InputSigCommon
import SourceVariables

Expand Down Expand Up @@ -335,7 +335,7 @@ class Def extends DefOrUse {
predicate isIteratorDef() { defOrUse instanceof IteratorDef }
}

private module SsaImpl = SsaImplCommon::Make<SsaInput>;
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;

class PhiNode extends SsaImpl::DefinitionExt {
PhiNode() {
Expand Down
6 changes: 6 additions & 0 deletions cpp/ql/src/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.8.3

### Minor Analysis Improvements

* The `cpp/uninitialized-local` query has been improved to produce fewer false positives.

## 0.8.2

No user-facing changes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,26 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }

override predicate isSource(Instruction source) {
// Holds if `source` is a node that represents the use of a stack variable
exists(VariableAddressInstruction var, Function func |
var = source and
func = source.getEnclosingFunction() and
var.getAstVariable() instanceof StackVariable and
// Pointer-to-member types aren't properly handled in the dbscheme.
not var.getResultType() instanceof PointerToMemberType and
exists(Function func |
// Rule out FPs caused by extraction errors.
not any(ErrorExpr e).getEnclosingFunction() = func and
not intentionallyReturnsStackPointer(func)
not intentionallyReturnsStackPointer(func) and
func = source.getEnclosingFunction()
|
// `source` is an instruction that represents the use of a stack variable
exists(VariableAddressInstruction var |
var = source and
var.getAstVariable() instanceof StackVariable and
// Pointer-to-member types aren't properly handled in the dbscheme.
not var.getResultType() instanceof PointerToMemberType
)
or
// `source` is an instruction that represents the return value of a
// function that is known to return stack-allocated memory.
exists(Call call |
call.getTarget().hasGlobalName(["alloca", "strdupa", "strndupa", "_alloca", "_malloca"]) and
source.getUnconvertedResultExpression() = call
)
)
}

Expand Down Expand Up @@ -85,10 +95,10 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
}

from
MustFlowPathNode source, MustFlowPathNode sink, VariableAddressInstruction var,
MustFlowPathNode source, MustFlowPathNode sink, Instruction instr,
ReturnStackAllocatedMemoryConfig conf
where
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
source.getInstruction() = var
source.getInstruction() = instr
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
var.getAst(), var.getAst().toString()
instr.getAst(), instr.getAst().toString()
Loading

0 comments on commit a130c0f

Please sign in to comment.