forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSnprintfOverflow.ql
More file actions
114 lines (108 loc) · 3.86 KB
/
SnprintfOverflow.ql
File metadata and controls
114 lines (108 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
* @name Potentially overflowing call to snprintf
* @description Using the return value from snprintf without proper checks can cause overflow.
*
* @kind problem
* @problem.severity warning
* @precision high
* @id cpp/overflowing-snprintf
* @tags reliability
* correctness
* security
*/
import cpp
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
/**
* Holds if there is a dataflow path from `source` to `sink`
* with no bounds checks along the way. `pathMightOverflow` is
* true if there is an arithmetic operation on the path that
* might overflow.
*/
predicate flowsToExpr(
Expr source, Expr sink, boolean pathMightOverflow) {
// Might the current expression overflow?
exists (boolean otherMightOverflow
| flowsToExprImpl(source, sink, otherMightOverflow)
| if convertedExprMightOverflow(sink)
then pathMightOverflow = true
else pathMightOverflow = otherMightOverflow)
}
/**
* Implementation of `flowsToExpr`. Does everything except
* checking whether the current expression might overflow.
*/
predicate flowsToExprImpl(
Expr source, Expr sink, boolean pathMightOverflow) {
(source = sink and pathMightOverflow = false and
source.(FunctionCall).getTarget().(Snprintf).returnsFullFormatLength())
or
exists (RangeSsaDefinition def, LocalScopeVariable v
| flowsToDef(source, def, v, pathMightOverflow) and
sink = def.getAUse(v))
or
flowsToExpr(
source, sink.(UnaryArithmeticOperation).getOperand(), pathMightOverflow)
or
flowsToExpr(
source, sink.(BinaryArithmeticOperation).getAnOperand(), pathMightOverflow)
or
flowsToExpr(
source, sink.(Assignment).getRValue(), pathMightOverflow)
or
flowsToExpr(
source, sink.(AssignOperation).getLValue(), pathMightOverflow)
or
exists (FormattingFunctionCall call
| sink = call and
flowsToExpr(source, call.getArgument(call.getTarget().getSizeParameterIndex()), pathMightOverflow))
}
/**
* Holds if there is a dataflow path from `source` to the SSA
* definition `(def,v)`. with no bounds checks along the way.
* `pathMightOverflow` is true if there is an arithmetic operation
* on the path that might overflow.
*/
predicate flowsToDef(
Expr source, RangeSsaDefinition def, LocalScopeVariable v,
boolean pathMightOverflow) {
// Might the current definition overflow?
exists (boolean otherMightOverflow
| flowsToDefImpl(source, def, v, otherMightOverflow)
| if defMightOverflow(def, v)
then pathMightOverflow = true
else pathMightOverflow = otherMightOverflow)
}
/**
* Implementation of `flowsToDef`. Does everything except
* checking whether the current definition might overflow.
*
* Note: RangeSsa is used to exclude paths that include a bounds check.
* RangeSsa inserts extra definitions after conditions like `if (x < 10)`.
* Such definitions are ignored here, so the path will terminate when
* a bounds check is encounter. Of course it isn't super accurate
* because useless checks such as `if (x >= 0)` will also terminate
* the path. But it is a good way to reduce the number of false positives.
*/
predicate flowsToDefImpl(
Expr source, RangeSsaDefinition def, LocalScopeVariable v,
boolean pathMightOverflow) {
// Assignment or initialization: `e = v;`
exists (Expr e
| e = def.getDefiningValue(v) and
flowsToExpr(source, e, pathMightOverflow))
or
// `x++`
exists (CrementOperation crem
| def = crem and
crem.getOperand() = v.getAnAccess() and
flowsToExpr(source, crem.getOperand(), pathMightOverflow))
or
// Phi definition.
flowsToDef(source, def.getAPhiInput(v), v, pathMightOverflow)
}
from FormattingFunctionCall call, Expr sink
where flowsToExpr(call, sink, true)
and sink = call.getArgument(call.getTarget().getSizeParameterIndex())
select
call, "The $@ of this snprintf call is derived from its return value, which may exceed the size of the buffer and overflow.",
sink, "size argument"