39class MIGChecker :
public Checker<check::PostCall, check::PreStmt<ReturnStmt>,
41 BugType BT{
this,
"Use-after-free (MIG calling convention violation)",
50#define CALL(required_args, deallocated_arg, ...) \
51 {{CDM::SimpleFunc, {__VA_ARGS__}, required_args}, deallocated_arg}
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"),
82#define CALL(required_args, deallocated_arg, ...) \
83 {{CDM::CXXMethod, {__VA_ARGS__}, required_args}, deallocated_arg}
88 CALL(1, 0,
"IOUserClient",
"releaseAsyncReference64"),
89 CALL(1, 0,
"IOUserClient",
"releaseNotificationPort"),
107 checkReturnAux(RS,
C);
110 checkReturnAux(RS,
C);
124 bool IncludeBaseRegions =
false) {
126 SymbolRef Sym =
V.getAsSymbol(IncludeBaseRegions);
136 const auto *VR = dyn_cast<VarRegion>(MR);
137 if (VR && VR->hasStackParametersStorage() &&
138 VR->getStackFrame()->inTopFrame())
139 return cast<ParmVarDecl>(VR->getDecl());
153 assert(LC &&
"Unknown location context");
170 if (!AC->getReturnType(
C.getASTContext())
171 .getCanonicalType()->isSignedIntegerType())
175 if (
D->
hasAttr<MIGServerRoutineAttr>())
179 if (
const auto *MD = dyn_cast<CXXMethodDecl>(
D))
180 for (
const auto *OMD: MD->overridden_methods())
181 if (OMD->hasAttr<MIGServerRoutineAttr>())
188 if (OsRefRetain.matches(
Call)) {
196 C.addTransition(
C.getState()->add<RefCountedParameters>(PVD));
204 const unsigned *ArgIdxPtr = Deallocators.lookup(
Call);
209 unsigned ArgIdx = *ArgIdxPtr;
212 if (!PVD || State->contains<RefCountedParameters>(PVD))
220 llvm::raw_svector_ostream OS(Str);
221 OS <<
"Value passed through parameter '" << PVD->
getName()
222 <<
"\' is deallocated";
223 return std::string(OS.str());
225 C.addTransition(State->set<ReleasedParameter>(
true),
T);
233 if (!State->isNull(
V).isConstrainedFalse())
240 static const int MigNoReply = -305;
242 if (!State->isNull(
V).isConstrainedTrue())
270 if (!State->get<ReleasedParameter>())
281 auto R = std::make_unique<PathSensitiveBugReport>(
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",
291 {bugreporter::TrackingKind::Thorough, false});
292 C.emitReport(std::move(R));
#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