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:
parent
d85edb9222
commit
28ac367b86
@ -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):
|
||||
|
||||
12
enclave/bin/funcs_with_memindjmp
Executable file
12
enclave/bin/funcs_with_memindjmp
Executable file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/gawk -f
|
||||
|
||||
match($2, /<(.+)>:/, m) {
|
||||
fn = m[1];
|
||||
}
|
||||
|
||||
/jmpq.+[(]/ {
|
||||
if (fn) {
|
||||
print fn;
|
||||
}
|
||||
fn = "";
|
||||
}
|
||||
@ -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)
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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$$'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user