Disable redzone. Our LVI mitigations clobber it. (#20)

* Disable redzone. Our LVI mitigations clobber it.

This disables the redzone in the gcc compiled SDK, the
cargo compiled enclave, the cargo dependencies, and so forth.

BOLT is modified to fail if any function that gets a
memory indirect jmp mitigation uses the redzone.

The checker is also modified to check and fail the build if
any functions use the redzone that had a memory indirect jmp
mitigation applied.

* Disable redzone. Our LVI mitigations clobber it.

This disables the redzone in the gcc compiled SDK, the
cargo compiled enclave, the cargo dependencies, and so forth.

BOLT is modified to fail if any function that gets a
memory indirect jmp mitigation uses the redzone.

The checker is also modified to check and fail the build if
any functions use the redzone that had a memory indirect jmp
mitigation applied.

Co-authored-by: Nolan Leake <nolan@sigbus.net>
This commit is contained in:
nolanl 2020-07-10 10:09:47 -07:00 committed by GitHub
parent d85edb9222
commit 28ac367b86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 55 additions and 10 deletions

View File

@ -36,7 +36,7 @@ CFLAGS = \
LDFLAGS =
ENCLAVE_RUSTFLAGS = -C opt-level=2 -C debuginfo=1 -C codegen-units=1 -C panic=abort -C llvm-args=-max-jump-table-size=1 -C llvm-args=-disable-tail-duplicate
ENCLAVE_RUSTFLAGS = -C opt-level=2 -C debuginfo=1 -C codegen-units=1 -C panic=abort -C llvm-args=-max-jump-table-size=1 -C llvm-args=-disable-tail-duplicate -C no-redzone
BINDGENFLAGS =
CARGOBUILDFLAGS =
@ -238,7 +238,7 @@ FORCE:
$(targetdir)/debug/prostc: FORCE $(RUST_DEPS_DIRS)
env -u CFLAGS $(CARGO) build --manifest-path=prostc/Cargo.toml --bin=prostc
$(targetdir)/release/lib%.a: FORCE $(RUST_DEPS_DIRS)
env CFLAGS="" RUSTFLAGS="$(ENCLAVE_RUSTFLAGS)" \
env CFLAGS="-mno-red-zone" RUSTFLAGS="$(ENCLAVE_RUSTFLAGS)" \
$(CARGO) build -vv --release --manifest-path=$*/Cargo.toml --lib $(if $(FEATURES),--features $(FEATURES))
$(RUST_DEPS_DIR)/prost-$(PROST_GIT_REV):

View File

@ -0,0 +1,12 @@
#!/usr/bin/gawk -f
match($2, /<(.+)>:/, m) {
fn = m[1];
}
/jmpq.+[(]/ {
if (fn) {
print fn;
}
fn = "";
}

View File

@ -9,13 +9,16 @@
import sys, re, binascii
import pyxed
#XXX Add command line option to report on lfences that are not needed.
#XXX Now that we have pyxed, we should use that everywhere instead of parsing "objdump -d".
#XXX Add command line option to report on lfences that are not needed?
WINDOW_SIZE=3
start_func = re.compile(r'^([0-9a-f]+) <(.+)>:$')
hexbyte = re.compile(r'^[0-9a-f][0-9a-f]$')
conditional_jmp = re.compile(r'j[^m][a-z]*')
redzone_arg = re.compile(r'[-]0x[0-9a-f]+[(]%rsp')
redundant_rex = re.compile(r'rex[.][A-Z]+$')
retcode = 0
func = None
@ -43,13 +46,19 @@ def match_previous_inst(inst, args, ago):
def is_load(inst, inst_hex):
if inst.startswith('ret'):
return False #We handle ret's load with a different mitigation.
if redundant_rex.match(inst):
return False #Spurious REX prefixes freak Xed out.
xed = pyxed.Decoder()
xed.set_mode(pyxed.XED_MACHINE_MODE_LONG_64, pyxed.XED_ADDRESS_WIDTH_64b)
xed.itext = binascii.unhexlify(inst_hex)
xed.runtime_address = 0x10001000 #Doesn't matter for our purposes.
xedinst = xed.decode()
try:
xedinst = xed.decode()
except pyxed.InvalidInstructionError:
print('Invalid instruction in', func, inst)
raise
assert(xedinst is not None)
for i in range(xedinst.get_number_of_memory_operands()):
if xedinst.is_mem_read(i):
@ -57,6 +66,11 @@ def is_load(inst, inst_hex):
return False
funcs_with_memindjmp = []
if len(sys.argv) > 1:
with open(sys.argv[1], 'r') as f:
funcs_with_memindjmp = f.readlines()
for line in sys.stdin:
#Track function boundaries
if func and (line == '' or line.isspace()):
@ -147,6 +161,22 @@ for line in sys.stdin:
print('rep cmps or rep scas in', func, ':', line)
retcode = 1
#Check that there is no use of the redzone. Our memory-indirect jmp mitigation
#clobbers the redzone, so we need to make sure it is fully disabled.
#
#Note that this has false positives like:
# mov %ax,-0x1(%rsp,%r11,1)
#if the compiler can prove r11 is always greated than 1, it doesn't actually
#touch the redzone. We workaround this by passing in a file with a list of
#functions that use memory indirect jmps, which are the only mitigation
#that clobber the redzone, and only reporting on redzone accesses (real for
#false) inthem.
if not inst.startswith('lea'):
for arg in args:
if redzone_arg.match(arg) and func in funcs_with_memindjmp:
print('Use of redzone in', func, ':', line)
retcode = 1
#Update instruction window
if len(window) > WINDOW_SIZE:
del(window[WINDOW_SIZE-1])
@ -155,6 +185,6 @@ for line in sys.stdin:
print("Mitigated conditional jmps:", cond_jmps)
print("Mitigated memory loads:", loads)
print("Mitigated rets:", rets)
print("Instructions:", insts, "Lfences:", lfences, "-", "%.3s%%" % (lfences/insts*100))
print("Instructions:", insts, "Lfences:", lfences, "-", "%.3f%%" % (lfences/insts*100))
sys.exit(retcode)

View File

@ -5,7 +5,7 @@ COPY apt.conf sources.list /etc/apt/
RUN apt-get update \
&& apt-get install -V -y --no-install-recommends --allow-downgrades \
build-essential ca-certificates curl git cmake ninja-build \
devscripts debhelper fakeroot libwww-perl gnupg \
devscripts debhelper fakeroot libwww-perl gawk gnupg \
ocaml-native-compilers ocamlbuild automake autoconf libtool wget python pkg-config \
libssl-dev libcurl4-openssl-dev protobuf-compiler libprotobuf-dev \
llvm-dev libclang-dev clang python3-distutils python3-dev \

View File

@ -25,7 +25,7 @@ SGX_LIBDIR ?= $(SGX_SDK_SOURCE_LIBDIR)
export SGX_LIBDIR
SGX_SIGN ?= $(SGX_SDK_SOURCE_LIBDIR)/sgx_sign
SGX_EDGER8R ?= $(SGX_SDK_SOURCE_LIBDIR)/sgx_edger8r
SGX_SDK_MAKE = env -u LDFLAGS -u CPPFLAGS CFLAGS="-D_TLIBC_USE_REP_STRING_ -fno-jump-tables -Wno-error=implicit-fallthrough" $(MAKE)
SGX_SDK_MAKE = env -u LDFLAGS -u CPPFLAGS CFLAGS="-D_TLIBC_USE_REP_STRING_ -fno-jump-tables -mno-red-zone -mindirect-branch-register -Wno-error=implicit-fallthrough" $(MAKE)
$(SGX_SDK_SOURCE_INCLUDEDIR): | $(SGX_SDK_SOURCE_DIR)
@ -90,7 +90,7 @@ $(builddir)/linux-sgx/linux-sgx-$(SGX_SDK_SOURCE_GIT_REV):
LLVM_BOLT ?= $(builddir)/bin/llvm-bolt
BOLT_DIR = $(builddir)/bolt
BOLT_GIT_REV = faef3fcd5b5cb9dfc8a6fcd9041cb3d8b891387b
BOLT_GIT_REV = 130d2c758964950cf713bddef123104b41642161
BOLT_SRC_DIR = $(BOLT_DIR)/llvm-bolt-$(BOLT_GIT_REV)
BOLT_LLVM_GIT_REV = f137ed238db11440f03083b1c88b7ffc0f4af65e
BOLT_LLVM_SRC_DIR = $(BOLT_DIR)/llvm-$(BOLT_LLVM_GIT_REV)
@ -139,7 +139,7 @@ $(PYXED_PYTHONPATH):
## linking
##
ENCLAVE_CFLAGS = -fvisibility=hidden -fPIC -I$(SGX_INCLUDEDIR)/tlibc -fno-jump-tables -fno-builtin -ffreestanding
ENCLAVE_CFLAGS = -fvisibility=hidden -fPIC -I$(SGX_INCLUDEDIR)/tlibc -fno-jump-tables -mno-red-zone -mindirect-branch-register -fno-builtin -ffreestanding
ENCLAVE_LDFLAGS = \
-Wl,-z,relro,-z,now,-z,noexecstack \
@ -164,7 +164,10 @@ $(builddir)/%.hardened.unstripped.so: $(builddir)/%.unstripped.so | $(LLVM_BOLT)
-o $@ $<
$(builddir)/%.hardened.unsigned.so: $(builddir)/%.hardened.unstripped.so $(PYXED_PYTHONPATH)
objdump -w -j .text -d $< | PYTHONPATH=$(PYXED_PYTHONPATH) python3 bin/lvi_checker
objdump -w -j .text --no-show-raw-insn -d $(builddir)/$*.unstripped.so | \
bin/funcs_with_memindjmp > $(builddir)/funcs_with_memindjmp
objdump -w -j .text -d $< | \
PYTHONPATH=$(PYXED_PYTHONPATH) python3 bin/lvi_checker $(builddir)/funcs_with_memindjmp
objdump -j .text --no-show-raw-insn -d $< | \
egrep '^\s+[0-9a-f]+:\s+(cpuid|getsec|rdpmc|sgdt|sidt|sldt|str|vmcall|vmfunc|rdtscp?|int[0-9a-z]*|iret|syscall|sysenter)\s+' | \
wc -l | grep -q '^0$$'