Hi theraven,
This patch adds the -fsafe-stack command line argument for clang, which enables
the Safe Stack protection (see [[ http://reviews.llvm.org/D6094 |
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 the current SVN
HEAD of Clang (r221154). The patches make the following changes:
-- Add -fsafe-stack and -fno-safe-stack options to clang to control safe stack
usage (the safe stack is disabled by default).
-- Add __attribute__((no_safe_stack)) attribute to clang that can be used to
disable the safe stack for individual functions even when enabled globally.
http://reviews.llvm.org/D6095
Files:
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
include/clang/Basic/LangOptions.def
include/clang/Basic/LangOptions.h
include/clang/Driver/Options.td
lib/CodeGen/CodeGenModule.cpp
lib/Driver/ToolChains.cpp
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Frontend/InitPreprocessor.cpp
lib/Sema/SemaDeclAttr.cpp
runtime/compiler-rt/Makefile
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1317,6 +1317,13 @@
let Documentation = [Undocumented];
}
+// Attribute to disable SafeStack (or equivalent) instrumentation.
+def NoSafeStack : InheritableAttr {
+ let Spellings = [GCC<"no_safe_stack">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [NoSafeStackDocs];
+}
+
// Attribute to disable AddressSanitizer (or equivalent) checks.
def NoSanitizeAddress : InheritableAttr {
let Spellings = [GCC<"no_address_safety_analysis">,
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -860,6 +860,15 @@
}];
}
+def NoSafeStackDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Use ``__attribute__((no_safe_stack))`` on a function declaration to
+specify that the safe stack instrumentation should not be applied to
+that function.
+ }];
+}
+
def NoSanitizeAddressDocs : Documentation {
let Category = DocCatFunction;
// This function has multiple distinct spellings, and so it requires a custom
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -192,7 +192,7 @@
"value symbol visibility")
ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility,
"type symbol visibility")
-ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff,
+ENUM_LANGOPT(StackProtector, StackProtectorMode, 3, SSPOff,
"stack protector mode")
ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined,
"signed integer overflow handling")
Index: include/clang/Basic/LangOptions.h
===================================================================
--- include/clang/Basic/LangOptions.h
+++ include/clang/Basic/LangOptions.h
@@ -66,7 +66,7 @@
typedef clang::Visibility Visibility;
enum GCMode { NonGC, GCOnly, HybridGC };
- enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq };
+ enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq, SSPSafeStack };
enum SignedOverflowBehaviorTy {
SOB_Undefined, // Default C standard behavior.
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -864,6 +864,10 @@
HelpText<"Use a strong heuristic to apply stack protectors to functions">;
def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>,
HelpText<"Enable stack protectors for functions potentially vulnerable to stack smashing">;
+def fsafe_stack : Flag<["-"], "fsafe-stack">, Group<f_Group>,
+ HelpText<"Enable safe stack protection against stack-based memory corruption errors">;
+def fno_safe_stack : Flag<["-"], "fno-safe-stack">, Group<f_Group>,
+ HelpText<"Disable safe stack protection against stack-based memory corruption errors">;
def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Emit full debug info for all types used by the program">;
def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group<f_Group>, Flags<[CC1Option]>,
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -738,6 +738,9 @@
B.addAttribute(llvm::Attribute::StackProtectStrong);
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
B.addAttribute(llvm::Attribute::StackProtectReq);
+ else if (LangOpts.getStackProtector() == LangOptions::SSPSafeStack)
+ if (!D->hasAttr<NoSafeStackAttr>())
+ B.addAttribute(llvm::Attribute::SafeStack);
// Add sanitizer attributes if function is not blacklisted.
if (!isInSanitizerBlacklist(F, D->getLocation())) {
Index: lib/Driver/ToolChains.cpp
===================================================================
--- lib/Driver/ToolChains.cpp
+++ lib/Driver/ToolChains.cpp
@@ -10,6 +10,7 @@
#include "ToolChains.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -2172,6 +2172,29 @@
CmdArgs.push_back(Args.MakeArgString(LibProfile));
}
+static void addSafeStackRT(
+ const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) {
+ if (!Args.hasFlag(options::OPT_fsafe_stack,
+ options::OPT_fno_safe_stack, false))
+ return;
+
+ const char *LibBaseName = "libclang_rt.safestack-";
+ SmallString<128> LibName = getCompilerRTLibDir(TC);
+ llvm::sys::path::append(LibName,
+ Twine(LibBaseName) + getArchNameForCompilerRTLib(TC) + ".a");
+
+ CmdArgs.push_back(Args.MakeArgString(LibName));
+
+ // On gnu platforms, safestack runtime requires dl
+ CmdArgs.push_back("-ldl");
+
+ // We need to ensure that the safe stack init function from the safestack
+ // runtime library is linked in, even though it might not be referenced by
+ // any code in the module before LTO optimizations are applied.
+ CmdArgs.push_back("-u");
+ CmdArgs.push_back("__llvm__safestack_init");
+}
+
static SmallString<128> getSanitizerRTLibName(const ToolChain &TC,
StringRef Sanitizer,
bool Shared) {
@@ -3675,7 +3698,14 @@
// -stack-protector=0 is default.
unsigned StackProtectorLevel = 0;
- if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector,
+ if (Args.hasFlag(options::OPT_fsafe_stack,
+ options::OPT_fno_safe_stack, false)) {
+ StackProtectorLevel = LangOptions::SSPSafeStack;
+ 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)) {
@@ -5843,6 +5873,21 @@
!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
+ // __llvm__safestack_init constructor executes before everything else
+ if (Args.hasFlag(options::OPT_fsafe_stack,
+ options::OPT_fno_safe_stack, false)) {
+ getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs,
+ "libclang_rt.safestack_osx.a");
+
+ // We need to ensure that the safe stack init function from the safestack
+ // runtime library is linked in, even though it might not be referenced by
+ // any code in the module before LTO optimizations are applied.
+ CmdArgs.push_back("-u");
+ CmdArgs.push_back("___llvm__safestack_init");
+ }
+
Args.AddAllArgs(CmdArgs, options::OPT_L);
LibOpenMP UsedOpenMPLib = LibUnknown;
@@ -6092,6 +6137,8 @@
CmdArgs.push_back(Args.MakeArgString("-L" + GCCLibPath));
+ addSafeStackRT(getToolChain(), Args, CmdArgs);
+
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
@@ -6638,6 +6685,8 @@
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
}
+ addSafeStackRT(getToolChain(), Args, CmdArgs);
+
Args.AddAllArgs(CmdArgs, options::OPT_L);
const ToolChain::path_list &Paths = ToolChain.getFilePaths();
for (const auto &Path : Paths)
@@ -6932,6 +6981,8 @@
}
}
+ addSafeStackRT(getToolChain(), Args, CmdArgs);
+
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
@@ -7471,6 +7522,8 @@
ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
}
+ addSafeStackRT(getToolChain(), Args, CmdArgs);
+
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_u);
@@ -7613,6 +7666,8 @@
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
}
+ addSafeStackRT(getToolChain(), Args, CmdArgs);
+
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
@@ -7738,6 +7793,8 @@
getToolChain().GetFilePath("crtbegin.o")));
}
+ addSafeStackRT(getToolChain(), Args, CmdArgs);
+
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1606,6 +1606,7 @@
case 1: Opts.setStackProtector(LangOptions::SSPOn); break;
case 2: Opts.setStackProtector(LangOptions::SSPStrong); break;
case 3: Opts.setStackProtector(LangOptions::SSPReq); break;
+ case 4: Opts.setStackProtector(LangOptions::SSPSafeStack); break;
}
// Parse -fsanitize= arguments.
Index: lib/Frontend/InitPreprocessor.cpp
===================================================================
--- lib/Frontend/InitPreprocessor.cpp
+++ lib/Frontend/InitPreprocessor.cpp
@@ -826,6 +826,8 @@
Builder.defineMacro("__SSP_STRONG__", "2");
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
Builder.defineMacro("__SSP_ALL__", "3");
+ else if (LangOpts.getStackProtector() == LangOptions::SSPSafeStack)
+ Builder.defineMacro("__SAFESTACK__", "4");
if (FEOpts.ProgramAction == frontend::RewriteObjC)
Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -4593,6 +4593,9 @@
case AttributeList::AT_ScopedLockable:
handleSimpleAttribute<ScopedLockableAttr>(S, D, Attr);
break;
+ case AttributeList::AT_NoSafeStack:
+ handleSimpleAttribute<NoSafeStackAttr>(S, D, Attr);
+ break;
case AttributeList::AT_NoSanitizeAddress:
handleSimpleAttribute<NoSanitizeAddressAttr>(S, D, Attr);
break;
Index: runtime/compiler-rt/Makefile
===================================================================
--- runtime/compiler-rt/Makefile
+++ runtime/compiler-rt/Makefile
@@ -83,7 +83,7 @@
eprintf.a 10.4.a osx.a ios.a cc_kext.a cc_kext_ios5.a \
asan_osx_dynamic.dylib \
profile_osx.a profile_ios.a \
- ubsan_osx.a
+ ubsan_osx.a safestack_osx.a
RuntimeLibrary.macho_embedded.Configs := \
hard_static.a hard_pic.a
@@ -127,7 +127,7 @@
# We try to build 32-bit runtimes both on 32-bit hosts and 64-bit hosts.
Runtime32BitConfigs = \
builtins-i386.a profile-i386.a san-i386.a asan-i386.a asan_cxx-i386.a \
- ubsan-i386.a ubsan_cxx-i386.a
+ ubsan-i386.a ubsan_cxx-i386.a safestack-i386.a
# We currently only try to generate runtime libraries on x86.
ifeq ($(ARCH),x86)
@@ -138,7 +138,7 @@
RuntimeLibrary.linux.Configs += \
builtins-x86_64.a profile-x86_64.a san-x86_64.a asan-x86_64.a \
asan_cxx-x86_64.a tsan-x86_64.a msan-x86_64.a ubsan-x86_64.a \
- ubsan_cxx-x86_64.a dfsan-x86_64.a lsan-x86_64.a
+ ubsan_cxx-x86_64.a dfsan-x86_64.a lsan-x86_64.a safestack-x86_64.a
# We need to build 32-bit ASan/UBsan libraries on 64-bit platform, and add them
# to the list of runtime libraries to make
# "clang -fsanitize=(address|undefined) -m32" work.
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits