Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/llvm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: CI

on: [push]

jobs:
build_llvm:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
- macOS-latest
cmake_args:
- ""
steps:
- name: Setup Windows
if: startsWith(matrix.os, 'windows')
uses: tstellar/actions/setup-windows@master
with:
arch: amd64
- uses: actions/checkout@v1
with:
fetch-depth: 1
- name: Install Ninja
uses: tstellar/actions/install-ninja@master
with:
os: ${{ runner.os }}
- name: Test LLVM
uses: tstellar/actions/build-test-llvm-project@master
with:
cmake_args: -G Ninja -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
os: ${{ runner.os }}
4 changes: 4 additions & 0 deletions clang/docs/ClangCommandLineReference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1917,6 +1917,10 @@ Use a strong heuristic to apply stack protectors to functions

Emit section containing metadata on function stack sizes

.. option:: -fstack-clash-protection, -fno-stack-clash-protection

Instrument stack allocation to prevent stack clash attacks (x86, non-Windows only).

.. option:: -fstandalone-debug, -fno-limit-debug-info, -fno-standalone-debug

Emit full debug info for all types used by the program
Expand Down
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ New Compiler Flags
------------------


- -fstack-clash-protection will provide a protection against the stack clash
attack for x86 architecture through automatic probing of each page of
allocated stack.

Deprecated Compiler Flags
-------------------------

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ CODEGENOPT(NoWarn , 1, 0) ///< Set when -Wa,--no-warn is enabled.
CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled.
CODEGENOPT(NoInlineLineTables, 1, 0) ///< Whether debug info should contain
///< inline line tables.
CODEGENOPT(StackClashProtector, 1, 0) ///< Set when -fstack-clash-protection is enabled.
CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled.
CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf.
CODEGENOPT(NoSignedZeros , 1, 0) ///< Allow ignoring the signedness of FP zero
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ def note_invalid_subexpr_in_const_expr : Note<
let CategoryName = "Inline Assembly Issue" in {
def err_asm_invalid_type_in_input : Error<
"invalid type %0 in asm input for constraint '%1'">;

def warn_stack_clash_protection_inline_asm : Warning<
"Unable to protect inline asm that clobbers stack pointer against stack clash">,
InGroup<DiagGroup<"stack-protector">>;
}

// Sema && Serialization
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,8 @@ class TargetInfo : public virtual TransferrableTargetInfo,
StringRef getNormalizedGCCRegisterName(StringRef Name,
bool ReturnCanonical = false) const;

virtual bool isSPRegName(StringRef) const { return false; }

/// Extracts a register from the passed constraint (if it is a
/// single-register constraint) and the asm label expression related to a
/// variable in the input or output list of an inline asm statement.
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Driver/CC1Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,8 @@ def stack_protector : Separate<["-"], "stack-protector">,
HelpText<"Enable stack protectors">;
def stack_protector_buffer_size : Separate<["-"], "stack-protector-buffer-size">,
HelpText<"Lower bound for a buffer to be considered for stack protection">;
def stack_clash_protection : Separate<["-"], "stack-clash-protection">,
HelpText<"Enable stack clash protection">;
def fvisibility : Separate<["-"], "fvisibility">,
HelpText<"Default type and symbol visibility">;
def ftype_visibility : Separate<["-"], "ftype-visibility">,
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1773,6 +1773,10 @@ def fno_signed_char : Flag<["-"], "fno-signed-char">, Group<f_Group>,
def fsplit_stack : Flag<["-"], "fsplit-stack">, Group<f_Group>;
def fstack_protector_all : Flag<["-"], "fstack-protector-all">, Group<f_Group>,
HelpText<"Enable stack protectors for all functions">;
def fstack_clash_protection : Flag<["-"], "fstack-clash-protection">, Group<f_Group>,
HelpText<"Enable stack clash protection">;
def fnostack_clash_protection : Flag<["-"], "fnostack-clash-protection">, Group<f_Group>,
HelpText<"Disable stack clash protection">;
def fstack_protector_strong : Flag<["-"], "fstack-protector-strong">, Group<f_Group>,
HelpText<"Enable stack protectors for some functions vulnerable to stack smashing. "
"Compared to -fstack-protector, this uses a stronger heuristic "
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {

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

bool isSPRegName(StringRef RegName) const override {
return RegName.equals("esp") || RegName.equals("rsp");
}

bool validateCpuSupports(StringRef Name) const override;

bool validateCpuIs(StringRef Name) const override;
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/CodeGen/CGStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2247,8 +2247,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {

if (Clobber == "memory")
ReadOnly = ReadNone = false;
else if (Clobber != "cc")
else if (Clobber != "cc") {
Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
if (CGM.getCodeGenOpts().StackClashProtector &&
getTarget().isSPRegName(Clobber)) {
CGM.getDiags().Report(S.getAsmLoc(),
diag::warn_stack_clash_protection_inline_asm);
}
}

if (!Constraints.empty())
Constraints += ',';
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1514,6 +1514,9 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (CodeGenOpts.UnwindTables)
B.addAttribute(llvm::Attribute::UWTable);

if (CodeGenOpts.StackClashProtector)
B.addAttribute("probe-stack", "inline-asm");

if (!hasUnwindExceptions(LangOpts))
B.addAttribute(llvm::Attribute::NoUnwind);

Expand Down
16 changes: 16 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3003,6 +3003,21 @@ static void RenderSSPOptions(const ToolChain &TC, const ArgList &Args,
}
}

static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple();

if (!EffectiveTriple.isOSLinux())
return;

if (!EffectiveTriple.isX86())
return;

if (Args.hasFlag(options::OPT_fstack_clash_protection,
options::OPT_fnostack_clash_protection, false))
CmdArgs.push_back("-stack-clash-protection");
}

static void RenderTrivialAutoVarInitOptions(const Driver &D,
const ToolChain &TC,
const ArgList &Args,
Expand Down Expand Up @@ -5244,6 +5259,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening"));

RenderSSPOptions(TC, Args, CmdArgs, KernelOrKext);
RenderSCPOptions(TC, Args, CmdArgs);
RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs);

// Translate -mstackrealign
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,

Opts.NoStackArgProbe = Args.hasArg(OPT_mno_stack_arg_probe);

Opts.StackClashProtector = Args.hasArg(OPT_stack_clash_protection);

if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
StringRef Name = A->getValue();
unsigned Method = llvm::StringSwitch<unsigned>(Name)
Expand Down
31 changes: 31 additions & 0 deletions clang/test/CodeGen/stack-clash-protection.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// check interaction between -fstack-clash-protection and dynamic allocation schemes
// RUN: %clang -target x86_64 -O0 -o %t.out %s -fstack-clash-protection && %t.out

int large_stack() __attribute__((noinline));

int large_stack() {
int stack[20000], i;
for (i = 0; i < sizeof(stack) / sizeof(int); ++i)
stack[i] = i;
return stack[1];
}

int main(int argc, char **argv) {
int volatile static_mem[8000];
for (unsigned i = 0; i < argc * sizeof(static_mem) / sizeof(static_mem[0]); ++i)
static_mem[i] = argc * i;

int vla[argc];
__builtin_memset(&vla[0], 0, argc);

int index = large_stack();

// also check allocation of 0 size
volatile void *mem = __builtin_alloca(argc - 1);

int volatile *dyn_mem = __builtin_alloca(sizeof(static_mem) * argc);
for (unsigned i = 0; i < argc * sizeof(static_mem) / sizeof(static_mem[0]); ++i)
dyn_mem[i] = argc * i;

return static_mem[(7999 * argc) / 2] - dyn_mem[(7999 * argc) / 2] + vla[argc - index];
}
33 changes: 33 additions & 0 deletions clang/test/Driver/stack-clash-protection.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: %clang -target i386-unknown-linux -fstack-clash-protection -### %s 2>&1 | FileCheck %s -check-prefix=SCP-i386
// RUN: %clang -target i386-unknown-linux -fnostack-clash-protection -fstack-clash-protection -### %s 2>&1 | FileCheck %s -check-prefix=SCP-i386
// RUN: %clang -target i386-unknown-linux -fstack-clash-protection -fnostack-clash-protection -### %s 2>&1 | FileCheck %s -check-prefix=SCP-i386-NO
// SCP-i386: "-stack-clash-protection"
// SCP-i386-NO-NOT: "-stack-clash-protection"

// RUN: %clang -target x86_64-scei-linux -fstack-clash-protection -### %s 2>&1 | FileCheck %s -check-prefix=SCP-x86
// SCP-x86: "-stack-clash-protection"

// RUN: %clang -target armv7k-apple-linux -fstack-clash-protection -### %s 2>&1 | FileCheck %s -check-prefix=SCP-armv7
// SCP-armv7-NOT: "-stack-clash-protection"
// SCP-armv7: argument unused during compilation: '-fstack-clash-protection'

// RUN: %clang -target x86_64-unknown-linux -fstack-clash-protection -c %s 2>&1 | FileCheck %s -check-prefix=SCP-warn
// SCP-warn: warning: Unable to protect inline asm that clobbers stack pointer against stack clash

// RUN: %clang -target x86_64-pc-unknown-linux -fstack-clash-protection -S -emit-llvm -o- %s | FileCheck %s -check-prefix=SCP-ll-linux64
// SCP-ll-linux64: attributes {{.*}} "probe-stack"="inline-asm"

// RUN: %clang -target x86_64-pc-windows-msvc -fstack-clash-protection -S -emit-llvm -o- %s 2>&1 | FileCheck %s -check-prefix=SCP-ll-win64
// SCP-ll-win64-NOT: attributes {{.*}} "probe-stack"="inline-asm"
// SCP-ll-win64: argument unused during compilation: '-fstack-clash-protection'

int foo(int c) {
int r;
__asm__("sub %0, %%rsp"
:
: "rm"(c)
: "rsp");
__asm__("mov %%rsp, %0"
: "=rm"(r)::);
return r;
}
4 changes: 4 additions & 0 deletions llvm/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ Changes to the X86 Target
During this release ...


* Functions with the probe-stack attribute set to "inline-asm" are now protected
against stack clash without the need of a third-party probing function and
with limited impact on performance.

Changes to the AMDGPU Target
-----------------------------

Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/TargetLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -1707,6 +1707,10 @@ class TargetLoweringBase {

/// Returns the name of the symbol used to emit stack probes or the empty
/// string if not applicable.
virtual bool hasStackProbeSymbol(MachineFunction &MF) const { return false; }

virtual bool hasInlineStackProbe(MachineFunction &MF) const { return false; }

virtual StringRef getStackProbeSymbolName(MachineFunction &MF) const {
return "";
}
Expand Down
5 changes: 2 additions & 3 deletions llvm/lib/Target/X86/X86CallFrameOptimization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,13 @@ bool X86CallFrameOptimization::isLegal(MachineFunction &MF) {
// memory for arguments.
unsigned FrameSetupOpcode = TII->getCallFrameSetupOpcode();
unsigned FrameDestroyOpcode = TII->getCallFrameDestroyOpcode();
bool UseStackProbe =
!STI->getTargetLowering()->getStackProbeSymbolName(MF).empty();
bool EmitStackProbeCall = STI->getTargetLowering()->hasStackProbeSymbol(MF);
unsigned StackProbeSize = STI->getTargetLowering()->getStackProbeSize(MF);
for (MachineBasicBlock &BB : MF) {
bool InsideFrameSequence = false;
for (MachineInstr &MI : BB) {
if (MI.getOpcode() == FrameSetupOpcode) {
if (TII->getFrameSize(MI) >= StackProbeSize && UseStackProbe)
if (TII->getFrameSize(MI) >= StackProbeSize && EmitStackProbeCall)
return false;
if (InsideFrameSequence)
return false;
Expand Down
Loading