-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathResetStringsOnFgetsOrFgetwsFailure.ql
More file actions
118 lines (106 loc) · 3.32 KB
/
ResetStringsOnFgetsOrFgetwsFailure.ql
File metadata and controls
118 lines (106 loc) · 3.32 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
115
116
117
118
/**
* @id c/cert/reset-strings-on-fgets-or-fgetws-failure
* @name FIO40-C: Reset strings on fgets() or fgetws() failure
* @description A string that used in a failing call to fgets() or fgetws() requires a reset before
* being referenced.
* @kind problem
* @precision very-high
* @problem.severity error
* @tags external/cert/id/fio40-c
* correctness
* security
* external/cert/severity/low
* external/cert/likelihood/probable
* external/cert/remediation-cost/medium
* external/cert/priority/p4
* external/cert/level/l3
* coding-standards/baseline/safety
* external/cert/obligation/rule
*/
import cpp
import codingstandards.cpp.FgetsErrorManagement
import codingstandards.cpp.Dereferenced
import codingstandards.c.cert
import semmle.code.cpp.dataflow.DataFlow
/*
* Models calls to `memcpy` `strcpy` `strncpy` and their wrappers
*/
class MemcpyLikeCall extends FunctionCall {
Expr destination;
MemcpyLikeCall() {
exists(string names |
names = ["memcpy", "memcpy_s", "strcpy", "strcpy_s", "strncpy", "strncpy_s"] and
(
this.getTarget().hasGlobalName(names)
or
exists(MacroInvocation mi | mi.getMacroName() = names and this = mi.getExpr())
) and
(
destination = this.getArgument(0)
or
exists(MemcpyLikeCall internalCall, int destination_pos |
internalCall.getEnclosingFunction() = this.getTarget() and
// Map destination argument
destination = this.getArgument(destination_pos) and
DataFlow::localFlow(DataFlow::parameterNode(this.getTarget().getParameter(destination_pos)),
DataFlow::exprNode(internalCall.getDestination()))
)
)
)
}
Expr getDestination() { result = destination }
}
/*
* Models accesses to the buffer by dereferencing the associated expression
*/
class BuffAccessExpr extends Expr {
BuffAccessExpr() {
// dereferenced expressions
this instanceof DereferencedExpr
or
// any parameter to a function
this = any(FunctionCall fc).getAnArgument()
}
}
/*
* Models buffer reset by means of overwriting
*/
class BuffReset extends Expr {
BuffReset() {
// *buf = ''
this = any(Assignment a).getLValue().(PointerDereferenceExpr).getOperand()
or
// buf[0] = ''
this = any(Assignment a).getLValue().(ArrayExpr).getArrayBase()
or
// FgetsLikeCall
this = any(FgetsLikeCall fgets).getBuffer()
or
// MemcpyLikeCall
this = any(MemcpyLikeCall a).getDestination()
}
}
/*
* CFG nodes that follows a failing call to `fgets`
*/
ControlFlowNode followsNullFgets(FgetsLikeCall fgets) {
exists(FgetsGuard guard |
fgets = guard.getFgetCall() and
//Stop recursion on buffer reset
not exists(Variable v |
v.getAnAccess() = fgets.getBuffer() and v.getAnAccess() = result.(BuffReset)
) and
(
result = guard.getNullSuccessor()
or
result = followsNullFgets(fgets).getASuccessor()
)
)
}
from BuffAccessExpr e, FgetsLikeCall fgets
where
not isExcluded(e, IO2Package::resetStringsOnFgetsOrFgetwsFailureQuery()) and
e = followsNullFgets(fgets) and
exists(Variable v | v.getAnAccess() = fgets.getBuffer() and v.getAnAccess() = e)
select e, "The buffer is not reset before being referenced following a failed $@.", fgets,
fgets.toString()