Skip to content

Commit 3bc6b11

Browse files
committed
C++: Share the 'bounded' predicate from 'cpp/uncontrolled-arithmetic' and use it in 'cpp/tainted-arithmetic'.
1 parent 17df8e4 commit 3bc6b11

File tree

3 files changed

+82
-69
lines changed

3 files changed

+82
-69
lines changed

cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import semmle.code.cpp.security.Overflow
1717
import semmle.code.cpp.security.Security
1818
import semmle.code.cpp.security.TaintTracking
1919
import TaintedWithPath
20+
import Bounded
2021

2122
bindingset[op]
2223
predicate missingGuard(Operation op, Expr e, string effect) {
@@ -37,6 +38,10 @@ class Configuration extends TaintTrackingConfiguration {
3738
op instanceof BinaryArithmeticOperation
3839
)
3940
}
41+
42+
override predicate isBarrier(Expr e) {
43+
super.isBarrier(e) or bounded(e) or e.getUnspecifiedType().(IntegralType).getSize() <= 1
44+
}
4045
}
4146

4247
from Expr origin, Expr e, string effect, PathNode sourceNode, PathNode sinkNode, Operation op

cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import cpp
1616
import semmle.code.cpp.security.Overflow
1717
import semmle.code.cpp.security.Security
1818
import semmle.code.cpp.security.TaintTracking
19-
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
2019
import TaintedWithPath
20+
import Bounded
2121

2222
predicate isUnboundedRandCall(FunctionCall fc) {
2323
exists(Function func | func = fc.getTarget() |
@@ -27,74 +27,6 @@ predicate isUnboundedRandCall(FunctionCall fc) {
2727
)
2828
}
2929

30-
/**
31-
* An operand `e` of a division expression (i.e., `e` is an operand of either a `DivExpr` or
32-
* a `AssignDivExpr`) is bounded when `e` is the left-hand side of the division.
33-
*/
34-
pragma[inline]
35-
predicate boundedDiv(Expr e, Expr left) { e = left }
36-
37-
/**
38-
* An operand `e` of a remainder expression `rem` (i.e., `rem` is either a `RemExpr` or
39-
* an `AssignRemExpr`) with left-hand side `left` and right-ahnd side `right` is bounded
40-
* when `e` is `left` and `right` is upper bounded by some number that is less than the maximum integer
41-
* allowed by the result type of `rem`.
42-
*/
43-
pragma[inline]
44-
predicate boundedRem(Expr e, Expr rem, Expr left, Expr right) {
45-
e = left and
46-
upperBound(right.getFullyConverted()) < exprMaxVal(rem.getFullyConverted())
47-
}
48-
49-
/**
50-
* An operand `e` of a bitwise and expression `andExpr` (i.e., `andExpr` is either an `BitwiseAndExpr`
51-
* or an `AssignAndExpr`) with operands `operand1` and `operand2` is the operand that is not `e` is upper
52-
* bounded by some number that is less than the maximum integer allowed by the result type of `andExpr`.
53-
*/
54-
pragma[inline]
55-
predicate boundedBitwiseAnd(Expr e, Expr andExpr, Expr operand1, Expr operand2) {
56-
operand1 != operand2 and
57-
e = operand1 and
58-
upperBound(operand2.getFullyConverted()) < exprMaxVal(andExpr.getFullyConverted())
59-
}
60-
61-
/**
62-
* Holds if `fc` is a part of the left operand of a binary operation that greatly reduces the range
63-
* of possible values.
64-
*/
65-
predicate bounded(Expr e) {
66-
// For `%` and `&` we require that `e` is bounded by a value that is strictly smaller than the
67-
// maximum possible value of the result type of the operation.
68-
// For example, the function call `rand()` is considered bounded in the following program:
69-
// ```
70-
// int i = rand() % (UINT8_MAX + 1);
71-
// ```
72-
// but not in:
73-
// ```
74-
// unsigned char uc = rand() % (UINT8_MAX + 1);
75-
// ```
76-
exists(RemExpr rem | boundedRem(e, rem, rem.getLeftOperand(), rem.getRightOperand()))
77-
or
78-
exists(AssignRemExpr rem | boundedRem(e, rem, rem.getLValue(), rem.getRValue()))
79-
or
80-
exists(BitwiseAndExpr andExpr |
81-
boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
82-
)
83-
or
84-
exists(AssignAndExpr andExpr |
85-
boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
86-
)
87-
or
88-
// Optimitically assume that a division always yields a much smaller value.
89-
boundedDiv(e, any(DivExpr div).getLeftOperand())
90-
or
91-
boundedDiv(e, any(AssignDivExpr div).getLValue())
92-
or
93-
boundedDiv(e, any(RShiftExpr shift).getLeftOperand())
94-
or
95-
boundedDiv(e, any(AssignRShiftExpr div).getLValue())
96-
}
97-
9830
predicate isUnboundedRandCallOrParent(Expr e) {
9931
isUnboundedRandCall(e)
10032
or
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* This file provides the `bounded` predicate that is used in both `cpp/uncontrolled-arithmetic`
3+
* and `cpp/tainted-arithmetic`.
4+
*/
5+
6+
private import cpp
7+
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
8+
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
9+
10+
/**
11+
* An operand `e` of a division expression (i.e., `e` is an operand of either a `DivExpr` or
12+
* a `AssignDivExpr`) is bounded when `e` is the left-hand side of the division.
13+
*/
14+
pragma[inline]
15+
private predicate boundedDiv(Expr e, Expr left) { e = left }
16+
17+
/**
18+
* An operand `e` of a remainder expression `rem` (i.e., `rem` is either a `RemExpr` or
19+
* an `AssignRemExpr`) with left-hand side `left` and right-ahnd side `right` is bounded
20+
* when `e` is `left` and `right` is upper bounded by some number that is less than the maximum integer
21+
* allowed by the result type of `rem`.
22+
*/
23+
pragma[inline]
24+
private predicate boundedRem(Expr e, Expr rem, Expr left, Expr right) {
25+
e = left and
26+
upperBound(right.getFullyConverted()) < exprMaxVal(rem.getFullyConverted())
27+
}
28+
29+
/**
30+
* An operand `e` of a bitwise and expression `andExpr` (i.e., `andExpr` is either an `BitwiseAndExpr`
31+
* or an `AssignAndExpr`) with operands `operand1` and `operand2` is the operand that is not `e` is upper
32+
* bounded by some number that is less than the maximum integer allowed by the result type of `andExpr`.
33+
*/
34+
pragma[inline]
35+
private predicate boundedBitwiseAnd(Expr e, Expr andExpr, Expr operand1, Expr operand2) {
36+
operand1 != operand2 and
37+
e = operand1 and
38+
upperBound(operand2.getFullyConverted()) < exprMaxVal(andExpr.getFullyConverted())
39+
}
40+
41+
/**
42+
* Holds if `e` is an operand of a binary operation that greatly reduces the range of possible
43+
* output values. For instance, if `e` is the left operand of a remainder expression.
44+
*/
45+
predicate bounded(Expr e) {
46+
// For `%` and `&` we require that `e` is bounded by a value that is strictly smaller than the
47+
// maximum possible value of the result type of the operation.
48+
// For example, the function call `rand()` is considered bounded in the following program:
49+
// ```
50+
// int i = rand() % (UINT8_MAX + 1);
51+
// ```
52+
// but not in:
53+
// ```
54+
// unsigned char uc = rand() % (UINT8_MAX + 1);
55+
// ```
56+
exists(RemExpr rem | boundedRem(e, rem, rem.getLeftOperand(), rem.getRightOperand()))
57+
or
58+
exists(AssignRemExpr rem | boundedRem(e, rem, rem.getLValue(), rem.getRValue()))
59+
or
60+
exists(BitwiseAndExpr andExpr |
61+
boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
62+
)
63+
or
64+
exists(AssignAndExpr andExpr |
65+
boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
66+
)
67+
or
68+
// Optimitically assume that a division always yields a much smaller value.
69+
boundedDiv(e, any(DivExpr div).getLeftOperand())
70+
or
71+
boundedDiv(e, any(AssignDivExpr div).getLValue())
72+
or
73+
boundedDiv(e, any(RShiftExpr shift).getLeftOperand())
74+
or
75+
boundedDiv(e, any(AssignRShiftExpr div).getLValue())
76+
}

0 commit comments

Comments
 (0)