blob: 3214101c6485ac129c4a28ba6398884519fa1427 [file] [log] [blame]
Ted Kremenekdbfb5f82009-07-23 01:07:19 +00001//==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines a set of flow-insensitive security checks.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Analysis/PathSensitive/BugReporter.h"
15#include "clang/Analysis/LocalCheckers.h"
16#include "clang/AST/StmtVisitor.h"
Ted Kremenek8baf86d2009-07-23 21:34:35 +000017#include "llvm/Support/raw_ostream.h"
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000018
19using namespace clang;
20
21namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000022class WalkAST : public StmtVisitor<WalkAST> {
Mike Stump1eb44332009-09-09 15:08:12 +000023 BugReporter &BR;
Ted Kremenek65a81a92009-08-28 00:08:09 +000024 IdentifierInfo *II_gets;
Zhongxing Xubd842e32009-11-09 12:19:26 +000025 IdentifierInfo *II_getpw;
Zhongxing Xu1bf40562009-12-03 09:15:23 +000026 IdentifierInfo *II_mktemp;
Ted Kremenek24650472009-09-02 02:47:41 +000027 enum { num_rands = 9 };
28 IdentifierInfo *II_rand[num_rands];
29 IdentifierInfo *II_random;
30 enum { num_setids = 6 };
31 IdentifierInfo *II_setid[num_setids];
Mike Stump1eb44332009-09-09 15:08:12 +000032
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000033public:
Ted Kremenekefcbb152009-07-23 22:29:41 +000034 WalkAST(BugReporter &br) : BR(br),
Zhongxing Xu1bf40562009-12-03 09:15:23 +000035 II_gets(0), II_getpw(0), II_mktemp(0),
36 II_rand(), II_random(0), II_setid() {}
Mike Stump1eb44332009-09-09 15:08:12 +000037
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000038 // Statement visitor methods.
Ted Kremenekefcbb152009-07-23 22:29:41 +000039 void VisitCallExpr(CallExpr *CE);
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000040 void VisitForStmt(ForStmt *S);
Ted Kremenek65a81a92009-08-28 00:08:09 +000041 void VisitCompoundStmt (CompoundStmt *S);
Ted Kremenek8baf86d2009-07-23 21:34:35 +000042 void VisitStmt(Stmt *S) { VisitChildren(S); }
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000043
44 void VisitChildren(Stmt *S);
Mike Stump1eb44332009-09-09 15:08:12 +000045
Ted Kremenekefcbb152009-07-23 22:29:41 +000046 // Helpers.
47 IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str);
Mike Stump1eb44332009-09-09 15:08:12 +000048
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000049 // Checker-specific methods.
Ted Kremenek8baf86d2009-07-23 21:34:35 +000050 void CheckLoopConditionForFloat(const ForStmt *FS);
Ted Kremenekefcbb152009-07-23 22:29:41 +000051 void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
Zhongxing Xubd842e32009-11-09 12:19:26 +000052 void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
Zhongxing Xu1bf40562009-12-03 09:15:23 +000053 void CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
Ted Kremenek24650472009-09-02 02:47:41 +000054 void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
55 void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
Ted Kremenek65a81a92009-08-28 00:08:09 +000056 void CheckUncheckedReturnValue(CallExpr *CE);
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000057};
58} // end anonymous namespace
59
60//===----------------------------------------------------------------------===//
Ted Kremenekefcbb152009-07-23 22:29:41 +000061// Helper methods.
62//===----------------------------------------------------------------------===//
63
64IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) {
65 if (!II)
66 II = &BR.getContext().Idents.get(str);
Mike Stump1eb44332009-09-09 15:08:12 +000067
68 return II;
Ted Kremenekefcbb152009-07-23 22:29:41 +000069}
70
71//===----------------------------------------------------------------------===//
Ted Kremenekdbfb5f82009-07-23 01:07:19 +000072// AST walking.
73//===----------------------------------------------------------------------===//
74
75void WalkAST::VisitChildren(Stmt *S) {
76 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
77 if (Stmt *child = *I)
78 Visit(child);
79}
80
Ted Kremenekefcbb152009-07-23 22:29:41 +000081void WalkAST::VisitCallExpr(CallExpr *CE) {
82 if (const FunctionDecl *FD = CE->getDirectCallee()) {
Ted Kremenek24650472009-09-02 02:47:41 +000083 CheckCall_gets(CE, FD);
Zhongxing Xubd842e32009-11-09 12:19:26 +000084 CheckCall_getpw(CE, FD);
Zhongxing Xu1bf40562009-12-03 09:15:23 +000085 CheckCall_mktemp(CE, FD);
Ted Kremenek24650472009-09-02 02:47:41 +000086 CheckCall_rand(CE, FD);
87 CheckCall_random(CE, FD);
Ted Kremenekefcbb152009-07-23 22:29:41 +000088 }
Mike Stump1eb44332009-09-09 15:08:12 +000089
Ted Kremenekefcbb152009-07-23 22:29:41 +000090 // Recurse and check children.
91 VisitChildren(CE);
92}
93
Ted Kremenek65a81a92009-08-28 00:08:09 +000094void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
95 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
Mike Stump1eb44332009-09-09 15:08:12 +000096 if (Stmt *child = *I) {
97 if (CallExpr *CE = dyn_cast<CallExpr>(child))
98 CheckUncheckedReturnValue(CE);
99 Visit(child);
100 }
Ted Kremenek65a81a92009-08-28 00:08:09 +0000101}
102
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000103void WalkAST::VisitForStmt(ForStmt *FS) {
Mike Stump1eb44332009-09-09 15:08:12 +0000104 CheckLoopConditionForFloat(FS);
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000105
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000106 // Recurse and check children.
107 VisitChildren(FS);
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000108}
109
110//===----------------------------------------------------------------------===//
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000111// Check: floating poing variable used as loop counter.
Ted Kremenek5abeb522009-07-23 21:44:18 +0000112// Originally: <rdar://problem/6336718>
113// Implements: CERT security coding advisory FLP-30.
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000114//===----------------------------------------------------------------------===//
115
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000116static const DeclRefExpr*
117GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
118 expr = expr->IgnoreParenCasts();
Mike Stump1eb44332009-09-09 15:08:12 +0000119
120 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000121 if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
122 B->getOpcode() == BinaryOperator::Comma))
123 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000124
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000125 if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y))
126 return lhs;
Mike Stump1eb44332009-09-09 15:08:12 +0000127
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000128 if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y))
129 return rhs;
Mike Stump1eb44332009-09-09 15:08:12 +0000130
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000131 return NULL;
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000132 }
Mike Stump1eb44332009-09-09 15:08:12 +0000133
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000134 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
135 const NamedDecl *ND = DR->getDecl();
136 return ND == x || ND == y ? DR : NULL;
137 }
Mike Stump1eb44332009-09-09 15:08:12 +0000138
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000139 if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
140 return U->isIncrementDecrementOp()
141 ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL;
142
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000143 return NULL;
144}
145
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000146/// CheckLoopConditionForFloat - This check looks for 'for' statements that
147/// use a floating point variable as a loop counter.
148/// CERT: FLP30-C, FLP30-CPP.
149///
150void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
151 // Does the loop have a condition?
152 const Expr *condition = FS->getCond();
Mike Stump1eb44332009-09-09 15:08:12 +0000153
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000154 if (!condition)
155 return;
156
157 // Does the loop have an increment?
158 const Expr *increment = FS->getInc();
Mike Stump1eb44332009-09-09 15:08:12 +0000159
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000160 if (!increment)
161 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000162
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000163 // Strip away '()' and casts.
164 condition = condition->IgnoreParenCasts();
165 increment = increment->IgnoreParenCasts();
Mike Stump1eb44332009-09-09 15:08:12 +0000166
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000167 // Is the loop condition a comparison?
168 const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
169
170 if (!B)
171 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000172
Ted Kremenekcad9f412009-07-24 20:26:31 +0000173 // Is this a comparison?
174 if (!(B->isRelationalOp() || B->isEqualityOp()))
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000175 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000176
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000177 // Are we comparing variables?
178 const DeclRefExpr *drLHS = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParens());
179 const DeclRefExpr *drRHS = dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParens());
Mike Stump1eb44332009-09-09 15:08:12 +0000180
Ted Kremenekcad9f412009-07-24 20:26:31 +0000181 // Does at least one of the variables have a floating point type?
182 drLHS = drLHS && drLHS->getType()->isFloatingType() ? drLHS : NULL;
183 drRHS = drRHS && drRHS->getType()->isFloatingType() ? drRHS : NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000184
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000185 if (!drLHS && !drRHS)
186 return;
187
188 const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
189 const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000190
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000191 if (!vdLHS && !vdRHS)
Mike Stump1eb44332009-09-09 15:08:12 +0000192 return;
193
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000194 // Does either variable appear in increment?
195 const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS);
Mike Stump1eb44332009-09-09 15:08:12 +0000196
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000197 if (!drInc)
198 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000199
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000200 // Emit the error. First figure out which DeclRefExpr in the condition
201 // referenced the compared variable.
202 const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
203
Mike Stump1eb44332009-09-09 15:08:12 +0000204 llvm::SmallVector<SourceRange, 2> ranges;
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000205 std::string sbuf;
206 llvm::raw_string_ostream os(sbuf);
Mike Stump1eb44332009-09-09 15:08:12 +0000207
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000208 os << "Variable '" << drCond->getDecl()->getNameAsCString()
209 << "' with floating point type '" << drCond->getType().getAsString()
210 << "' should not be used as a loop counter";
211
212 ranges.push_back(drCond->getSourceRange());
213 ranges.push_back(drInc->getSourceRange());
Mike Stump1eb44332009-09-09 15:08:12 +0000214
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000215 const char *bugType = "Floating point variable used as loop counter";
Benjamin Kramerf0171732009-11-29 18:27:55 +0000216 BR.EmitBasicReport(bugType, "Security", os.str(),
Ted Kremenek8baf86d2009-07-23 21:34:35 +0000217 FS->getLocStart(), ranges.data(), ranges.size());
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000218}
219
220//===----------------------------------------------------------------------===//
Ted Kremenekefcbb152009-07-23 22:29:41 +0000221// Check: Any use of 'gets' is insecure.
222// Originally: <rdar://problem/6335715>
223// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
Zhongxing Xuaa30b3b2009-11-09 08:13:04 +0000224// CWE-242: Use of Inherently Dangerous Function
Ted Kremenekefcbb152009-07-23 22:29:41 +0000225//===----------------------------------------------------------------------===//
226
227void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
228 if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
229 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000230
Zhongxing Xubd842e32009-11-09 12:19:26 +0000231 const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
232 if (!FPT)
Ted Kremenekefcbb152009-07-23 22:29:41 +0000233 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000234
Ted Kremenekefcbb152009-07-23 22:29:41 +0000235 // Verify that the function takes a single argument.
Zhongxing Xubd842e32009-11-09 12:19:26 +0000236 if (FPT->getNumArgs() != 1)
Ted Kremenekefcbb152009-07-23 22:29:41 +0000237 return;
238
239 // Is the argument a 'char*'?
Zhongxing Xubd842e32009-11-09 12:19:26 +0000240 const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
Ted Kremenekefcbb152009-07-23 22:29:41 +0000241 if (!PT)
242 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000243
Ted Kremenekefcbb152009-07-23 22:29:41 +0000244 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
245 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000246
Ted Kremenekefcbb152009-07-23 22:29:41 +0000247 // Issue a warning.
248 SourceRange R = CE->getCallee()->getSourceRange();
249 BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
250 "Security",
251 "Call to function 'gets' is extremely insecure as it can "
252 "always result in a buffer overflow",
253 CE->getLocStart(), &R, 1);
254}
255
256//===----------------------------------------------------------------------===//
Zhongxing Xubd842e32009-11-09 12:19:26 +0000257// Check: Any use of 'getpwd' is insecure.
258// CWE-477: Use of Obsolete Functions
259//===----------------------------------------------------------------------===//
260
261void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
262 if (FD->getIdentifier() != GetIdentifier(II_getpw, "getpw"))
263 return;
264
265 const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
266 if (!FPT)
267 return;
268
269 // Verify that the function takes two arguments.
270 if (FPT->getNumArgs() != 2)
271 return;
272
273 // Verify the first argument type is integer.
274 if (!FPT->getArgType(0)->isIntegerType())
275 return;
276
277 // Verify the second argument type is char*.
278 const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1));
279 if (!PT)
280 return;
281
282 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
283 return;
284
285 // Issue a warning.
286 SourceRange R = CE->getCallee()->getSourceRange();
287 BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'",
288 "Security",
289 "The getpw() function is dangerous as it may overflow the "
290 "provided buffer. It is obsoleted by getpwuid().",
291 CE->getLocStart(), &R, 1);
292}
293
294//===----------------------------------------------------------------------===//
Zhongxing Xu1bf40562009-12-03 09:15:23 +0000295// Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp().
296// CWE-377: Insecure Temporary File
297//===----------------------------------------------------------------------===//
298
299void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
300 if (FD->getIdentifier() != GetIdentifier(II_mktemp, "mktemp"))
301 return;
302
303 const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
304 if(!FPT)
305 return;
306
307 // Verify that the funcion takes a single argument.
308 if (FPT->getNumArgs() != 1)
309 return;
310
311 // Verify that the argument is Pointer Type.
312 const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
313 if (!PT)
314 return;
315
316 // Verify that the argument is a 'char*'.
317 if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
318 return;
319
320 // Issue a waring.
321 SourceRange R = CE->getCallee()->getSourceRange();
322 BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
323 "Security",
324 "Call to function 'mktemp' is insecure as it always "
325 "creates or uses insecure temporary file",
326 CE->getLocStart(), &R, 1);
327}
328
329
330//===----------------------------------------------------------------------===//
Ted Kremenek24650472009-09-02 02:47:41 +0000331// Check: Linear congruent random number generators should not be used
332// Originally: <rdar://problem/63371000>
333// CWE-338: Use of cryptographically weak prng
334//===----------------------------------------------------------------------===//
335
336void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
337 if (II_rand[0] == NULL) {
338 // This check applies to these functions
339 static const char * const identifiers[num_rands] = {
340 "drand48", "erand48", "jrand48", "lrand48", "mrand48", "nrand48",
341 "lcong48",
342 "rand", "rand_r"
343 };
Mike Stump1eb44332009-09-09 15:08:12 +0000344
Ted Kremenek24650472009-09-02 02:47:41 +0000345 for (size_t i = 0; i < num_rands; i++)
Mike Stump1eb44332009-09-09 15:08:12 +0000346 II_rand[i] = &BR.getContext().Idents.get(identifiers[i]);
Ted Kremenek24650472009-09-02 02:47:41 +0000347 }
Mike Stump1eb44332009-09-09 15:08:12 +0000348
Ted Kremenek24650472009-09-02 02:47:41 +0000349 const IdentifierInfo *id = FD->getIdentifier();
350 size_t identifierid;
351
352 for (identifierid = 0; identifierid < num_rands; identifierid++)
353 if (id == II_rand[identifierid])
354 break;
355
356 if (identifierid >= num_rands)
357 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000358
Ted Kremenek24650472009-09-02 02:47:41 +0000359 const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
360 if (!FTP)
361 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000362
Ted Kremenek24650472009-09-02 02:47:41 +0000363 if (FTP->getNumArgs() == 1) {
364 // Is the argument an 'unsigned short *'?
365 // (Actually any integer type is allowed.)
366 const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
367 if (!PT)
368 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000369
Ted Kremenek24650472009-09-02 02:47:41 +0000370 if (! PT->getPointeeType()->isIntegerType())
371 return;
372 }
Mike Stump1eb44332009-09-09 15:08:12 +0000373 else if (FTP->getNumArgs() != 0)
Ted Kremenek24650472009-09-02 02:47:41 +0000374 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000375
Ted Kremenek24650472009-09-02 02:47:41 +0000376 // Issue a warning.
377 std::string buf1;
378 llvm::raw_string_ostream os1(buf1);
379 os1 << "'" << FD->getNameAsString() << "' is a poor random number generator";
380
381 std::string buf2;
382 llvm::raw_string_ostream os2(buf2);
383 os2 << "Function '" << FD->getNameAsString()
384 << "' is obsolete because it implements a poor random number generator."
385 << " Use 'arc4random' instead";
386
387 SourceRange R = CE->getCallee()->getSourceRange();
Mike Stump1eb44332009-09-09 15:08:12 +0000388
Benjamin Kramerf0171732009-11-29 18:27:55 +0000389 BR.EmitBasicReport(os1.str(), "Security", os2.str(),
Ted Kremenek24650472009-09-02 02:47:41 +0000390 CE->getLocStart(), &R, 1);
391}
392
393//===----------------------------------------------------------------------===//
394// Check: 'random' should not be used
395// Originally: <rdar://problem/63371000>
396//===----------------------------------------------------------------------===//
397
398void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
399 if (FD->getIdentifier() != GetIdentifier(II_random, "random"))
400 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000401
Ted Kremenek24650472009-09-02 02:47:41 +0000402 const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
403 if (!FTP)
404 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000405
Ted Kremenek24650472009-09-02 02:47:41 +0000406 // Verify that the function takes no argument.
407 if (FTP->getNumArgs() != 0)
408 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000409
Ted Kremenek24650472009-09-02 02:47:41 +0000410 // Issue a warning.
411 SourceRange R = CE->getCallee()->getSourceRange();
412 BR.EmitBasicReport("'random' is not a secure random number generator",
413 "Security",
414 "The 'random' function produces a sequence of values that "
415 "an adversary may be able to predict. Use 'arc4random' "
416 "instead",
417 CE->getLocStart(), &R, 1);
418}
419
420//===----------------------------------------------------------------------===//
Ted Kremenek65a81a92009-08-28 00:08:09 +0000421// Check: Should check whether privileges are dropped successfully.
422// Originally: <rdar://problem/6337132>
423//===----------------------------------------------------------------------===//
424
425void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
426 const FunctionDecl *FD = CE->getDirectCallee();
427 if (!FD)
428 return;
429
430 if (II_setid[0] == NULL) {
Ted Kremenek24650472009-09-02 02:47:41 +0000431 static const char * const identifiers[num_setids] = {
Ted Kremenek65a81a92009-08-28 00:08:09 +0000432 "setuid", "setgid", "seteuid", "setegid",
433 "setreuid", "setregid"
434 };
Mike Stump1eb44332009-09-09 15:08:12 +0000435
Ted Kremenek24650472009-09-02 02:47:41 +0000436 for (size_t i = 0; i < num_setids; i++)
Mike Stump1eb44332009-09-09 15:08:12 +0000437 II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
Ted Kremenek65a81a92009-08-28 00:08:09 +0000438 }
Mike Stump1eb44332009-09-09 15:08:12 +0000439
Ted Kremenek65a81a92009-08-28 00:08:09 +0000440 const IdentifierInfo *id = FD->getIdentifier();
441 size_t identifierid;
442
Ted Kremenek24650472009-09-02 02:47:41 +0000443 for (identifierid = 0; identifierid < num_setids; identifierid++)
Ted Kremenek65a81a92009-08-28 00:08:09 +0000444 if (id == II_setid[identifierid])
445 break;
446
Ted Kremenek24650472009-09-02 02:47:41 +0000447 if (identifierid >= num_setids)
Ted Kremenek65a81a92009-08-28 00:08:09 +0000448 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000449
Ted Kremenek65a81a92009-08-28 00:08:09 +0000450 const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
451 if (!FTP)
452 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000453
Ted Kremeneka8187832009-08-28 00:24:55 +0000454 // Verify that the function takes one or two arguments (depending on
455 // the function).
Ted Kremenek65a81a92009-08-28 00:08:09 +0000456 if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
457 return;
458
459 // The arguments must be integers.
460 for (unsigned i = 0; i < FTP->getNumArgs(); i++)
461 if (! FTP->getArgType(i)->isIntegerType())
462 return;
463
464 // Issue a warning.
465 std::string buf1;
466 llvm::raw_string_ostream os1(buf1);
467 os1 << "Return value is not checked in call to '" << FD->getNameAsString()
468 << "'";
469
470 std::string buf2;
471 llvm::raw_string_ostream os2(buf2);
472 os2 << "The return value from the call to '" << FD->getNameAsString()
473 << "' is not checked. If an error occurs in '"
474 << FD->getNameAsString()
475 << "', the following code may execute with unexpected privileges";
476
477 SourceRange R = CE->getCallee()->getSourceRange();
Mike Stump1eb44332009-09-09 15:08:12 +0000478
Benjamin Kramerf0171732009-11-29 18:27:55 +0000479 BR.EmitBasicReport(os1.str(), "Security", os2.str(),
Ted Kremenek65a81a92009-08-28 00:08:09 +0000480 CE->getLocStart(), &R, 1);
481}
482
483//===----------------------------------------------------------------------===//
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000484// Entry point for check.
485//===----------------------------------------------------------------------===//
486
Mike Stump1eb44332009-09-09 15:08:12 +0000487void clang::CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR) {
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000488 WalkAST walker(BR);
Mike Stump1eb44332009-09-09 15:08:12 +0000489 walker.Visit(D->getBody());
Ted Kremenekdbfb5f82009-07-23 01:07:19 +0000490}