Skip to content

Commit ee6c255

Browse files
authored
Merge pull request #17328 from paldepind/tweak-unbounded-barrier
C++: Tweak the `bounded` barrier
2 parents e294c8e + e7f059a commit ee6c255

File tree

5 files changed

+110
-79
lines changed

5 files changed

+110
-79
lines changed
+21-23
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
11
/**
2-
* This file provides the `bounded` predicate that is used in both `cpp/uncontrolled-arithmetic`
3-
* and `cpp/tainted-arithmetic`.
2+
* This file provides the `bounded` predicate that is used in `cpp/uncontrolled-arithmetic`,
3+
* `cpp/tainted-arithmetic` and `cpp/uncontrolled-allocation-size`.
44
*/
55

66
private import cpp
77
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
88
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
99

1010
/**
11-
* An operand `e` of a bitwise and expression `andExpr` (i.e., `andExpr` is either an `BitwiseAndExpr`
12-
* or an `AssignAndExpr`) with operands `operand1` and `operand2` is the operand that is not `e` is upper
13-
* bounded by some number that is less than the maximum integer allowed by the result type of `andExpr`.
11+
* An operand `operand` of a bitwise and expression `andExpr` (i.e., `andExpr` is either a
12+
* `BitwiseAndExpr` or an `AssignAndExpr`) is upper bounded by some number that is less than the
13+
* maximum integer allowed by the result type of `andExpr`.
1414
*/
1515
pragma[inline]
16-
private predicate boundedBitwiseAnd(Expr e, Expr andExpr, Expr operand1, Expr operand2) {
17-
operand1 != operand2 and
18-
e = operand1 and
19-
upperBound(operand2.getFullyConverted()) < exprMaxVal(andExpr.getFullyConverted())
16+
private predicate boundedBitwiseAnd(Expr operand, Expr andExpr) {
17+
upperBound(operand.getFullyConverted()) < exprMaxVal(andExpr.getFullyConverted())
2018
}
2119

2220
/**
23-
* Holds if `e` is an arithmetic expression that cannot overflow, or if `e` is an operand of an
24-
* operation that may greatly reduce the range of possible values.
21+
* Holds if `e` is an arithmetic expression that cannot overflow, or if `e` is an operation that
22+
* may greatly reduce the range of possible values.
2523
*/
2624
predicate bounded(Expr e) {
2725
// There can be two separate reasons for `convertedExprMightOverflow` not holding:
@@ -35,25 +33,25 @@ predicate bounded(Expr e) {
3533
) and
3634
not convertedExprMightOverflow(e)
3735
or
38-
// Optimistically assume that a remainder expression always yields a much smaller value.
39-
e = any(RemExpr rem).getLeftOperand()
36+
// Optimistically assume that the following operations always yields a much smaller value.
37+
e instanceof RemExpr
4038
or
41-
e = any(AssignRemExpr rem).getLValue()
39+
e instanceof DivExpr
4240
or
43-
exists(BitwiseAndExpr andExpr |
44-
boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
45-
)
41+
e instanceof RShiftExpr
4642
or
47-
exists(AssignAndExpr andExpr |
48-
boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
43+
exists(BitwiseAndExpr andExpr |
44+
e = andExpr and boundedBitwiseAnd(andExpr.getAnOperand(), andExpr)
4945
)
5046
or
51-
// Optimistically assume that a division always yields a much smaller value.
52-
e = any(DivExpr div).getLeftOperand()
47+
// For the assignment variant of the operations we place the barrier on the assigned lvalue.
48+
e = any(AssignRemExpr rem).getLValue()
5349
or
5450
e = any(AssignDivExpr div).getLValue()
5551
or
56-
e = any(RShiftExpr shift).getLeftOperand()
57-
or
5852
e = any(AssignRShiftExpr div).getLValue()
53+
or
54+
exists(AssignAndExpr andExpr |
55+
e = andExpr.getLValue() and boundedBitwiseAnd(andExpr.getRValue(), andExpr)
56+
)
5957
}

cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ArithmeticUncontrolled/ArithmeticUncontrolled.expected

+6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ edges
3232
| test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r | provenance | |
3333
| test.cpp:30:13:30:14 | get_rand2 output argument | test.cpp:31:7:31:7 | r | provenance | |
3434
| test.cpp:36:13:36:13 | get_rand3 output argument | test.cpp:37:7:37:7 | r | provenance | |
35+
| test.cpp:62:19:62:24 | call to rand | test.cpp:62:19:62:24 | call to rand | provenance | |
36+
| test.cpp:62:19:62:24 | call to rand | test.cpp:65:9:65:9 | x | provenance | |
3537
| test.cpp:86:10:86:13 | call to rand | test.cpp:86:10:86:13 | call to rand | provenance | |
3638
| test.cpp:86:10:86:13 | call to rand | test.cpp:90:10:90:10 | x | provenance | |
3739
| test.cpp:98:10:98:13 | call to rand | test.cpp:98:10:98:13 | call to rand | provenance | |
@@ -105,6 +107,9 @@ nodes
105107
| test.cpp:31:7:31:7 | r | semmle.label | r |
106108
| test.cpp:36:13:36:13 | get_rand3 output argument | semmle.label | get_rand3 output argument |
107109
| test.cpp:37:7:37:7 | r | semmle.label | r |
110+
| test.cpp:62:19:62:24 | call to rand | semmle.label | call to rand |
111+
| test.cpp:62:19:62:24 | call to rand | semmle.label | call to rand |
112+
| test.cpp:65:9:65:9 | x | semmle.label | x |
108113
| test.cpp:86:10:86:13 | call to rand | semmle.label | call to rand |
109114
| test.cpp:86:10:86:13 | call to rand | semmle.label | call to rand |
110115
| test.cpp:90:10:90:10 | x | semmle.label | x |
@@ -156,6 +161,7 @@ subpaths
156161
| test.cpp:25:7:25:7 | r | test.cpp:8:9:8:12 | call to rand | test.cpp:25:7:25:7 | r | This arithmetic expression depends on an $@, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | uncontrolled value |
157162
| test.cpp:31:7:31:7 | r | test.cpp:13:10:13:13 | call to rand | test.cpp:31:7:31:7 | r | This arithmetic expression depends on an $@, potentially causing an overflow. | test.cpp:13:10:13:13 | call to rand | uncontrolled value |
158163
| test.cpp:37:7:37:7 | r | test.cpp:18:9:18:12 | call to rand | test.cpp:37:7:37:7 | r | This arithmetic expression depends on an $@, potentially causing an overflow. | test.cpp:18:9:18:12 | call to rand | uncontrolled value |
164+
| test.cpp:65:9:65:9 | x | test.cpp:62:19:62:24 | call to rand | test.cpp:65:9:65:9 | x | This arithmetic expression depends on an $@, potentially causing an underflow. | test.cpp:62:19:62:22 | call to rand | uncontrolled value |
159165
| test.cpp:90:10:90:10 | x | test.cpp:86:10:86:13 | call to rand | test.cpp:90:10:90:10 | x | This arithmetic expression depends on an $@, potentially causing an overflow. | test.cpp:86:10:86:13 | call to rand | uncontrolled value |
160166
| test.cpp:102:10:102:10 | x | test.cpp:98:10:98:13 | call to rand | test.cpp:102:10:102:10 | x | This arithmetic expression depends on an $@, potentially causing an overflow. | test.cpp:98:10:98:13 | call to rand | uncontrolled value |
161167
| test.cpp:146:9:146:9 | y | test.cpp:137:10:137:13 | call to rand | test.cpp:146:9:146:9 | y | This arithmetic expression depends on an $@, potentially causing an overflow. | test.cpp:137:10:137:13 | call to rand | uncontrolled value |

cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ArithmeticUncontrolled/test.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ unsigned int test_remainder_subtract_unsigned()
6262
unsigned int x = rand();
6363
unsigned int y = x % 100; // y <= x
6464

65-
return x - y; // GOOD (as y <= x)
65+
return x - y; // GOOD (as y <= x) [FALSE POSITIVE]
6666
}
6767

6868
typedef unsigned long size_t;

0 commit comments

Comments
 (0)