From c4122c17b473a6f9f2a5940a98939209aaaa3dfc Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Mon, 15 Jun 2015 21:08:13 +0000 Subject: Protection against stack-based memory corruption errors using SafeStack: Clang command line option and function attribute This patch adds the -fsanitize=safe-stack command line argument for clang, which enables the Safe Stack protection (see http://reviews.llvm.org/D6094 for the detailed description of the Safe Stack). This patch is our implementation of the safe stack on top of Clang. The patches make the following changes: - Add -fsanitize=safe-stack and -fno-sanitize=safe-stack options to clang to control safe stack usage (the safe stack is disabled by default). - Add __attribute__((no_sanitize("safe-stack"))) attribute to clang that can be used to disable the safe stack for individual functions even when enabled globally. Original patch by Volodymyr Kuznetsov and others at the Dependable Systems Lab at EPFL; updates and upstreaming by myself. Differential Revision: http://reviews.llvm.org/D6095 llvm-svn: 239762 --- clang/lib/CodeGen/CGDeclCXX.cpp | 2 ++ clang/lib/CodeGen/CodeGenFunction.cpp | 2 ++ clang/lib/Driver/Tools.cpp | 18 +++++++++++++++++- clang/lib/Lex/PPMacroExpansion.cpp | 1 + 4 files changed, 22 insertions(+), 1 deletion(-) (limited to 'clang/lib') diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 06d157bd82e..50a499607f8 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -273,6 +273,8 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction( Fn->addFnAttr(llvm::Attribute::SanitizeThread); if (getLangOpts().Sanitize.has(SanitizerKind::Memory)) Fn->addFnAttr(llvm::Attribute::SanitizeMemory); + if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack)) + Fn->addFnAttr(llvm::Attribute::SafeStack); } return Fn; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 01da7500561..f370ac27676 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -621,6 +621,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, Fn->addFnAttr(llvm::Attribute::SanitizeThread); if (SanOpts.has(SanitizerKind::Memory)) Fn->addFnAttr(llvm::Attribute::SanitizeMemory); + if (SanOpts.has(SanitizerKind::SafeStack)) + Fn->addFnAttr(llvm::Attribute::SafeStack); // Pass inline keyword to optimizer if it appears explicitly on any // declaration. Also, in the case of -fno-inline attach NoInline diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index ed9df1207df..800053cc931 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -2433,6 +2433,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("ubsan_standalone_cxx"); } + if (SanArgs.needsSafeStackRt()) + StaticRuntimes.push_back("safestack"); } // Should be called before we add system libraries (C++ ABI, libstdc++/libc++, @@ -4001,7 +4003,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -stack-protector=0 is default. unsigned StackProtectorLevel = 0; - if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, + if (getToolChain().getSanitizerArgs().needsSafeStackRt()) { + Args.ClaimAllArgs(options::OPT_fno_stack_protector); + Args.ClaimAllArgs(options::OPT_fstack_protector_all); + Args.ClaimAllArgs(options::OPT_fstack_protector_strong); + Args.ClaimAllArgs(options::OPT_fstack_protector); + } else if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, options::OPT_fstack_protector_all, options::OPT_fstack_protector_strong, options::OPT_fstack_protector)) { @@ -6364,6 +6371,15 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_nostartfiles)) getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs); + // SafeStack requires its own runtime libraries + // These libraries should be linked first, to make sure the + // __safestack_init constructor executes before everything else + if (getToolChain().getSanitizerArgs().needsSafeStackRt()) { + getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs, + "libclang_rt.safestack_osx.a", + /*AlwaysLink=*/true); + } + Args.AddAllArgs(CmdArgs, options::OPT_L); if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 03784e20450..0aaf3dd23c4 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1190,6 +1190,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("is_trivially_copyable", LangOpts.CPlusPlus) .Case("is_union", LangOpts.CPlusPlus) .Case("modules", LangOpts.Modules) + .Case("safe_stack", LangOpts.Sanitize.has(SanitizerKind::SafeStack)) .Case("tls", PP.getTargetInfo().isTLSSupported()) .Case("underlying_type", LangOpts.CPlusPlus) .Default(false); -- cgit v1.2.3