xref: /src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1ac9a064cSDimitry Andric //== PutenvStackArrayChecker.cpp ------------------------------- -*- C++ -*--=//
2ac9a064cSDimitry Andric //
3ac9a064cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ac9a064cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5ac9a064cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ac9a064cSDimitry Andric //
7ac9a064cSDimitry Andric //===----------------------------------------------------------------------===//
8ac9a064cSDimitry Andric //
9ac9a064cSDimitry Andric // This file defines PutenvStackArrayChecker which finds calls of ``putenv``
10ac9a064cSDimitry Andric // function with automatic array variable as the argument.
11ac9a064cSDimitry Andric // https://wiki.sei.cmu.edu/confluence/x/6NYxBQ
12ac9a064cSDimitry Andric //
13ac9a064cSDimitry Andric //===----------------------------------------------------------------------===//
14ac9a064cSDimitry Andric 
15ac9a064cSDimitry Andric #include "AllocationState.h"
16ac9a064cSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
17ac9a064cSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
18ac9a064cSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
19ac9a064cSDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20ac9a064cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
21ac9a064cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
22ac9a064cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23ac9a064cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
24ac9a064cSDimitry Andric 
25ac9a064cSDimitry Andric using namespace clang;
26ac9a064cSDimitry Andric using namespace ento;
27ac9a064cSDimitry Andric 
28ac9a064cSDimitry Andric namespace {
29ac9a064cSDimitry Andric class PutenvStackArrayChecker : public Checker<check::PostCall> {
30ac9a064cSDimitry Andric private:
31ac9a064cSDimitry Andric   BugType BT{this, "'putenv' called with stack-allocated string",
32ac9a064cSDimitry Andric              categories::SecurityError};
33ac9a064cSDimitry Andric   const CallDescription Putenv{CDM::CLibrary, {"putenv"}, 1};
34ac9a064cSDimitry Andric 
35ac9a064cSDimitry Andric public:
36ac9a064cSDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
37ac9a064cSDimitry Andric };
38ac9a064cSDimitry Andric } // namespace
39ac9a064cSDimitry Andric 
checkPostCall(const CallEvent & Call,CheckerContext & C) const40ac9a064cSDimitry Andric void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
41ac9a064cSDimitry Andric                                             CheckerContext &C) const {
42ac9a064cSDimitry Andric   if (!Putenv.matches(Call))
43ac9a064cSDimitry Andric     return;
44ac9a064cSDimitry Andric 
45ac9a064cSDimitry Andric   SVal ArgV = Call.getArgSVal(0);
46ac9a064cSDimitry Andric   const Expr *ArgExpr = Call.getArgExpr(0);
47ac9a064cSDimitry Andric 
48ac9a064cSDimitry Andric   const auto *SSR =
49ac9a064cSDimitry Andric       dyn_cast<StackSpaceRegion>(ArgV.getAsRegion()->getMemorySpace());
50ac9a064cSDimitry Andric   if (!SSR)
51ac9a064cSDimitry Andric     return;
52ac9a064cSDimitry Andric   const auto *StackFrameFuncD =
53ac9a064cSDimitry Andric       dyn_cast_or_null<FunctionDecl>(SSR->getStackFrame()->getDecl());
54ac9a064cSDimitry Andric   if (StackFrameFuncD && StackFrameFuncD->isMain())
55ac9a064cSDimitry Andric     return;
56ac9a064cSDimitry Andric 
57ac9a064cSDimitry Andric   StringRef ErrorMsg = "The 'putenv' function should not be called with "
58ac9a064cSDimitry Andric                        "arrays that have automatic storage";
59ac9a064cSDimitry Andric   ExplodedNode *N = C.generateErrorNode();
60ac9a064cSDimitry Andric   auto Report = std::make_unique<PathSensitiveBugReport>(BT, ErrorMsg, N);
61ac9a064cSDimitry Andric 
62ac9a064cSDimitry Andric   // Track the argument.
63ac9a064cSDimitry Andric   bugreporter::trackExpressionValue(Report->getErrorNode(), ArgExpr, *Report);
64ac9a064cSDimitry Andric 
65ac9a064cSDimitry Andric   C.emitReport(std::move(Report));
66ac9a064cSDimitry Andric }
67ac9a064cSDimitry Andric 
registerPutenvStackArray(CheckerManager & Mgr)68ac9a064cSDimitry Andric void ento::registerPutenvStackArray(CheckerManager &Mgr) {
69ac9a064cSDimitry Andric   Mgr.registerChecker<PutenvStackArrayChecker>();
70ac9a064cSDimitry Andric }
71ac9a064cSDimitry Andric 
shouldRegisterPutenvStackArray(const CheckerManager &)72ac9a064cSDimitry Andric bool ento::shouldRegisterPutenvStackArray(const CheckerManager &) {
73ac9a064cSDimitry Andric   return true;
74ac9a064cSDimitry Andric }
75