forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFileWrite.qll
More file actions
162 lines (142 loc) · 4.16 KB
/
Copy pathFileWrite.qll
File metadata and controls
162 lines (142 loc) · 4.16 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/**
* Provides classes for modeling writing of data to files through various standard mechanisms such as `fprintf`, `fwrite` and `operator<<`.
*/
import cpp
/**
* A function call that writes to a file.
*/
class FileWrite extends Expr {
FileWrite() { fileWrite(this, _, _) }
/**
* Gets a source expression of this write.
*/
Expr getASource() { fileWrite(this, result, _) }
/**
* Gets the expression for the object being written to.
*/
Expr getDest() { fileWrite(this, _, result) }
}
/**
* A `std::basic_ostream` class, or something that can be used
* as one.
*/
class BasicOStreamClass extends Type {
BasicOStreamClass() {
this.(Class).getName().matches("basic\\_ostream%")
or
this.getUnspecifiedType() instanceof BasicOStreamClass
or
this.(Class).getABaseClass() instanceof BasicOStreamClass
or
this.(ReferenceType).getBaseType() instanceof BasicOStreamClass
}
}
/**
* A call to a member of `std::basic_ostream`, or something related,
* or a call with one of those objects as the first parameter.
*/
class BasicOStreamCall extends FunctionCall {
BasicOStreamCall() {
if getTarget() instanceof MemberFunction
then getQualifier().getType() instanceof BasicOStreamClass
else getArgument(0).getType() instanceof BasicOStreamClass
}
}
/**
* Output by a function that can be chained, such as `operator<<`.
*/
abstract class ChainedOutputCall extends BasicOStreamCall {
/**
* Gets the source expression of this output.
*/
abstract Expr getSource();
/**
* Gets the immediate destination expression of this output.
*/
abstract Expr getDest();
/**
* Gets the destination at the far left-hand end of the output chain.
*/
Expr getEndDest() {
// recurse into the destination
result = getDest().(ChainedOutputCall).getEndDest()
or
// or return something other than a ChainedOutputCall
result = getDest() and
not result instanceof ChainedOutputCall
}
}
/**
* A call to `operator<<` on an output stream.
*/
class OperatorLShiftCall extends ChainedOutputCall {
OperatorLShiftCall() { getTarget().(Operator).hasName("operator<<") }
override Expr getSource() {
if getTarget() instanceof MemberFunction
then result = getArgument(0)
else result = getArgument(1)
}
override Expr getDest() {
if getTarget() instanceof MemberFunction
then result = getQualifier()
else result = getArgument(0)
}
}
/**
* A call to 'put'.
*/
class PutFunctionCall extends ChainedOutputCall {
PutFunctionCall() { getTarget().(MemberFunction).hasName("put") }
override Expr getSource() { result = getArgument(0) }
override Expr getDest() { result = getQualifier() }
}
/**
* A call to 'write'.
*/
class WriteFunctionCall extends ChainedOutputCall {
WriteFunctionCall() { getTarget().(MemberFunction).hasName("write") }
override Expr getSource() { result = getArgument(0) }
override Expr getDest() { result = getQualifier() }
}
/**
* Whether the function call is a call to `operator<<` or a similar function, that eventually starts at the given file stream.
*/
private predicate fileStreamChain(ChainedOutputCall out, Expr source, Expr dest) {
source = out.getSource() and
dest = out.getEndDest() and
exists(string nme | nme = "basic_ofstream" or nme = "basic_fstream" |
dest.getUnderlyingType().(Class).getSimpleName() = nme
)
}
/**
* Whether the function call is a write to file 'dest' from 'source'.
*/
private predicate fileWrite(Call write, Expr source, Expr dest) {
exists(Function f, int s, int d |
f = write.getTarget() and source = write.getArgument(s) and dest = write.getArgument(d)
|
exists(string name | f.hasGlobalOrStdName(name) |
// named functions
name = "fwrite" and s = 0 and d = 3
or
(
name = "fputs" or
name = "fputws" or
name = "fputc" or
name = "fputwc" or
name = "putc" or
name = "putwc" or
name = "putw"
) and
s = 0 and
d = 1
)
or
// fprintf
s >= f.(Fprintf).getFormatParameterIndex() and
d = f.(Fprintf).getOutputParameterIndex()
)
or
// file stream using '<<', 'put' or 'write'
fileStreamChain(write, source, dest)
}