Skip to content

Commit b914254

Browse files
author
serge_sans_paille
committed
Support -fstack-clash-protection for x86
Implement protection against the stack clash attack [0] through inline stack probing. Probe stack allocation every PAGE_SIZE during frame lowering or dynamic allocation to make sure the page guard, if any, is touched when touching the stack, in a similar manner to GCC[1]. This extends the existing `probe-stack' mechanism with a special value `inline-asm'. Technically the former uses function call before stack allocation while this patch provides inlined stack probes and chunk allocation. Only implemented for x86. [0] https://www.qualys.com/2017/06/19/stack-clash/stack-clash.txt [1] https://gcc.gnu.org/ml/gcc-patches/2017-07/msg00556.html Differential Revision: https://reviews.llvm.org/D68720
1 parent 8905b6e commit b914254

31 files changed

+778
-22
lines changed

clang/docs/ClangCommandLineReference.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,6 +1917,10 @@ Use a strong heuristic to apply stack protectors to functions
19171917

19181918
Emit section containing metadata on function stack sizes
19191919

1920+
.. option:: -fstack-clash-protection, -fno-stack-clash-protection
1921+
1922+
Instrument stack allocation to prevent stack clash attacks (x86, non-Windows only).
1923+
19201924
.. option:: -fstandalone-debug, -fno-limit-debug-info, -fno-standalone-debug
19211925

19221926
Emit full debug info for all types used by the program

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ New Compiler Flags
6161
------------------
6262

6363

64+
- -fstack-clash-protection will provide a protection against the stack clash
65+
attack for x86 architecture through automatic probing of each page of
66+
allocated stack.
67+
6468
Deprecated Compiler Flags
6569
-------------------------
6670

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ CODEGENOPT(NoWarn , 1, 0) ///< Set when -Wa,--no-warn is enabled.
150150
CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled.
151151
CODEGENOPT(NoInlineLineTables, 1, 0) ///< Whether debug info should contain
152152
///< inline line tables.
153+
CODEGENOPT(StackClashProtector, 1, 0) ///< Set when -fstack-clash-protection is enabled.
153154
CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled.
154155
CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf.
155156
CODEGENOPT(NoSignedZeros , 1, 0) ///< Allow ignoring the signedness of FP zero

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ def note_invalid_subexpr_in_const_expr : Note<
239239
let CategoryName = "Inline Assembly Issue" in {
240240
def err_asm_invalid_type_in_input : Error<
241241
"invalid type %0 in asm input for constraint '%1'">;
242+
243+
def warn_stack_clash_protection_inline_asm : Warning<
244+
"Unable to protect inline asm that clobbers stack pointer against stack clash">,
245+
InGroup<DiagGroup<"stack-protector">>;
242246
}
243247

244248
// Sema && Serialization

clang/include/clang/Basic/TargetInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,8 @@ class TargetInfo : public virtual TransferrableTargetInfo,
816816
StringRef getNormalizedGCCRegisterName(StringRef Name,
817817
bool ReturnCanonical = false) const;
818818

819+
virtual bool isSPRegName(StringRef) const { return false; }
820+
819821
/// Extracts a register from the passed constraint (if it is a
820822
/// single-register constraint) and the asm label expression related to a
821823
/// variable in the input or output list of an inline asm statement.

clang/include/clang/Driver/CC1Options.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,8 @@ def stack_protector : Separate<["-"], "stack-protector">,
751751
HelpText<"Enable stack protectors">;
752752
def stack_protector_buffer_size : Separate<["-"], "stack-protector-buffer-size">,
753753
HelpText<"Lower bound for a buffer to be considered for stack protection">;
754+
def stack_clash_protection : Separate<["-"], "stack-clash-protection">,
755+
HelpText<"Enable stack clash protection">;
754756
def fvisibility : Separate<["-"], "fvisibility">,
755757
HelpText<"Default type and symbol visibility">;
756758
def ftype_visibility : Separate<["-"], "ftype-visibility">,

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,6 +1773,10 @@ def fno_signed_char : Flag<["-"], "fno-signed-char">, Group<f_Group>,
17731773
def fsplit_stack : Flag<["-"], "fsplit-stack">, Group<f_Group>;
17741774
def fstack_protector_all : Flag<["-"], "fstack-protector-all">, Group<f_Group>,
17751775
HelpText<"Enable stack protectors for all functions">;
1776+
def fstack_clash_protection : Flag<["-"], "fstack-clash-protection">, Group<f_Group>,
1777+
HelpText<"Enable stack clash protection">;
1778+
def fnostack_clash_protection : Flag<["-"], "fnostack-clash-protection">, Group<f_Group>,
1779+
HelpText<"Disable stack clash protection">;
17761780
def fstack_protector_strong : Flag<["-"], "fstack-protector-strong">, Group<f_Group>,
17771781
HelpText<"Enable stack protectors for some functions vulnerable to stack smashing. "
17781782
"Compared to -fstack-protector, this uses a stronger heuristic "

clang/lib/Basic/Targets/X86.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
166166

167167
ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override;
168168

169+
bool isSPRegName(StringRef RegName) const override {
170+
return RegName.equals("esp") || RegName.equals("rsp");
171+
}
172+
169173
bool validateCpuSupports(StringRef Name) const override;
170174

171175
bool validateCpuIs(StringRef Name) const override;

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2247,8 +2247,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
22472247

22482248
if (Clobber == "memory")
22492249
ReadOnly = ReadNone = false;
2250-
else if (Clobber != "cc")
2250+
else if (Clobber != "cc") {
22512251
Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
2252+
if (CGM.getCodeGenOpts().StackClashProtector &&
2253+
getTarget().isSPRegName(Clobber)) {
2254+
CGM.getDiags().Report(S.getAsmLoc(),
2255+
diag::warn_stack_clash_protection_inline_asm);
2256+
}
2257+
}
22522258

22532259
if (!Constraints.empty())
22542260
Constraints += ',';

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,9 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
15141514
if (CodeGenOpts.UnwindTables)
15151515
B.addAttribute(llvm::Attribute::UWTable);
15161516

1517+
if (CodeGenOpts.StackClashProtector)
1518+
B.addAttribute("probe-stack", "inline-asm");
1519+
15171520
if (!hasUnwindExceptions(LangOpts))
15181521
B.addAttribute(llvm::Attribute::NoUnwind);
15191522

0 commit comments

Comments
 (0)