In general, if we see an allocation, we associate the immutable memory space with the constructed memory region. This works fine if we see the allocation. However, with symbolic regions it's not great because there we don't know anything about their memory spaces, thus put them into the Unknown space. The unfortunate consequence is that once we learn about some aliasing with this Symbolic Region, we can't change the memory space to the deduced one. In this patch, we open up the memory spaces as a trait, basically allowing associating a better memory space with a memregion that was created with the Unknown memory space. As a side effect, this means that now queriing the memory space of a region depends on the State, but many places in the analyzer, such as the Store, doesn't have (and cannot have) access to the State by design. This means that some uses must solely rely on the memspaces of the region, but any other users should use the getter taking a State. Co-authored-by: Balazs Benics <benicsbalazs@gmail.com>
78 lines
2.7 KiB
C++
78 lines
2.7 KiB
C++
//== PutenvStackArrayChecker.cpp ------------------------------- -*- C++ -*--=//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines PutenvStackArrayChecker which finds calls of ``putenv``
|
|
// function with automatic array variable as the argument.
|
|
// https://wiki.sei.cmu.edu/confluence/x/6NYxBQ
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "AllocationState.h"
|
|
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
|
|
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
|
#include "clang/StaticAnalyzer/Core/Checker.h"
|
|
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
|
|
|
|
using namespace clang;
|
|
using namespace ento;
|
|
|
|
namespace {
|
|
class PutenvStackArrayChecker : public Checker<check::PostCall> {
|
|
private:
|
|
BugType BT{this, "'putenv' called with stack-allocated string",
|
|
categories::SecurityError};
|
|
const CallDescription Putenv{CDM::CLibrary, {"putenv"}, 1};
|
|
|
|
public:
|
|
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
|
|
};
|
|
} // namespace
|
|
|
|
void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
|
|
CheckerContext &C) const {
|
|
if (!Putenv.matches(Call))
|
|
return;
|
|
|
|
SVal ArgV = Call.getArgSVal(0);
|
|
const Expr *ArgExpr = Call.getArgExpr(0);
|
|
|
|
if (!ArgV.getAsRegion())
|
|
return;
|
|
|
|
const auto *SSR =
|
|
ArgV.getAsRegion()->getMemorySpaceAs<StackSpaceRegion>(C.getState());
|
|
if (!SSR)
|
|
return;
|
|
const auto *StackFrameFuncD =
|
|
dyn_cast_or_null<FunctionDecl>(SSR->getStackFrame()->getDecl());
|
|
if (StackFrameFuncD && StackFrameFuncD->isMain())
|
|
return;
|
|
|
|
StringRef ErrorMsg = "The 'putenv' function should not be called with "
|
|
"arrays that have automatic storage";
|
|
ExplodedNode *N = C.generateErrorNode();
|
|
auto Report = std::make_unique<PathSensitiveBugReport>(BT, ErrorMsg, N);
|
|
|
|
// Track the argument.
|
|
bugreporter::trackExpressionValue(Report->getErrorNode(), ArgExpr, *Report);
|
|
|
|
C.emitReport(std::move(Report));
|
|
}
|
|
|
|
void ento::registerPutenvStackArray(CheckerManager &Mgr) {
|
|
Mgr.registerChecker<PutenvStackArrayChecker>();
|
|
}
|
|
|
|
bool ento::shouldRegisterPutenvStackArray(const CheckerManager &) {
|
|
return true;
|
|
}
|