From 4f601623cf7785cbe59e7f1da4c84cfa52ad5ee4 Mon Sep 17 00:00:00 2001 From: Juraj Vijtiuk Date: Sat, 22 Jun 2019 21:37:32 +0200 Subject: [PATCH] Add initial implementation of malloc off by one bugs --- scripts/lava.py | 4 +- scripts/lava.sh | 2 +- tools/fbi/src/find_bug_inj.cpp | 3 ++ tools/lavaODB/include/lava.hxx | 5 ++ .../include/MallocOffByOneArgHandler.h | 52 +++++++++++++++++++ tools/lavaTool/include/MatchFinder.h | 7 +++ 6 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 tools/lavaTool/include/MallocOffByOneArgHandler.h diff --git a/scripts/lava.py b/scripts/lava.py index dc458202..a32c42c5 100644 --- a/scripts/lava.py +++ b/scripts/lava.py @@ -160,6 +160,7 @@ def __str__(self): "ATP_POINTER_WRITE", "ATP_QUERY_POINT", "ATP_PRINTF_LEAK", + "ATP_MALLOC_OFF_BY_ONE" ] return 'ATP[{}](loc={}:{}, type={})'.format( self.id, self.loc.filename, self.loc.begin.line, type_strs[self.typ] @@ -181,9 +182,10 @@ class Bug(Base): RET_BUFFER = 1 REL_WRITE = 2 PRINTF_LEAK = 3 + MALLOC_OFF_BY_ONE = 4 # }; type_strings = ['BUG_PTR_ADD', 'BUG_RET_BUFFER', - 'BUG_REL_WRITE', 'BUG_PRINTF_LEAK'] + 'BUG_REL_WRITE', 'BUG_PRINTF_LEAK', 'MALLOC_OFF_BY_ONE'] id = Column(BigInteger, primary_key=True) type = Column(Integer) diff --git a/scripts/lava.sh b/scripts/lava.sh index d8a6421c..c14965b5 100755 --- a/scripts/lava.sh +++ b/scripts/lava.sh @@ -90,7 +90,7 @@ demo=0 curtail=0 ATP_TYPE="" # default bugtypes -bugtypes="ptr_add,rel_write" +bugtypes="ptr_add,rel_write,malloc_off_by_one" # default # of bugs to be injected at a time many=50 diff --git a/tools/fbi/src/find_bug_inj.cpp b/tools/fbi/src/find_bug_inj.cpp index 3f6b9f1b..3daec4ee 100644 --- a/tools/fbi/src/find_bug_inj.cpp +++ b/tools/fbi/src/find_bug_inj.cpp @@ -898,6 +898,9 @@ void attack_point_lval_usage(Panda__LogEntry *ple) { case AttackPoint::PRINTF_LEAK: record_injectable_bugs_at(atp, is_new_atp, { }); break; + case AttackPoint::MALLOC_OFF_BY_ONE: + record_injectable_bugs_at(atp, is_new_atp, { }); + break; } t.commit(); } diff --git a/tools/lavaODB/include/lava.hxx b/tools/lavaODB/include/lava.hxx index d4161e03..acd53dd8 100644 --- a/tools/lavaODB/include/lava.hxx +++ b/tools/lavaODB/include/lava.hxx @@ -310,6 +310,7 @@ struct AttackPoint { POINTER_WRITE, QUERY_POINT, PRINTF_LEAK, + MALLOC_OFF_BY_ONE, TYPE_END } type; @@ -333,6 +334,7 @@ struct AttackPoint { "ATP_POINTER_WRITE", "ATP_QUERY_POINT", "ATP_PRINTF_LEAK", + "ATP_MALLOC_OFF_BY_ONE" }; os << "ATP [" << m.loc.filename << " " << m.loc.begin << "] {"; os << names[m.type] << "}"; @@ -350,6 +352,7 @@ struct Bug { RET_BUFFER, REL_WRITE, PRINTF_LEAK, + MALLOC_OFF_BY_ONE, TYPE_END } type; @@ -357,6 +360,8 @@ struct Bug { [PTR_ADD] = 0, [RET_BUFFER] = 1, [REL_WRITE] = 2, + [PRINTF_LEAK] = 0, + [MALLOC_OFF_BY_ONE] = 0, }; #pragma db not_null diff --git a/tools/lavaTool/include/MallocOffByOneArgHandler.h b/tools/lavaTool/include/MallocOffByOneArgHandler.h new file mode 100644 index 00000000..d5c7e0c5 --- /dev/null +++ b/tools/lavaTool/include/MallocOffByOneArgHandler.h @@ -0,0 +1,52 @@ +#ifndef MALLOC_OFF_BY_ONE_H +#define MALLOC_OFF_BY_ONE_H + +using namespace clang; + +struct MallocOffByOneArgHandler : public LavaMatchHandler { + using LavaMatchHandler::LavaMatchHandler; + + virtual void handle(const MatchFinder::MatchResult &Result) { + const SourceManager &sm = *Result.SourceManager; + const CallExpr *callExpr = Result.Nodes.getNodeAs("call_expression"); + + if (ArgDataflow) { + auto fnname = get_containing_function_name(Result, *callExpr); + + // only instrument this printf with a read disclosure + // if it's in the body of a function that is on our whitelist + if (fninstr(fnname)) { + debug(INJECT) << "MallocOffByOneHandler: Containing function is in whitelist " << fnname.second << " : " << fnname.first << "\n"; + } + else { + debug(INJECT) << "MallocOffByOneHandler: Containing function is NOT in whitelist " << fnname.second << " : " << fnname.first << "\n"; + return; + } + + debug(INJECT) << "MallocOffByOneHandler handle: ok to instrument " << fnname.second << "\n"; + } + + LExpr addend = LDecimal(0); + const Expr *size_arg = callExpr->getArg(callExpr->getNumArgs() - 1); + if (size_arg) { + LavaASTLoc ast_loc = GetASTLoc(sm, size_arg); + Mod.Change(size_arg); + if (LavaAction == LavaQueries) { + addend = LavaAtpQuery(ast_loc, + AttackPoint::MALLOC_OFF_BY_ONE); + num_atp_queries++; + Mod.Add(addend, nullptr); + } else if (LavaAction == LavaInjectBugs) { + + const std::vector &injectable_bugs = + map_get_default(bugs_with_atp_at, + std::make_pair(ast_loc, AttackPoint::MALLOC_OFF_BY_ONE)); + for (const Bug *bug : injectable_bugs) { + Mod.Parenthesize().InsertBefore(Test(bug).render() + " ? (" + ExprStr(size_arg) + " - 1 ) : "); + } + } + } + } +}; + +#endif diff --git a/tools/lavaTool/include/MatchFinder.h b/tools/lavaTool/include/MatchFinder.h index a55fce0d..f111dff7 100644 --- a/tools/lavaTool/include/MatchFinder.h +++ b/tools/lavaTool/include/MatchFinder.h @@ -13,6 +13,7 @@ #include "FunctionPointerFieldHandler.h" #include "CallExprArgAdditionalHandler.h" #include "FunctionPointerTypedefHandler.h" +#include "MallocOffByOneArgHandler.h" // Must match value in scripts/fninstr.py //#define IGNORE_FN_PTRS @@ -151,6 +152,12 @@ class LavaMatchFinder : public MatchFinder, public SourceFileCallbacks { makeHandler() ); */ } + + addMatcher( + callExpr( + callee(functionDecl(hasName("malloc")))).bind("call_expression"), + makeHandler() + ); } virtual bool handleBeginSource(CompilerInstance &CI, StringRef Filename) override { Insert.clear();