1*d99bd55aSTed Kremenek //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
2*d99bd55aSTed Kremenek //
3*d99bd55aSTed Kremenek //                     The LLVM Compiler Infrastructure
4*d99bd55aSTed Kremenek //
5*d99bd55aSTed Kremenek // This file is distributed under the University of Illinois Open Source
6*d99bd55aSTed Kremenek // License. See LICENSE.TXT for details.
7*d99bd55aSTed Kremenek //
8*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
9*d99bd55aSTed Kremenek //
10*d99bd55aSTed Kremenek //  This file defines a set of flow-insensitive security checks.
11*d99bd55aSTed Kremenek //
12*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
13*d99bd55aSTed Kremenek 
14*d99bd55aSTed Kremenek #include "clang/Basic/TargetInfo.h"
15*d99bd55aSTed Kremenek #include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
16*d99bd55aSTed Kremenek #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
17*d99bd55aSTed Kremenek #include "clang/AST/StmtVisitor.h"
18*d99bd55aSTed Kremenek #include "llvm/Support/raw_ostream.h"
19*d99bd55aSTed Kremenek 
20*d99bd55aSTed Kremenek using namespace clang;
21*d99bd55aSTed Kremenek using namespace ento;
22*d99bd55aSTed Kremenek 
23*d99bd55aSTed Kremenek static bool isArc4RandomAvailable(const ASTContext &Ctx) {
24*d99bd55aSTed Kremenek   const llvm::Triple &T = Ctx.Target.getTriple();
25*d99bd55aSTed Kremenek   return T.getVendor() == llvm::Triple::Apple ||
26*d99bd55aSTed Kremenek          T.getOS() == llvm::Triple::FreeBSD;
27*d99bd55aSTed Kremenek }
28*d99bd55aSTed Kremenek 
29*d99bd55aSTed Kremenek namespace {
30*d99bd55aSTed Kremenek class WalkAST : public StmtVisitor<WalkAST> {
31*d99bd55aSTed Kremenek   BugReporter &BR;
32*d99bd55aSTed Kremenek   IdentifierInfo *II_gets;
33*d99bd55aSTed Kremenek   IdentifierInfo *II_getpw;
34*d99bd55aSTed Kremenek   IdentifierInfo *II_mktemp;
35*d99bd55aSTed Kremenek   enum { num_rands = 9 };
36*d99bd55aSTed Kremenek   IdentifierInfo *II_rand[num_rands];
37*d99bd55aSTed Kremenek   IdentifierInfo *II_random;
38*d99bd55aSTed Kremenek   enum { num_setids = 6 };
39*d99bd55aSTed Kremenek   IdentifierInfo *II_setid[num_setids];
40*d99bd55aSTed Kremenek 
41*d99bd55aSTed Kremenek   const bool CheckRand;
42*d99bd55aSTed Kremenek 
43*d99bd55aSTed Kremenek public:
44*d99bd55aSTed Kremenek   WalkAST(BugReporter &br) : BR(br),
45*d99bd55aSTed Kremenek                              II_gets(0), II_getpw(0), II_mktemp(0),
46*d99bd55aSTed Kremenek                              II_rand(), II_random(0), II_setid(),
47*d99bd55aSTed Kremenek                  CheckRand(isArc4RandomAvailable(BR.getContext())) {}
48*d99bd55aSTed Kremenek 
49*d99bd55aSTed Kremenek   // Statement visitor methods.
50*d99bd55aSTed Kremenek   void VisitCallExpr(CallExpr *CE);
51*d99bd55aSTed Kremenek   void VisitForStmt(ForStmt *S);
52*d99bd55aSTed Kremenek   void VisitCompoundStmt (CompoundStmt *S);
53*d99bd55aSTed Kremenek   void VisitStmt(Stmt *S) { VisitChildren(S); }
54*d99bd55aSTed Kremenek 
55*d99bd55aSTed Kremenek   void VisitChildren(Stmt *S);
56*d99bd55aSTed Kremenek 
57*d99bd55aSTed Kremenek   // Helpers.
58*d99bd55aSTed Kremenek   IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str);
59*d99bd55aSTed Kremenek 
60*d99bd55aSTed Kremenek   // Checker-specific methods.
61*d99bd55aSTed Kremenek   void CheckLoopConditionForFloat(const ForStmt *FS);
62*d99bd55aSTed Kremenek   void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
63*d99bd55aSTed Kremenek   void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
64*d99bd55aSTed Kremenek   void CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
65*d99bd55aSTed Kremenek   void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
66*d99bd55aSTed Kremenek   void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
67*d99bd55aSTed Kremenek   void CheckUncheckedReturnValue(CallExpr *CE);
68*d99bd55aSTed Kremenek };
69*d99bd55aSTed Kremenek } // end anonymous namespace
70*d99bd55aSTed Kremenek 
71*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
72*d99bd55aSTed Kremenek // Helper methods.
73*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
74*d99bd55aSTed Kremenek 
75*d99bd55aSTed Kremenek IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) {
76*d99bd55aSTed Kremenek   if (!II)
77*d99bd55aSTed Kremenek     II = &BR.getContext().Idents.get(str);
78*d99bd55aSTed Kremenek 
79*d99bd55aSTed Kremenek   return II;
80*d99bd55aSTed Kremenek }
81*d99bd55aSTed Kremenek 
82*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
83*d99bd55aSTed Kremenek // AST walking.
84*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
85*d99bd55aSTed Kremenek 
86*d99bd55aSTed Kremenek void WalkAST::VisitChildren(Stmt *S) {
87*d99bd55aSTed Kremenek   for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
88*d99bd55aSTed Kremenek     if (Stmt *child = *I)
89*d99bd55aSTed Kremenek       Visit(child);
90*d99bd55aSTed Kremenek }
91*d99bd55aSTed Kremenek 
92*d99bd55aSTed Kremenek void WalkAST::VisitCallExpr(CallExpr *CE) {
93*d99bd55aSTed Kremenek   if (const FunctionDecl *FD = CE->getDirectCallee()) {
94*d99bd55aSTed Kremenek     CheckCall_gets(CE, FD);
95*d99bd55aSTed Kremenek     CheckCall_getpw(CE, FD);
96*d99bd55aSTed Kremenek     CheckCall_mktemp(CE, FD);
97*d99bd55aSTed Kremenek     if (CheckRand) {
98*d99bd55aSTed Kremenek       CheckCall_rand(CE, FD);
99*d99bd55aSTed Kremenek       CheckCall_random(CE, FD);
100*d99bd55aSTed Kremenek     }
101*d99bd55aSTed Kremenek   }
102*d99bd55aSTed Kremenek 
103*d99bd55aSTed Kremenek   // Recurse and check children.
104*d99bd55aSTed Kremenek   VisitChildren(CE);
105*d99bd55aSTed Kremenek }
106*d99bd55aSTed Kremenek 
107*d99bd55aSTed Kremenek void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
108*d99bd55aSTed Kremenek   for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
109*d99bd55aSTed Kremenek     if (Stmt *child = *I) {
110*d99bd55aSTed Kremenek       if (CallExpr *CE = dyn_cast<CallExpr>(child))
111*d99bd55aSTed Kremenek         CheckUncheckedReturnValue(CE);
112*d99bd55aSTed Kremenek       Visit(child);
113*d99bd55aSTed Kremenek     }
114*d99bd55aSTed Kremenek }
115*d99bd55aSTed Kremenek 
116*d99bd55aSTed Kremenek void WalkAST::VisitForStmt(ForStmt *FS) {
117*d99bd55aSTed Kremenek   CheckLoopConditionForFloat(FS);
118*d99bd55aSTed Kremenek 
119*d99bd55aSTed Kremenek   // Recurse and check children.
120*d99bd55aSTed Kremenek   VisitChildren(FS);
121*d99bd55aSTed Kremenek }
122*d99bd55aSTed Kremenek 
123*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
124*d99bd55aSTed Kremenek // Check: floating poing variable used as loop counter.
125*d99bd55aSTed Kremenek // Originally: <rdar://problem/6336718>
126*d99bd55aSTed Kremenek // Implements: CERT security coding advisory FLP-30.
127*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
128*d99bd55aSTed Kremenek 
129*d99bd55aSTed Kremenek static const DeclRefExpr*
130*d99bd55aSTed Kremenek GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
131*d99bd55aSTed Kremenek   expr = expr->IgnoreParenCasts();
132*d99bd55aSTed Kremenek 
133*d99bd55aSTed Kremenek   if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
134*d99bd55aSTed Kremenek     if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
135*d99bd55aSTed Kremenek           B->getOpcode() == BO_Comma))
136*d99bd55aSTed Kremenek       return NULL;
137*d99bd55aSTed Kremenek 
138*d99bd55aSTed Kremenek     if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y))
139*d99bd55aSTed Kremenek       return lhs;
140*d99bd55aSTed Kremenek 
141*d99bd55aSTed Kremenek     if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y))
142*d99bd55aSTed Kremenek       return rhs;
143*d99bd55aSTed Kremenek 
144*d99bd55aSTed Kremenek     return NULL;
145*d99bd55aSTed Kremenek   }
146*d99bd55aSTed Kremenek 
147*d99bd55aSTed Kremenek   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
148*d99bd55aSTed Kremenek     const NamedDecl *ND = DR->getDecl();
149*d99bd55aSTed Kremenek     return ND == x || ND == y ? DR : NULL;
150*d99bd55aSTed Kremenek   }
151*d99bd55aSTed Kremenek 
152*d99bd55aSTed Kremenek   if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
153*d99bd55aSTed Kremenek     return U->isIncrementDecrementOp()
154*d99bd55aSTed Kremenek       ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL;
155*d99bd55aSTed Kremenek 
156*d99bd55aSTed Kremenek   return NULL;
157*d99bd55aSTed Kremenek }
158*d99bd55aSTed Kremenek 
159*d99bd55aSTed Kremenek /// CheckLoopConditionForFloat - This check looks for 'for' statements that
160*d99bd55aSTed Kremenek ///  use a floating point variable as a loop counter.
161*d99bd55aSTed Kremenek ///  CERT: FLP30-C, FLP30-CPP.
162*d99bd55aSTed Kremenek ///
163*d99bd55aSTed Kremenek void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
164*d99bd55aSTed Kremenek   // Does the loop have a condition?
165*d99bd55aSTed Kremenek   const Expr *condition = FS->getCond();
166*d99bd55aSTed Kremenek 
167*d99bd55aSTed Kremenek   if (!condition)
168*d99bd55aSTed Kremenek     return;
169*d99bd55aSTed Kremenek 
170*d99bd55aSTed Kremenek   // Does the loop have an increment?
171*d99bd55aSTed Kremenek   const Expr *increment = FS->getInc();
172*d99bd55aSTed Kremenek 
173*d99bd55aSTed Kremenek   if (!increment)
174*d99bd55aSTed Kremenek     return;
175*d99bd55aSTed Kremenek 
176*d99bd55aSTed Kremenek   // Strip away '()' and casts.
177*d99bd55aSTed Kremenek   condition = condition->IgnoreParenCasts();
178*d99bd55aSTed Kremenek   increment = increment->IgnoreParenCasts();
179*d99bd55aSTed Kremenek 
180*d99bd55aSTed Kremenek   // Is the loop condition a comparison?
181*d99bd55aSTed Kremenek   const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
182*d99bd55aSTed Kremenek 
183*d99bd55aSTed Kremenek   if (!B)
184*d99bd55aSTed Kremenek     return;
185*d99bd55aSTed Kremenek 
186*d99bd55aSTed Kremenek   // Is this a comparison?
187*d99bd55aSTed Kremenek   if (!(B->isRelationalOp() || B->isEqualityOp()))
188*d99bd55aSTed Kremenek     return;
189*d99bd55aSTed Kremenek 
190*d99bd55aSTed Kremenek   // Are we comparing variables?
191*d99bd55aSTed Kremenek   const DeclRefExpr *drLHS =
192*d99bd55aSTed Kremenek     dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
193*d99bd55aSTed Kremenek   const DeclRefExpr *drRHS =
194*d99bd55aSTed Kremenek     dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
195*d99bd55aSTed Kremenek 
196*d99bd55aSTed Kremenek   // Does at least one of the variables have a floating point type?
197*d99bd55aSTed Kremenek   drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : NULL;
198*d99bd55aSTed Kremenek   drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : NULL;
199*d99bd55aSTed Kremenek 
200*d99bd55aSTed Kremenek   if (!drLHS && !drRHS)
201*d99bd55aSTed Kremenek     return;
202*d99bd55aSTed Kremenek 
203*d99bd55aSTed Kremenek   const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
204*d99bd55aSTed Kremenek   const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;
205*d99bd55aSTed Kremenek 
206*d99bd55aSTed Kremenek   if (!vdLHS && !vdRHS)
207*d99bd55aSTed Kremenek     return;
208*d99bd55aSTed Kremenek 
209*d99bd55aSTed Kremenek   // Does either variable appear in increment?
210*d99bd55aSTed Kremenek   const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS);
211*d99bd55aSTed Kremenek 
212*d99bd55aSTed Kremenek   if (!drInc)
213*d99bd55aSTed Kremenek     return;
214*d99bd55aSTed Kremenek 
215*d99bd55aSTed Kremenek   // Emit the error.  First figure out which DeclRefExpr in the condition
216*d99bd55aSTed Kremenek   // referenced the compared variable.
217*d99bd55aSTed Kremenek   const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
218*d99bd55aSTed Kremenek 
219*d99bd55aSTed Kremenek   llvm::SmallVector<SourceRange, 2> ranges;
220*d99bd55aSTed Kremenek   llvm::SmallString<256> sbuf;
221*d99bd55aSTed Kremenek   llvm::raw_svector_ostream os(sbuf);
222*d99bd55aSTed Kremenek 
223*d99bd55aSTed Kremenek   os << "Variable '" << drCond->getDecl()->getName()
224*d99bd55aSTed Kremenek      << "' with floating point type '" << drCond->getType().getAsString()
225*d99bd55aSTed Kremenek      << "' should not be used as a loop counter";
226*d99bd55aSTed Kremenek 
227*d99bd55aSTed Kremenek   ranges.push_back(drCond->getSourceRange());
228*d99bd55aSTed Kremenek   ranges.push_back(drInc->getSourceRange());
229*d99bd55aSTed Kremenek 
230*d99bd55aSTed Kremenek   const char *bugType = "Floating point variable used as loop counter";
231*d99bd55aSTed Kremenek   BR.EmitBasicReport(bugType, "Security", os.str(),
232*d99bd55aSTed Kremenek                      FS->getLocStart(), ranges.data(), ranges.size());
233*d99bd55aSTed Kremenek }
234*d99bd55aSTed Kremenek 
235*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
236*d99bd55aSTed Kremenek // Check: Any use of 'gets' is insecure.
237*d99bd55aSTed Kremenek // Originally: <rdar://problem/6335715>
238*d99bd55aSTed Kremenek // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
239*d99bd55aSTed Kremenek // CWE-242: Use of Inherently Dangerous Function
240*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
241*d99bd55aSTed Kremenek 
242*d99bd55aSTed Kremenek void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
243*d99bd55aSTed Kremenek   if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
244*d99bd55aSTed Kremenek     return;
245*d99bd55aSTed Kremenek 
246*d99bd55aSTed Kremenek   const FunctionProtoType *FPT
247*d99bd55aSTed Kremenek     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
248*d99bd55aSTed Kremenek   if (!FPT)
249*d99bd55aSTed Kremenek     return;
250*d99bd55aSTed Kremenek 
251*d99bd55aSTed Kremenek   // Verify that the function takes a single argument.
252*d99bd55aSTed Kremenek   if (FPT->getNumArgs() != 1)
253*d99bd55aSTed Kremenek     return;
254*d99bd55aSTed Kremenek 
255*d99bd55aSTed Kremenek   // Is the argument a 'char*'?
256*d99bd55aSTed Kremenek   const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
257*d99bd55aSTed Kremenek   if (!PT)
258*d99bd55aSTed Kremenek     return;
259*d99bd55aSTed Kremenek 
260*d99bd55aSTed Kremenek   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
261*d99bd55aSTed Kremenek     return;
262*d99bd55aSTed Kremenek 
263*d99bd55aSTed Kremenek   // Issue a warning.
264*d99bd55aSTed Kremenek   SourceRange R = CE->getCallee()->getSourceRange();
265*d99bd55aSTed Kremenek   BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
266*d99bd55aSTed Kremenek                      "Security",
267*d99bd55aSTed Kremenek                      "Call to function 'gets' is extremely insecure as it can "
268*d99bd55aSTed Kremenek                      "always result in a buffer overflow",
269*d99bd55aSTed Kremenek                      CE->getLocStart(), &R, 1);
270*d99bd55aSTed Kremenek }
271*d99bd55aSTed Kremenek 
272*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
273*d99bd55aSTed Kremenek // Check: Any use of 'getpwd' is insecure.
274*d99bd55aSTed Kremenek // CWE-477: Use of Obsolete Functions
275*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
276*d99bd55aSTed Kremenek 
277*d99bd55aSTed Kremenek void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
278*d99bd55aSTed Kremenek   if (FD->getIdentifier() != GetIdentifier(II_getpw, "getpw"))
279*d99bd55aSTed Kremenek     return;
280*d99bd55aSTed Kremenek 
281*d99bd55aSTed Kremenek   const FunctionProtoType *FPT
282*d99bd55aSTed Kremenek     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
283*d99bd55aSTed Kremenek   if (!FPT)
284*d99bd55aSTed Kremenek     return;
285*d99bd55aSTed Kremenek 
286*d99bd55aSTed Kremenek   // Verify that the function takes two arguments.
287*d99bd55aSTed Kremenek   if (FPT->getNumArgs() != 2)
288*d99bd55aSTed Kremenek     return;
289*d99bd55aSTed Kremenek 
290*d99bd55aSTed Kremenek   // Verify the first argument type is integer.
291*d99bd55aSTed Kremenek   if (!FPT->getArgType(0)->isIntegerType())
292*d99bd55aSTed Kremenek     return;
293*d99bd55aSTed Kremenek 
294*d99bd55aSTed Kremenek   // Verify the second argument type is char*.
295*d99bd55aSTed Kremenek   const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1));
296*d99bd55aSTed Kremenek   if (!PT)
297*d99bd55aSTed Kremenek     return;
298*d99bd55aSTed Kremenek 
299*d99bd55aSTed Kremenek   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
300*d99bd55aSTed Kremenek     return;
301*d99bd55aSTed Kremenek 
302*d99bd55aSTed Kremenek   // Issue a warning.
303*d99bd55aSTed Kremenek   SourceRange R = CE->getCallee()->getSourceRange();
304*d99bd55aSTed Kremenek   BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'",
305*d99bd55aSTed Kremenek                      "Security",
306*d99bd55aSTed Kremenek                      "The getpw() function is dangerous as it may overflow the "
307*d99bd55aSTed Kremenek                      "provided buffer. It is obsoleted by getpwuid().",
308*d99bd55aSTed Kremenek                      CE->getLocStart(), &R, 1);
309*d99bd55aSTed Kremenek }
310*d99bd55aSTed Kremenek 
311*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
312*d99bd55aSTed Kremenek // Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp().
313*d99bd55aSTed Kremenek // CWE-377: Insecure Temporary File
314*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
315*d99bd55aSTed Kremenek 
316*d99bd55aSTed Kremenek void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
317*d99bd55aSTed Kremenek   if (FD->getIdentifier() != GetIdentifier(II_mktemp, "mktemp"))
318*d99bd55aSTed Kremenek     return;
319*d99bd55aSTed Kremenek 
320*d99bd55aSTed Kremenek   const FunctionProtoType *FPT
321*d99bd55aSTed Kremenek     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
322*d99bd55aSTed Kremenek   if(!FPT)
323*d99bd55aSTed Kremenek     return;
324*d99bd55aSTed Kremenek 
325*d99bd55aSTed Kremenek   // Verify that the funcion takes a single argument.
326*d99bd55aSTed Kremenek   if (FPT->getNumArgs() != 1)
327*d99bd55aSTed Kremenek     return;
328*d99bd55aSTed Kremenek 
329*d99bd55aSTed Kremenek   // Verify that the argument is Pointer Type.
330*d99bd55aSTed Kremenek   const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
331*d99bd55aSTed Kremenek   if (!PT)
332*d99bd55aSTed Kremenek     return;
333*d99bd55aSTed Kremenek 
334*d99bd55aSTed Kremenek   // Verify that the argument is a 'char*'.
335*d99bd55aSTed Kremenek   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
336*d99bd55aSTed Kremenek     return;
337*d99bd55aSTed Kremenek 
338*d99bd55aSTed Kremenek   // Issue a waring.
339*d99bd55aSTed Kremenek   SourceRange R = CE->getCallee()->getSourceRange();
340*d99bd55aSTed Kremenek   BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
341*d99bd55aSTed Kremenek                      "Security",
342*d99bd55aSTed Kremenek                      "Call to function 'mktemp' is insecure as it always "
343*d99bd55aSTed Kremenek                      "creates or uses insecure temporary file.  Use 'mkstemp' instead",
344*d99bd55aSTed Kremenek                      CE->getLocStart(), &R, 1);
345*d99bd55aSTed Kremenek }
346*d99bd55aSTed Kremenek 
347*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
348*d99bd55aSTed Kremenek // Check: Linear congruent random number generators should not be used
349*d99bd55aSTed Kremenek // Originally: <rdar://problem/63371000>
350*d99bd55aSTed Kremenek // CWE-338: Use of cryptographically weak prng
351*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
352*d99bd55aSTed Kremenek 
353*d99bd55aSTed Kremenek void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
354*d99bd55aSTed Kremenek   if (II_rand[0] == NULL) {
355*d99bd55aSTed Kremenek     // This check applies to these functions
356*d99bd55aSTed Kremenek     static const char * const identifiers[num_rands] = {
357*d99bd55aSTed Kremenek       "drand48", "erand48", "jrand48", "lrand48", "mrand48", "nrand48",
358*d99bd55aSTed Kremenek       "lcong48",
359*d99bd55aSTed Kremenek       "rand", "rand_r"
360*d99bd55aSTed Kremenek     };
361*d99bd55aSTed Kremenek 
362*d99bd55aSTed Kremenek     for (size_t i = 0; i < num_rands; i++)
363*d99bd55aSTed Kremenek       II_rand[i] = &BR.getContext().Idents.get(identifiers[i]);
364*d99bd55aSTed Kremenek   }
365*d99bd55aSTed Kremenek 
366*d99bd55aSTed Kremenek   const IdentifierInfo *id = FD->getIdentifier();
367*d99bd55aSTed Kremenek   size_t identifierid;
368*d99bd55aSTed Kremenek 
369*d99bd55aSTed Kremenek   for (identifierid = 0; identifierid < num_rands; identifierid++)
370*d99bd55aSTed Kremenek     if (id == II_rand[identifierid])
371*d99bd55aSTed Kremenek       break;
372*d99bd55aSTed Kremenek 
373*d99bd55aSTed Kremenek   if (identifierid >= num_rands)
374*d99bd55aSTed Kremenek     return;
375*d99bd55aSTed Kremenek 
376*d99bd55aSTed Kremenek   const FunctionProtoType *FTP
377*d99bd55aSTed Kremenek     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
378*d99bd55aSTed Kremenek   if (!FTP)
379*d99bd55aSTed Kremenek     return;
380*d99bd55aSTed Kremenek 
381*d99bd55aSTed Kremenek   if (FTP->getNumArgs() == 1) {
382*d99bd55aSTed Kremenek     // Is the argument an 'unsigned short *'?
383*d99bd55aSTed Kremenek     // (Actually any integer type is allowed.)
384*d99bd55aSTed Kremenek     const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
385*d99bd55aSTed Kremenek     if (!PT)
386*d99bd55aSTed Kremenek       return;
387*d99bd55aSTed Kremenek 
388*d99bd55aSTed Kremenek     if (! PT->getPointeeType()->isIntegerType())
389*d99bd55aSTed Kremenek       return;
390*d99bd55aSTed Kremenek   }
391*d99bd55aSTed Kremenek   else if (FTP->getNumArgs() != 0)
392*d99bd55aSTed Kremenek     return;
393*d99bd55aSTed Kremenek 
394*d99bd55aSTed Kremenek   // Issue a warning.
395*d99bd55aSTed Kremenek   llvm::SmallString<256> buf1;
396*d99bd55aSTed Kremenek   llvm::raw_svector_ostream os1(buf1);
397*d99bd55aSTed Kremenek   os1 << '\'' << FD << "' is a poor random number generator";
398*d99bd55aSTed Kremenek 
399*d99bd55aSTed Kremenek   llvm::SmallString<256> buf2;
400*d99bd55aSTed Kremenek   llvm::raw_svector_ostream os2(buf2);
401*d99bd55aSTed Kremenek   os2 << "Function '" << FD
402*d99bd55aSTed Kremenek       << "' is obsolete because it implements a poor random number generator."
403*d99bd55aSTed Kremenek       << "  Use 'arc4random' instead";
404*d99bd55aSTed Kremenek 
405*d99bd55aSTed Kremenek   SourceRange R = CE->getCallee()->getSourceRange();
406*d99bd55aSTed Kremenek   BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
407*d99bd55aSTed Kremenek }
408*d99bd55aSTed Kremenek 
409*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
410*d99bd55aSTed Kremenek // Check: 'random' should not be used
411*d99bd55aSTed Kremenek // Originally: <rdar://problem/63371000>
412*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
413*d99bd55aSTed Kremenek 
414*d99bd55aSTed Kremenek void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
415*d99bd55aSTed Kremenek   if (FD->getIdentifier() != GetIdentifier(II_random, "random"))
416*d99bd55aSTed Kremenek     return;
417*d99bd55aSTed Kremenek 
418*d99bd55aSTed Kremenek   const FunctionProtoType *FTP
419*d99bd55aSTed Kremenek     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
420*d99bd55aSTed Kremenek   if (!FTP)
421*d99bd55aSTed Kremenek     return;
422*d99bd55aSTed Kremenek 
423*d99bd55aSTed Kremenek   // Verify that the function takes no argument.
424*d99bd55aSTed Kremenek   if (FTP->getNumArgs() != 0)
425*d99bd55aSTed Kremenek     return;
426*d99bd55aSTed Kremenek 
427*d99bd55aSTed Kremenek   // Issue a warning.
428*d99bd55aSTed Kremenek   SourceRange R = CE->getCallee()->getSourceRange();
429*d99bd55aSTed Kremenek   BR.EmitBasicReport("'random' is not a secure random number generator",
430*d99bd55aSTed Kremenek                      "Security",
431*d99bd55aSTed Kremenek                      "The 'random' function produces a sequence of values that "
432*d99bd55aSTed Kremenek                      "an adversary may be able to predict.  Use 'arc4random' "
433*d99bd55aSTed Kremenek                      "instead", CE->getLocStart(), &R, 1);
434*d99bd55aSTed Kremenek }
435*d99bd55aSTed Kremenek 
436*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
437*d99bd55aSTed Kremenek // Check: Should check whether privileges are dropped successfully.
438*d99bd55aSTed Kremenek // Originally: <rdar://problem/6337132>
439*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
440*d99bd55aSTed Kremenek 
441*d99bd55aSTed Kremenek void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
442*d99bd55aSTed Kremenek   const FunctionDecl *FD = CE->getDirectCallee();
443*d99bd55aSTed Kremenek   if (!FD)
444*d99bd55aSTed Kremenek     return;
445*d99bd55aSTed Kremenek 
446*d99bd55aSTed Kremenek   if (II_setid[0] == NULL) {
447*d99bd55aSTed Kremenek     static const char * const identifiers[num_setids] = {
448*d99bd55aSTed Kremenek       "setuid", "setgid", "seteuid", "setegid",
449*d99bd55aSTed Kremenek       "setreuid", "setregid"
450*d99bd55aSTed Kremenek     };
451*d99bd55aSTed Kremenek 
452*d99bd55aSTed Kremenek     for (size_t i = 0; i < num_setids; i++)
453*d99bd55aSTed Kremenek       II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
454*d99bd55aSTed Kremenek   }
455*d99bd55aSTed Kremenek 
456*d99bd55aSTed Kremenek   const IdentifierInfo *id = FD->getIdentifier();
457*d99bd55aSTed Kremenek   size_t identifierid;
458*d99bd55aSTed Kremenek 
459*d99bd55aSTed Kremenek   for (identifierid = 0; identifierid < num_setids; identifierid++)
460*d99bd55aSTed Kremenek     if (id == II_setid[identifierid])
461*d99bd55aSTed Kremenek       break;
462*d99bd55aSTed Kremenek 
463*d99bd55aSTed Kremenek   if (identifierid >= num_setids)
464*d99bd55aSTed Kremenek     return;
465*d99bd55aSTed Kremenek 
466*d99bd55aSTed Kremenek   const FunctionProtoType *FTP
467*d99bd55aSTed Kremenek     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
468*d99bd55aSTed Kremenek   if (!FTP)
469*d99bd55aSTed Kremenek     return;
470*d99bd55aSTed Kremenek 
471*d99bd55aSTed Kremenek   // Verify that the function takes one or two arguments (depending on
472*d99bd55aSTed Kremenek   //   the function).
473*d99bd55aSTed Kremenek   if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
474*d99bd55aSTed Kremenek     return;
475*d99bd55aSTed Kremenek 
476*d99bd55aSTed Kremenek   // The arguments must be integers.
477*d99bd55aSTed Kremenek   for (unsigned i = 0; i < FTP->getNumArgs(); i++)
478*d99bd55aSTed Kremenek     if (! FTP->getArgType(i)->isIntegerType())
479*d99bd55aSTed Kremenek       return;
480*d99bd55aSTed Kremenek 
481*d99bd55aSTed Kremenek   // Issue a warning.
482*d99bd55aSTed Kremenek   llvm::SmallString<256> buf1;
483*d99bd55aSTed Kremenek   llvm::raw_svector_ostream os1(buf1);
484*d99bd55aSTed Kremenek   os1 << "Return value is not checked in call to '" << FD << '\'';
485*d99bd55aSTed Kremenek 
486*d99bd55aSTed Kremenek   llvm::SmallString<256> buf2;
487*d99bd55aSTed Kremenek   llvm::raw_svector_ostream os2(buf2);
488*d99bd55aSTed Kremenek   os2 << "The return value from the call to '" << FD
489*d99bd55aSTed Kremenek       << "' is not checked.  If an error occurs in '" << FD
490*d99bd55aSTed Kremenek       << "', the following code may execute with unexpected privileges";
491*d99bd55aSTed Kremenek 
492*d99bd55aSTed Kremenek   SourceRange R = CE->getCallee()->getSourceRange();
493*d99bd55aSTed Kremenek   BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
494*d99bd55aSTed Kremenek }
495*d99bd55aSTed Kremenek 
496*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
497*d99bd55aSTed Kremenek // Entry point for check.
498*d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
499*d99bd55aSTed Kremenek 
500*d99bd55aSTed Kremenek void ento::CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR) {
501*d99bd55aSTed Kremenek   WalkAST walker(BR);
502*d99bd55aSTed Kremenek   walker.Visit(D->getBody());
503*d99bd55aSTed Kremenek }
504