Commit 6fc8d15c authored by Yonghong Song's avatar Yonghong Song Committed by Brenden Blanco

fix clang frontend issues for fc26

In fc26, kernel config enables CONFIG_FORTIFY_SOURCE
in 4.13 kernel. This is not available in fc25.
This config is used to detect overflows of buffers in common string
and memory functions where the compiler can determine and
validate the buffer sizes.

When enabled, this option provides an implementation (body)
for certain string function. For example, in
/lib/modules/4.13.10-200.fc26.x86_64/build/include/linux/string.h,
you can find
...
extern void * memcpy(void *,const void *,__kernel_size_t);
...
__FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size)
{
        size_t p_size = __builtin_object_size(p, 0);
        size_t q_size = __builtin_object_size(q, 0);
        if (__builtin_constant_p(size)) {
                if (p_size < size)
                        __write_overflow();
                if (q_size < size)
                        __read_overflow2();
        }
        if (p_size < size || q_size < size)
                fortify_panic(__func__);
        return __builtin_memcpy(p, q, size);
}

In current clang frontend, we treat an external function with function body
as a rewritable target. We also assume the declaration of this external function,
if body is present, must have named arguments. This is largely true
for functions in bpf program file/text itself as these external functions often
do not have declarations.

We should not try to rewrite string/memory functions exposed by
CONFIG_FORTIFY_SOURCE. This patch adds restriction for rewritable function
only if the corresponding file is the main file with bpf program itself.

I discovered that it is possible file name is empty for tracepoint
functions, e.g.,
  TRACEPOINT_PROBE(irq, softirq_entry)
The reason could be function name itself is derived from helpers.h while
function declaration/body is in the main file after macro expansion.
Note that function name is still correctly derived by the compiler.
Signed-off-by: default avatarYonghong Song <yhs@fb.com>
parent a9a5ff71
......@@ -259,7 +259,7 @@ bool BTypeVisitor::VisitFunctionDecl(FunctionDecl *D) {
// put each non-static non-inline function decl in its own section, to be
// extracted by the MemoryManager
auto real_start_loc = rewriter_.getSourceMgr().getFileLoc(D->getLocStart());
if (D->isExternallyVisible() && D->hasBody()) {
if (fe_.is_rewritable_ext_func(D)) {
current_fn_ = D->getName();
string bd = rewriter_.getRewrittenText(expansionRange(D->getSourceRange()));
fe_.func_src_.set_src(current_fn_, bd);
......@@ -795,13 +795,16 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
// First traversal of AST to retrieve maps with external pointers.
BTypeConsumer::BTypeConsumer(ASTContext &C, BFrontendAction &fe,
Rewriter &rewriter, set<Decl *> &m) :
map_visitor_(m), btype_visitor_(C, fe), probe_visitor_(C, rewriter, m) {}
Rewriter &rewriter, set<Decl *> &m)
: fe_(fe),
map_visitor_(m),
btype_visitor_(C, fe),
probe_visitor_(C, rewriter, m) {}
bool BTypeConsumer::HandleTopLevelDecl(DeclGroupRef Group) {
for (auto D : Group) {
if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
if (F->isExternallyVisible() && F->hasBody()) {
if (fe_.is_rewritable_ext_func(F)) {
for (auto arg : F->parameters()) {
if (arg != F->getParamDecl(0) && !arg->getType()->isFundamentalType()) {
map_visitor_.set_ptreg(arg);
......@@ -825,7 +828,7 @@ void BTypeConsumer::HandleTranslationUnit(ASTContext &Context) {
for (it = DC->decls_begin(); it != DC->decls_end(); it++) {
Decl *D = *it;
if (FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
if (F->isExternallyVisible() && F->hasBody()) {
if (fe_.is_rewritable_ext_func(F)) {
for (auto arg : F->parameters()) {
if (arg != F->getParamDecl(0) && !arg->getType()->isFundamentalType())
probe_visitor_.set_ptreg(arg);
......@@ -840,15 +843,23 @@ void BTypeConsumer::HandleTranslationUnit(ASTContext &Context) {
BFrontendAction::BFrontendAction(llvm::raw_ostream &os, unsigned flags,
TableStorage &ts, const std::string &id,
const std::string &main_path,
FuncSource &func_src, std::string &mod_src)
: os_(os),
flags_(flags),
ts_(ts),
id_(id),
rewriter_(new Rewriter),
main_path_(main_path),
func_src_(func_src),
mod_src_(mod_src) {}
bool BFrontendAction::is_rewritable_ext_func(FunctionDecl *D) {
StringRef file_name = rewriter_->getSourceMgr().getFilename(D->getLocStart());
return (D->isExternallyVisible() && D->hasBody() &&
(file_name.empty() || file_name == main_path_));
}
void BFrontendAction::EndSourceFileAction() {
if (flags_ & DEBUG_PREPROCESSOR)
rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(llvm::errs());
......
......@@ -115,6 +115,7 @@ class BTypeConsumer : public clang::ASTConsumer {
bool HandleTopLevelDecl(clang::DeclGroupRef Group) override;
void HandleTranslationUnit(clang::ASTContext &Context) override;
private:
BFrontendAction &fe_;
MapVisitor map_visitor_;
BTypeVisitor btype_visitor_;
ProbeVisitor probe_visitor_;
......@@ -128,8 +129,8 @@ class BFrontendAction : public clang::ASTFrontendAction {
// Initialize with the output stream where the new source file contents
// should be written.
BFrontendAction(llvm::raw_ostream &os, unsigned flags, TableStorage &ts,
const std::string &id, FuncSource &func_src,
std::string &mod_src);
const std::string &id, const std::string &main_path,
FuncSource &func_src, std::string &mod_src);
// Called by clang when the AST has been completed, here the output stream
// will be flushed.
......@@ -141,6 +142,7 @@ class BFrontendAction : public clang::ASTFrontendAction {
clang::Rewriter &rewriter() const { return *rewriter_; }
TableStorage &table_storage() const { return ts_; }
std::string id() const { return id_; }
bool is_rewritable_ext_func(clang::FunctionDecl *D);
private:
llvm::raw_ostream &os_;
......@@ -150,6 +152,7 @@ class BFrontendAction : public clang::ASTFrontendAction {
std::unique_ptr<clang::Rewriter> rewriter_;
friend class BTypeVisitor;
std::map<std::string, clang::SourceRange> func_range_;
const std::string &main_path_;
FuncSource &func_src_;
std::string &mod_src_;
std::set<clang::Decl *> m_;
......
......@@ -316,7 +316,7 @@ int ClangLoader::do_compile(unique_ptr<llvm::Module> *mod, TableStorage &ts,
// capture the rewritten c file
string out_str1;
llvm::raw_string_ostream os1(out_str1);
BFrontendAction bact(os1, flags_, ts, id, func_src, mod_src);
BFrontendAction bact(os1, flags_, ts, id, main_path, func_src, mod_src);
if (!compiler1.ExecuteAction(bact))
return -1;
unique_ptr<llvm::MemoryBuffer> out_buf1 = llvm::MemoryBuffer::getMemBuffer(out_str1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment