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

175 if (D->hasAttr())

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 (C.inTopFrame())

259 return;

260

262 return;

263

264

265

266 if (!RS)

267 return;

268

270 if (!State->get())

271 return;

272

273 SVal V = C.getSVal(RS);

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