clang: lib/StaticAnalyzer/Checkers/MIGChecker.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
33#include
34
35using namespace clang;
36using namespace ento;
37
38namespace {
39class MIGChecker : public Checker<check::PostCall, check::PreStmt,
40 check::EndFunction> {
41 BugType BT{this, "Use-after-free (MIG calling convention violation)",
43
44
45
46
47
48
50#define CALL(required_args, deallocated_arg, ...) \
51 {{CDM::SimpleFunc, {__VA_ARGS__}, required_args}, deallocated_arg}
52
53
54
55
56 CALL(3, 1, "vm_deallocate"),
57 CALL(3, 1, "mach_vm_deallocate"),
58 CALL(2, 0, "mig_deallocate"),
59 CALL(2, 1, "mach_port_deallocate"),
60 CALL(1, 0, "device_deallocate"),
61 CALL(1, 0, "iokit_remove_connect_reference"),
62 CALL(1, 0, "iokit_remove_reference"),
63 CALL(1, 0, "iokit_release_port"),
64 CALL(1, 0, "ipc_port_release"),
65 CALL(1, 0, "ipc_port_release_sonce"),
66 CALL(1, 0, "ipc_voucher_attr_control_release"),
67 CALL(1, 0, "ipc_voucher_release"),
68 CALL(1, 0, "lock_set_dereference"),
69 CALL(1, 0, "memory_object_control_deallocate"),
70 CALL(1, 0, "pset_deallocate"),
71 CALL(1, 0, "semaphore_dereference"),
72 CALL(1, 0, "space_deallocate"),
73 CALL(1, 0, "space_inspect_deallocate"),
74 CALL(1, 0, "task_deallocate"),
75 CALL(1, 0, "task_inspect_deallocate"),
76 CALL(1, 0, "task_name_deallocate"),
77 CALL(1, 0, "thread_deallocate"),
78 CALL(1, 0, "thread_inspect_deallocate"),
79 CALL(1, 0, "upl_deallocate"),
80 CALL(1, 0, "vm_map_deallocate"),
81#undef CALL
82#define CALL(required_args, deallocated_arg, ...) \
83 {{CDM::CXXMethod, {__VA_ARGS__}, required_args}, deallocated_arg}
84
85
86
87
88 CALL(1, 0, "IOUserClient", "releaseAsyncReference64"),
89 CALL(1, 0, "IOUserClient", "releaseNotificationPort"),
90#undef CALL
91 };
92
93 CallDescription OsRefRetain{CDM::SimpleFunc, {"os_ref_retain"}, 1};
94
96
97public:
99
100
101
102
103
104
105
107 checkReturnAux(RS, C);
108 }
110 checkReturnAux(RS, C);
111 }
112
113};
114}
115
116
117
119
120
122
124 bool IncludeBaseRegions = false) {
125
126 SymbolRef Sym = V.getAsSymbol(IncludeBaseRegions);
127 if (!Sym)
128 return nullptr;
129
130
131
132
133
134
136 const auto *VR = dyn_cast(MR);
137 if (VR && VR->hasStackParametersStorage() &&
138 VR->getStackFrame()->inTopFrame())
139 return cast(VR->getDecl());
140
142 if (!SR)
143 return nullptr;
144
146 }
147
148 return nullptr;
149}
150
153 assert(LC && "Unknown location context");
154
156
157 while (LC) {
160 }
161
163
165
166
167
168
169
170 if (!AC->getReturnType(C.getASTContext())
171 .getCanonicalType()->isSignedIntegerType())
172 return false;
173 }
174
176 return true;
177
178
179 if (const auto *MD = dyn_cast(D))
180 for (const auto *OMD: MD->overridden_methods())
181 if (OMD->hasAttr())
182 return true;
183
184 return false;
185}
186
188 if (OsRefRetain.matches(Call)) {
189
190
191
194
195
196 C.addTransition(C.getState()->add(PVD));
197 }
198 return;
199 }
200
202 return;
203
204 const unsigned *ArgIdxPtr = Deallocators.lookup(Call);
205 if (!ArgIdxPtr)
206 return;
207
209 unsigned ArgIdx = *ArgIdxPtr;
210 SVal Arg = Call.getArgSVal(ArgIdx);
212 if (!PVD || State->contains(PVD))
213 return;
214
218 return "";
220 llvm::raw_svector_ostream OS(Str);
221 OS << "Value passed through parameter '" << PVD->getName()
222 << "\' is deallocated";
223 return std::string(OS.str());
224 });
225 C.addTransition(State->set(true), T);
226}
227
228
231
232
233 if (!State->isNull(V).isConstrainedFalse())
234 return true;
235
238
239
240 static const int MigNoReply = -305;
242 if (!State->isNull(V).isConstrainedTrue())
243 return true;
244
245
246 return false;
247}
248
250
251
252
253
254
255
256
257
258 if (.inTopFrame())
259 return;
260
262 return;
263
264
265
266 if (!RS)
267 return;
268
270 if (!State->get())
271 return;
272
275 return;
276
278 if (!N)
279 return;
280
281 auto R = std::make_unique(
282 BT,
283 "MIG callback fails with error after deallocating argument value. "
284 "This is a use-after-free vulnerability because the caller will try to "
285 "deallocate it again",
286 N);
287
291 {bugreporter::TrackingKind::Thorough, false});
292 C.emitReport(std::move(R));
293}
294
297}
298
299bool ento::shouldRegisterMIGChecker(const CheckerManager &mgr) {
300 return true;
301}
#define CALL(required_args, deallocated_arg,...)
static bool mayBeSuccess(SVal V, CheckerContext &C)
static bool isInMIGCall(CheckerContext &C)
static const ParmVarDecl * getOriginParam(SVal V, CheckerContext &C, bool IncludeBaseRegions=false)
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
static std::optional< AnyCall > forDecl(const Decl *D)
If D is a callable (Objective-C method or a function), return a constructed AnyCall object.
Decl - This represents one declaration (or definition), e.g.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Represents a parameter to a function.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
It represents a stack frame of the call stack (based on CallEvent).
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const BugType & getBugType() const
An immutable map from CallDescriptions to arbitrary data.
A CallDescription is a pattern that can be used to match calls based on the qualified name and the ar...
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
MemRegion - The root abstract class for all memory regions.
const SymbolicRegion * getSymbolicBase() const
If this is a symbolic region, returns the region.
The tag upon which the TagVisitor reacts.
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
virtual const MemRegion * getOriginRegion() const
Find the region from which this symbol originates.
SymbolicRegion - A special, "non-concrete" region.
SymbolRef getSymbol() const
It might return null.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
const char *const MemoryError
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T