Skip to content

Commit 9190b10

Browse files
authored
Merge branch 'main' into post-release-prep/codeql-cli-2.16.2
2 parents 7a2332c + e596862 commit 9190b10

File tree

105 files changed

+11686
-2523
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+11686
-2523
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* Added an abstract class `FlowOutBarrierFunction` that can be used to block flow out of a function.

cpp/ql/lib/semmle/code/cpp/exprs/Assignment.qll

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,15 @@ class ConditionDeclExpr extends Expr, @condition_decl {
244244

245245
/**
246246
* Gets the compiler-generated variable access that conceptually occurs after
247-
* the initialization of the declared variable.
247+
* the initialization of the declared variable, if any.
248248
*/
249-
VariableAccess getVariableAccess() { result = this.getChild(0) }
249+
VariableAccess getVariableAccess() { result = this.getExpr() }
250+
251+
/**
252+
* Gets the expression that is evaluated after the initialization of the declared
253+
* variable.
254+
*/
255+
Expr getExpr() { result = this.getChild(0) }
250256

251257
/**
252258
* Gets the expression that initializes the declared variable. This predicate

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ private import codeql.ssa.Ssa as SsaImplCommon
22
private import semmle.code.cpp.ir.IR
33
private import DataFlowUtil
44
private import DataFlowImplCommon as DataFlowImplCommon
5+
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
56
private import semmle.code.cpp.models.interfaces.Allocation as Alloc
67
private import semmle.code.cpp.models.interfaces.DataFlow as DataFlow
8+
private import semmle.code.cpp.models.interfaces.FlowOutBarrier as FOB
9+
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as FIO
710
private import semmle.code.cpp.ir.internal.IRCppLanguage
811
private import DataFlowPrivate
912
private import ssa0.SsaInternals as SsaInternals0
@@ -784,10 +787,30 @@ private Node getAPriorDefinition(SsaDefOrUse defOrUse) {
784787
)
785788
}
786789

790+
/**
791+
* Holds if there should not be use-use flow out of `n` (or a conversion that
792+
* flows to `n`).
793+
*/
794+
private predicate modeledFlowBarrier(Node n) {
795+
exists(FIO::FunctionInput input, CallInstruction call |
796+
call.getStaticCallTarget().(FOB::FlowOutBarrierFunction).isFlowOutBarrier(input) and
797+
n = callInput(call, input)
798+
)
799+
or
800+
exists(Operand operand, Instruction instr, Node n0, int indirectionIndex |
801+
modeledFlowBarrier(n0) and
802+
nodeHasInstruction(n0, instr, indirectionIndex) and
803+
conversionFlow(operand, instr, false, _) and
804+
nodeHasOperand(n, operand, indirectionIndex)
805+
)
806+
}
807+
787808
/** Holds if there is def-use or use-use flow from `nodeFrom` to `nodeTo`. */
788809
predicate ssaFlow(Node nodeFrom, Node nodeTo) {
789810
exists(Node nFrom, boolean uncertain, SsaDefOrUse defOrUse |
790-
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain) and nodeFrom != nodeTo
811+
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain) and
812+
not modeledFlowBarrier(nFrom) and
813+
nodeFrom != nodeTo
791814
|
792815
if uncertain = true then nodeFrom = [nFrom, getAPriorDefinition(defOrUse)] else nodeFrom = nFrom
793816
)

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,13 +2125,6 @@ class ChiInstruction extends Instruction {
21252125
*/
21262126
final Instruction getPartial() { result = this.getPartialOperand().getDef() }
21272127

2128-
/**
2129-
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
2130-
*/
2131-
final predicate getUpdatedInterval(int startBit, int endBit) {
2132-
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
2133-
}
2134-
21352128
/**
21362129
* Holds if the `ChiPartialOperand` totally, but not exactly, overlaps with the `ChiTotalOperand`.
21372130
* This means that the `ChiPartialOperand` will not override the entire memory associated with the

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -233,20 +233,6 @@ private module Cached {
233233
)
234234
}
235235

236-
/**
237-
* Holds if the partial operand of this `ChiInstruction` updates the bit range
238-
* `[startBitOffset, endBitOffset)` of the total operand.
239-
*/
240-
cached
241-
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) {
242-
exists(Alias::MemoryLocation location, OldInstruction oldInstruction |
243-
oldInstruction = getOldInstruction(chi.getPartial()) and
244-
location = Alias::getResultMemoryLocation(oldInstruction) and
245-
startBitOffset = Alias::getStartBitOffset(location) and
246-
endBitOffset = Alias::getEndBitOffset(location)
247-
)
248-
}
249-
250236
/**
251237
* Holds if `operand` totally overlaps with its definition and consumes the bit range
252238
* `[startBitOffset, endBitOffset)`.

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,13 +2125,6 @@ class ChiInstruction extends Instruction {
21252125
*/
21262126
final Instruction getPartial() { result = this.getPartialOperand().getDef() }
21272127

2128-
/**
2129-
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
2130-
*/
2131-
final predicate getUpdatedInterval(int startBit, int endBit) {
2132-
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
2133-
}
2134-
21352128
/**
21362129
* Holds if the `ChiPartialOperand` totally, but not exactly, overlaps with the `ChiTotalOperand`.
21372130
* This means that the `ChiPartialOperand` will not override the entire memory associated with the

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,6 @@ Instruction getMemoryOperandDefinition(
202202
none()
203203
}
204204

205-
/**
206-
* Holds if the partial operand of this `ChiInstruction` updates the bit range
207-
* `[startBitOffset, endBitOffset)` of the total operand.
208-
*/
209-
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBit, int endBit) { none() }
210-
211205
/**
212206
* Holds if the operand totally overlaps with its definition and consumes the
213207
* bit range `[startBitOffset, endBitOffset)`.

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3173,7 +3173,7 @@ class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr {
31733173
private TranslatedConditionDecl getDecl() { result = getTranslatedConditionDecl(expr) }
31743174

31753175
private TranslatedExpr getConditionExpr() {
3176-
result = getTranslatedExpr(expr.getVariableAccess().getFullyConverted())
3176+
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
31773177
}
31783178
}
31793179

cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,13 +2125,6 @@ class ChiInstruction extends Instruction {
21252125
*/
21262126
final Instruction getPartial() { result = this.getPartialOperand().getDef() }
21272127

2128-
/**
2129-
* Gets the bit range `[startBit, endBit)` updated by the partial operand of this `ChiInstruction`, relative to the start address of the total operand.
2130-
*/
2131-
final predicate getUpdatedInterval(int startBit, int endBit) {
2132-
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
2133-
}
2134-
21352128
/**
21362129
* Holds if the `ChiPartialOperand` totally, but not exactly, overlaps with the `ChiTotalOperand`.
21372130
* This means that the `ChiPartialOperand` will not override the entire memory associated with the

cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -233,20 +233,6 @@ private module Cached {
233233
)
234234
}
235235

236-
/**
237-
* Holds if the partial operand of this `ChiInstruction` updates the bit range
238-
* `[startBitOffset, endBitOffset)` of the total operand.
239-
*/
240-
cached
241-
predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBitOffset, int endBitOffset) {
242-
exists(Alias::MemoryLocation location, OldInstruction oldInstruction |
243-
oldInstruction = getOldInstruction(chi.getPartial()) and
244-
location = Alias::getResultMemoryLocation(oldInstruction) and
245-
startBitOffset = Alias::getStartBitOffset(location) and
246-
endBitOffset = Alias::getEndBitOffset(location)
247-
)
248-
}
249-
250236
/**
251237
* Holds if `operand` totally overlaps with its definition and consumes the bit range
252238
* `[startBitOffset, endBitOffset)`.

cpp/ql/lib/semmle/code/cpp/models/Models.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ private import implementations.Deallocation
33
private import implementations.Fread
44
private import implementations.Getenv
55
private import implementations.Gets
6+
private import implementations.GetText
67
private import implementations.IdentityFunction
78
private import implementations.Inet
89
private import implementations.Iterator
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import semmle.code.cpp.models.interfaces.DataFlow
2+
3+
/**
4+
* Returns the transated text index for a given gettext function `f`
5+
*/
6+
private int getTextArg(Function f) {
7+
// basic variations of gettext
8+
f.hasGlobalOrStdName("gettext") and result = 0
9+
or
10+
f.hasGlobalOrStdName("dgettext") and result = 1
11+
or
12+
f.hasGlobalOrStdName("dcgettext") and result = 1
13+
or
14+
// plural variations of gettext that take one format string for singular and another for plural form
15+
f.hasGlobalOrStdName("ngettext") and
16+
(result = 0 or result = 1)
17+
or
18+
f.hasGlobalOrStdName("dngettext") and
19+
(result = 1 or result = 2)
20+
or
21+
f.hasGlobalOrStdName("dcngettext") and
22+
(result = 1 or result = 2)
23+
}
24+
25+
class GetTextFunction extends DataFlowFunction {
26+
int argInd;
27+
28+
GetTextFunction() { argInd = getTextArg(this) }
29+
30+
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
31+
input.isParameterDeref(argInd) and output.isReturnValueDeref()
32+
}
33+
}

cpp/ql/lib/semmle/code/cpp/models/implementations/Swap.qll

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import semmle.code.cpp.models.interfaces.DataFlow
22
import semmle.code.cpp.models.interfaces.Taint
33
import semmle.code.cpp.models.interfaces.Alias
4+
import semmle.code.cpp.models.interfaces.FlowOutBarrier
45

56
/**
67
* The standard function `swap`. A use of `swap` looks like this:
78
* ```
89
* std::swap(obj1, obj2)
910
* ```
1011
*/
11-
private class Swap extends DataFlowFunction {
12+
private class Swap extends DataFlowFunction, FlowOutBarrierFunction {
1213
Swap() { this.hasQualifiedName(["std", "bsl"], "swap") }
1314

1415
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
@@ -18,6 +19,8 @@ private class Swap extends DataFlowFunction {
1819
input.isParameterDeref(1) and
1920
output.isParameterDeref(0)
2021
}
22+
23+
override predicate isFlowOutBarrier(FunctionInput input) { input.isParameterDeref([0, 1]) }
2124
}
2225

2326
/**
@@ -26,7 +29,9 @@ private class Swap extends DataFlowFunction {
2629
* obj1.swap(obj2)
2730
* ```
2831
*/
29-
private class MemberSwap extends TaintFunction, MemberFunction, AliasFunction {
32+
private class MemberSwap extends TaintFunction, MemberFunction, AliasFunction,
33+
FlowOutBarrierFunction
34+
{
3035
MemberSwap() {
3136
this.hasName("swap") and
3237
this.getNumberOfParameters() = 1 and
@@ -47,4 +52,8 @@ private class MemberSwap extends TaintFunction, MemberFunction, AliasFunction {
4752
override predicate parameterEscapesOnlyViaReturn(int index) { index = 0 }
4853

4954
override predicate parameterIsAlwaysReturned(int index) { index = 0 }
55+
56+
override predicate isFlowOutBarrier(FunctionInput input) {
57+
input.isQualifierObject() or input.isParameterDeref(0)
58+
}
5059
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Provides an abstract class for blocking flow out of functions. To use this
3+
* QL library, create a QL class extending `FlowOutBarrierFunction` with a
4+
* characteristic predicate that selects the function or set of functions you
5+
* are modeling. Within that class, override the predicates provided by
6+
* `FlowOutBarrierFunction` to match the flow within that function.
7+
*/
8+
9+
import semmle.code.cpp.Function
10+
import FunctionInputsAndOutputs
11+
12+
/**
13+
* A library function for which flow should not continue after reaching one
14+
* of its inputs.
15+
*
16+
* For example, since `std::swap(a, b)` swaps the values pointed to by `a`
17+
* and `b` there should not be use-use flow out of `a` or `b`.
18+
*/
19+
abstract class FlowOutBarrierFunction extends Function {
20+
/**
21+
* Holds if use-use flow should not continue onwards after reaching
22+
* the argument, qualifier, or buffer represented by `input`.
23+
*/
24+
pragma[nomagic]
25+
abstract predicate isFlowOutBarrier(FunctionInput input);
26+
}

cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
import semmle.code.cpp.ir.dataflow.TaintTracking
19+
import semmle.code.cpp.models.implementations.GetText
1920
import semmle.code.cpp.commons.Printf
2021

2122
// For the following `...gettext` functions, we assume that
@@ -26,30 +27,21 @@ predicate whitelistFunction(Function f, int arg) {
2627
// basic variations of gettext
2728
f.getName() = "_" and arg = 0
2829
or
29-
f.getName() = "gettext" and arg = 0
30-
or
31-
f.getName() = "dgettext" and arg = 1
32-
or
33-
f.getName() = "dcgettext" and arg = 1
34-
or
35-
// plural variations of gettext that take one format string for singular and another for plural form
36-
f.getName() = "ngettext" and
37-
(arg = 0 or arg = 1)
38-
or
39-
f.getName() = "dngettext" and
40-
(arg = 1 or arg = 2)
41-
or
42-
f.getName() = "dcngettext" and
43-
(arg = 1 or arg = 2)
30+
exists(FunctionInput input |
31+
f.(GetTextFunction).hasDataFlow(input, _) and
32+
input.isParameterDeref(arg)
33+
)
4434
}
4535

46-
// we assume that ALL uses of the `_` macro
36+
// we assume that ALL uses of the `_` macro (and calls to `gettext`)
4737
// return constant string literals
4838
predicate underscoreMacro(Expr e) {
4939
exists(MacroInvocation mi |
5040
mi.getMacroName() = "_" and
5141
mi.getExpr() = e
5242
)
43+
or
44+
e = any(GetTextFunction gettext).getACallToThisFunction()
5345
}
5446

5547
/**
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added dataflow models for the `gettext` function variants.

cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,12 @@ irFlow
303303
| test.cpp:914:46:914:53 | source | test.cpp:919:10:919:30 | global_pointer_static |
304304
| test.cpp:915:57:915:76 | *indirect_source(1) | test.cpp:921:19:921:50 | *global_pointer_static_indirect_1 |
305305
| test.cpp:932:23:932:28 | call to source | test.cpp:937:10:937:24 | * ... |
306+
| test.cpp:958:18:958:32 | *call to indirect_source | test.cpp:961:19:961:28 | *translated |
307+
| test.cpp:973:18:973:32 | *call to indirect_source | test.cpp:977:19:977:28 | *translated |
308+
| test.cpp:994:18:994:32 | *call to indirect_source | test.cpp:999:19:999:28 | *translated |
309+
| test.cpp:994:18:994:32 | *call to indirect_source | test.cpp:1003:19:1003:28 | *translated |
310+
| test.cpp:1021:18:1021:32 | *call to indirect_source | test.cpp:1027:19:1027:28 | *translated |
311+
| test.cpp:1021:18:1021:32 | *call to indirect_source | test.cpp:1031:19:1031:28 | *translated |
306312
| true_upon_entry.cpp:9:11:9:16 | call to source | true_upon_entry.cpp:13:8:13:8 | x |
307313
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
308314
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |

0 commit comments

Comments
 (0)