34 using namespace clang;
38 class MIGChecker :
public Checker<check::PostCall, check::PreStmt<ReturnStmt>,
40 BugType BT{
this,
"Use-after-free (MIG calling convention violation)",
48 std::vector<std::pair<CallDescription, unsigned>> Deallocators = {
49 #define CALL(required_args, deallocated_arg, ...) \
50 {{{__VA_ARGS__}, required_args}, deallocated_arg}
55 CALL(3, 1,
"vm_deallocate"),
56 CALL(3, 1,
"mach_vm_deallocate"),
57 CALL(2, 0,
"mig_deallocate"),
58 CALL(2, 1,
"mach_port_deallocate"),
59 CALL(1, 0,
"device_deallocate"),
60 CALL(1, 0,
"iokit_remove_connect_reference"),
61 CALL(1, 0,
"iokit_remove_reference"),
62 CALL(1, 0,
"iokit_release_port"),
63 CALL(1, 0,
"ipc_port_release"),
64 CALL(1, 0,
"ipc_port_release_sonce"),
65 CALL(1, 0,
"ipc_voucher_attr_control_release"),
66 CALL(1, 0,
"ipc_voucher_release"),
67 CALL(1, 0,
"lock_set_dereference"),
68 CALL(1, 0,
"memory_object_control_deallocate"),
69 CALL(1, 0,
"pset_deallocate"),
70 CALL(1, 0,
"semaphore_dereference"),
71 CALL(1, 0,
"space_deallocate"),
72 CALL(1, 0,
"space_inspect_deallocate"),
73 CALL(1, 0,
"task_deallocate"),
74 CALL(1, 0,
"task_inspect_deallocate"),
75 CALL(1, 0,
"task_name_deallocate"),
76 CALL(1, 0,
"thread_deallocate"),
77 CALL(1, 0,
"thread_inspect_deallocate"),
78 CALL(1, 0,
"upl_deallocate"),
79 CALL(1, 0,
"vm_map_deallocate"),
84 CALL(1, 0,
"IOUserClient",
"releaseAsyncReference64"),
85 CALL(1, 0,
"IOUserClient",
"releaseNotificationPort"),
89 CallDescription OsRefRetain{
"os_ref_retain", 1};
91 void checkReturnAux(
const ReturnStmt *RS, CheckerContext &C)
const;
94 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
102 void checkPreStmt(
const ReturnStmt *RS, CheckerContext &C)
const {
103 checkReturnAux(RS, C);
105 void checkEndFunction(
const ReturnStmt *RS, CheckerContext &C)
const {
106 checkReturnAux(RS, C);
120 bool IncludeBaseRegions =
false) {
122 SymbolRef Sym =
V.getAsSymbol(IncludeBaseRegions);
131 while (
const MemRegion *MR = Sym->getOriginRegion()) {
132 const auto *VR = dyn_cast<VarRegion>(MR);
133 if (VR && VR->hasStackParametersStorage() &&
134 VR->getStackFrame()->inTopFrame())
135 return cast<ParmVarDecl>(VR->getDecl());
137 const SymbolicRegion *SR = MR->getSymbolicBase();
141 Sym = SR->getSymbol();
149 assert(LC &&
"Unknown location context");
166 if (!AC->getReturnType(C.getASTContext())
167 .getCanonicalType()->isSignedIntegerType())
171 if (D->
hasAttr<MIGServerRoutineAttr>())
175 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D))
176 for (
const auto *OMD: MD->overridden_methods())
177 if (OMD->hasAttr<MIGServerRoutineAttr>())
183 void MIGChecker::checkPostCall(
const CallEvent &Call, CheckerContext &C)
const {
184 if (OsRefRetain.matches(Call)) {
192 C.addTransition(
C.getState()->add<RefCountedParameters>(PVD));
200 auto I = llvm::find_if(Deallocators,
201 [&](
const std::pair<CallDescription, unsigned> &Item) {
202 return Item.first.matches(Call);
204 if (I == Deallocators.end())
208 unsigned ArgIdx = I->second;
209 SVal Arg =
Call.getArgSVal(ArgIdx);
211 if (!PVD ||
State->contains<RefCountedParameters>(PVD))
215 C.getNoteTag([
this, PVD](PathSensitiveBugReport &BR) ->
std::string {
216 if (&BR.getBugType() != &BT)
219 llvm::raw_svector_ostream
OS(Str);
220 OS <<
"Value passed through parameter '" << PVD->
getName()
221 <<
"\' is deallocated";
224 C.addTransition(
State->set<ReleasedParameter>(
true), T);
232 if (!
State->isNull(
V).isConstrainedFalse())
235 SValBuilder &SVB = C.getSValBuilder();
239 static const int MigNoReply = -305;
240 V = SVB.evalEQ(C.getState(),
V, SVB.makeIntVal(MigNoReply, ACtx.
IntTy));
241 if (!
State->isNull(
V).isConstrainedTrue())
248 void MIGChecker::checkReturnAux(
const ReturnStmt *RS, CheckerContext &C)
const {
269 if (!
State->get<ReleasedParameter>())
272 SVal
V =
C.getSVal(RS);
276 ExplodedNode *N =
C.generateErrorNode();
280 auto R = std::make_unique<PathSensitiveBugReport>(
282 "MIG callback fails with error after deallocating argument value. "
283 "This is a use-after-free vulnerability because the caller will try to "
284 "deallocate it again",
290 {bugreporter::TrackingKind::Thorough, false});
291 C.emitReport(std::move(R));
294 void ento::registerMIGChecker(CheckerManager &Mgr) {
295 Mgr.registerChecker<MIGChecker>();
298 bool ento::shouldRegisterMIGChecker(
const CheckerManager &mgr) {