Initial release of Intel SGX for Linux.

This release is used in conjunction with the linux-sgx-driver Intial release:
https://github.com/01org/linux-sgx-driver
commit-id: 0e865ce5e6b297a787bcdc12d98bada8174be6d7

Intel-id: 33399

Signed-off-by: Angie Chinchilla <angie.v.chinchilla@intel.com>
This commit is contained in:
Angie Chinchilla
2016-06-23 18:51:53 -04:00
parent ba82cfcbb0
commit 9441de4c38
2767 changed files with 820699 additions and 0 deletions

View File

@ -0,0 +1,89 @@
#
# Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
include ../../../buildenv.mk
#Don't CFLAGS +=, because it depend on gdb is m32 or m64
CFLAGS :=
CPPFLAGS += -I$(COMMON_DIR)/inc/ \
-I$(COMMON_DIR)/inc/internal/
CFLAGS += -W -Wall -Werror -D_GNU_SOURCE -fpic -fstack-protector
LDLIBS += -ldl
ifdef DEBUG
CFLAGS += -g -DSE_DEBUG=1
endif
OBJ1 := se_memory.o se_trace.o
OBJ2 := se_ptrace.o ptrace_version.o
OBJS := $(OBJ1) $(OBJ2)
GDB_PLUGINS_FILES := gdb-sgx-plugin/sgx_emmt.py \
gdb-sgx-plugin/gdb_sgx_cmd \
gdb-sgx-plugin/gdb_sgx_plugin.py \
gdb-sgx-plugin/load_symbol_cmd.py \
gdb-sgx-plugin/readelf.py
GDB_OUT_DIR := $(BUILD_DIR)/gdb-sgx-plugin
TARGET := libsgx_ptrace.so
.PHONY: all
all: $(TARGET) install
.PHONY:install
install: | $(GDB_OUT_DIR) $(GDB_PLUGINS_FILES)
$(CP) $(GDB_PLUGINS_FILES) $(GDB_OUT_DIR)
$(CP) $(TARGET) $(BUILD_DIR)
$(TARGET): $(OBJS)
$(CC) -shared -o $@ $^ $(LDLIBS) $(CFLAGS)
$(OBJ1): %.o: $(COMMON_DIR)/src/%.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
$(OBJ2): %.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
$(GDB_OUT_DIR):
@$(MKDIR) $@
$(BUILD_DIR):
@$(MKDIR) $@
.PHONY: clean
clean:
@$(RM) $(TARGET) $(OBJS) $(BUILD_DIR)/$(TARGET)
@$(RM) -r $(GDB_OUT_DIR)

View File

@ -0,0 +1,35 @@
#
# Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
# the path can be specified by directory command
define hook-detach
detach_enclaves
end

View File

@ -0,0 +1,597 @@
#!/usr/bin/env python
#
# Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
from __future__ import print_function
import gdb
import struct
import os.path
from ctypes import create_string_buffer
import load_symbol_cmd
import sgx_emmt
# Calculate the bit mode of current debuggee project
SIZE = gdb.parse_and_eval("sizeof(long)")
ET_SIM = 0x1
ET_DEBUG = 0x2
PAGE_SIZE = 0x1000
# The following definitions should strictly align with the structure of
# debug_enclave_info_t in uRTS.
# Here we only care about the first 7 items in the structure.
# pointer: next_enclave_info, start_addr, tcs_list, lpFileName,
# g_peak_heap_used_addr
# int32_t: enclave_type, file_name_size
ENCLAVE_INFO_SIZE = 5 * 8 + 2 * 4
INFO_FMT = 'QQQIIQQ'
ENCLAVES_ADDR = {}
# The following definitions should strictly align with the struct of
# tcs_t
# Here we only care about the first 8 items in the structure
# uint64_t: state, flags, ossa, oentry, aep, ofs_base
# uint32_t: nssa, cssa
ENCLAVE_TCS_INFO_SIZE = 6*8 + 2*4
TCS_INFO_FMT = 'QQQIIQQQ'
def get_inferior():
"""Get current inferior"""
try:
if len(gdb.inferiors()) == 0:
print ("No gdb inferior could be found.")
return -1
else:
inferior = gdb.inferiors()[0]
return inferior
except AttributeError:
print ("This gdb's python support is too old, please update first.")
exit()
def read_from_memory(addr, size):
"""Read data with specified size from the specified meomory"""
inferior = get_inferior()
# actually we can check the addr more securely
# ( check the address is inside the enclave)
if inferior == -1 or addr == 0:
print ("Error happens in read_from_memory: addr = {0:x}".format(int(addr)))
return None
try:
string = inferior.read_memory(addr, size)
return string
except gdb.MemoryError:
print ("Can't access memory at {0:x}.".format(int(addr)))
return None
def write_to_memory(addr, buf):
"""Write a specified buffer to the specified memory"""
inferior = get_inferior()
if inferior == -1 or addr == 0:
print ("Error happens in write_to_memory: addr = {0:x}".format(int(addr)))
return -1
try:
inferior.write_memory(addr, buf)
return 0
except gdb.MemoryError:
print ("Can't access memory at {0:x}.".format(int(addr)))
return -1
def target_path_to_host_path(target_path):
so_name = os.path.basename(target_path)
strpath = gdb.execute("show solib-search-path", False, True)
path = strpath.split()[-1]
strlen = len(path)
path = path[0:strlen-1]
host_path = path + "/" + so_name
#strlen = len(host_path)
#host_path = host_path[0:strlen-7]
return host_path
class enclave_info:
"""Class to contain the enclave inforation,
such as start address, stack addresses, stack size, etc.
The enclave information is for one enclave."""
def __init__(self, _next_ei, _start_addr, _enclave_type, _stack_addr_list, \
_stack_size, _enclave_path, _heap_addr, _tcs_addr_list):
self.next_ei = _next_ei
self.start_addr = _start_addr
self.enclave_type = _enclave_type
self.stack_addr_list = _stack_addr_list
self.stack_size = _stack_size
self.enclave_path = _enclave_path
self.heap_addr = _heap_addr
self.tcs_addr_list = _tcs_addr_list
def __str__(self):
print ("stack address list = {0:s}".format(self.stack_addr_list))
return "start_addr = %#x, enclave_path = \"%s\", stack_size = %d" \
% (self.start_addr, self.enclave_path, self.stack_size)
def __eq__(self, other):
if other == None:
return False
if self.start_addr == other.start_addr:
return True
else:
return False
def init_enclave_debug(self):
# Only product HW enclave can't be debugged
if (self.enclave_type & ET_SIM) != ET_SIM and (self.enclave_type & ET_DEBUG) != ET_DEBUG:
print ('Warning: {0:s} is a product hardware enclave. It can\'t be debugged and sgx_emmt doesn\'t work'.format(self.enclave_path))
return -1
# set TCS debug flag
for tcs_addr in self.tcs_addr_list:
string = read_from_memory(tcs_addr + 8, 4)
if string == None:
return 0
flag = struct.unpack('I', string)[0]
flag |= 1
gdb_cmd = "set *(unsigned int *)%#x = %#x" %(tcs_addr + 8, flag)
gdb.execute(gdb_cmd, False, True)
#If it is a product enclave, won't reach here.
#load enclave symbol
if os.path.exists(self.enclave_path) == True:
enclave_path = self.enclave_path
else:
enclave_path = target_path_to_host_path(self.enclave_path)
gdb_cmd = load_symbol_cmd.GetLoadSymbolCommand(enclave_path, str(self.start_addr))
if gdb_cmd == -1:
return 0
print (gdb_cmd)
gdb.execute(gdb_cmd, False, True)
global ENCLAVES_ADDR
ENCLAVES_ADDR[self.start_addr] = gdb_cmd.split()[2]
return 0
def get_peak_heap_used(self):
"""Get the peak value of the heap used"""
if self.heap_addr == 0:
return -2
# read the peak_heap_used value
string = read_from_memory(self.heap_addr, SIZE)
if string == None:
return -1
if SIZE == 4:
fmt = 'I'
elif SIZE == 8:
fmt = "Q"
peak_heap_used = struct.unpack(fmt, string)[0]
return peak_heap_used
def internal_compare (self, a, b):
return (a > b) - (a < b)
def find_boundary_page_index(self, stack_addr, stack_size):
"""Find the unused page index of the boundary for the used and unused pages
with the binary search algorithm"""
page_index = -1 #record the last unused page index
low = 0
high = (stack_size>>12) - 1
mid = 0
# Read the mid page and check if it is used or not
# If the mid page is used, then continue to search [mid+1, high]
while low <= high:
#print "low = %x, high = %x, mid = %x" % (low, high, mid)
mid = (low + high)>>1
string = read_from_memory(stack_addr + mid*PAGE_SIZE + (PAGE_SIZE>>1), PAGE_SIZE>>1)
if string == None:
return -2
dirty_flag = 0
for i in range(0, PAGE_SIZE>>4):
temp = struct.unpack_from("Q", string, ((PAGE_SIZE>>4) - 1 - i)*8)[0]
if (self.internal_compare(temp, 0xcccccccccccccccc)) != 0:
dirty_flag = 1
break
if dirty_flag == 0:
low = mid + 1
page_index = mid
else:
high = mid -1
return page_index
def get_peak_stack_used(self):
"""Get the peak value of the stack used"""
peak_stack_used = 0
for stack_addr in self.stack_addr_list:
page_index = self.find_boundary_page_index(stack_addr, self.stack_size)
if page_index == (self.stack_size)/PAGE_SIZE - 1:
continue
elif page_index == -2:
return -1
else:
string = read_from_memory(stack_addr + (page_index+1) * PAGE_SIZE, PAGE_SIZE)
if string == None:
return -1
for i in range(0, len(string)):
temp = struct.unpack_from("B", string, i)[0]
if (self.internal_compare(temp, 0xcc)) != 0:
if peak_stack_used < (self.stack_size - (page_index+1) * PAGE_SIZE - i):
peak_stack_used = self.stack_size- (page_index+1) * PAGE_SIZE - i
break # go to the top for loop
return peak_stack_used
def show_emmt(self):
ret = gdb.execute("show sgx_emmt", False, True)
if ret.strip() == "sgx_emmt enabled":
print ("Enclave: \"{0:s}\"".format(self.enclave_path))
peak_stack_used = self.get_peak_stack_used()
if peak_stack_used == -1:
print ("Failed to collect the stack usage information for \"{0:s}\"".format(self.enclave_path))
else:
print (" [Peak stack used]: {0:x}".format(peak_stack_used))
peak_heap_used = self.get_peak_heap_used()
if peak_heap_used == -1:
print ("Failed to collect the heap usage information for \"{0:s}\"".format(self.enclave_path))
elif peak_heap_used == -2:
print (" [Can't get peak heap used]: You may use version script to control symbol export. Please export \'g_peak_heap_used\' in your version script.")
else:
print (" [Peak heap used]: {0:x}".format(peak_heap_used))
def fini_enclave_debug(self):
# If it is HW product enclave, nothing to do
if (self.enclave_type & ET_SIM) != ET_SIM and (self.enclave_type & ET_DEBUG) != ET_DEBUG:
return -2
self.show_emmt()
try:
# clear TCS debug flag
for tcs_addr in self.tcs_addr_list:
string = read_from_memory(tcs_addr + 8, 4)
if string == None:
return -2
flag = struct.unpack('I', string)[0]
flag &= (~1)
gdb_cmd = "set *(unsigned int *)%#x = %#x" %(tcs_addr + 8, flag)
gdb.execute(gdb_cmd, False, True)
#unload symbol
if os.path.exists(self.enclave_path) == True:
enclave_path = self.enclave_path
else:
enclave_path = target_path_to_host_path(self.enclave_path)
gdb_cmd = load_symbol_cmd.GetUnloadSymbolCommand(enclave_path, str(self.start_addr))
if gdb_cmd == -1:
return -1
print (gdb_cmd)
try:
gdb.execute(gdb_cmd, False, True)
global ENCLAVES_ADDR
del ENCLAVES_ADDR[self.start_addr]
except gdb.error:
print ("Old gdb doesn't support remove-file-symbol command")
return 0
##It is possible enclave has been destroyed, so may raise exception on memory access
except gdb.MemoryError:
return -1
except:
return -1
def retrieve_enclave_info(info_addr = 0):
"""retrieve one enclave info"""
# Step 1: find the enclave info address
if info_addr == 0:
if SIZE == 4:
info_addr = gdb.parse_and_eval("$eax")
elif SIZE == 8:
info_addr = gdb.parse_and_eval("$rdi")
# Step 2: retrieve the enclave info
info_str = read_from_memory(info_addr, ENCLAVE_INFO_SIZE)
if info_str == None:
return None
info_tuple = struct.unpack_from(INFO_FMT, info_str, 0)
# (next_enclave_info,start_addr,tcs_list,enclave_type,file_name_size,
# lpFileName,g_peak_heap_used_addr)
#print "next_addr: %#x, start_addr: %#x, tcs_list: %#x, enclave_type:%#x, file_name_size: %#x," \
# % (info_tuple[0], info_tuple[1], info_tuple[2], info_tuple[3], info_tuple[4])
#print "name_addr: %#x, peak_heap_used_addr: %#x" \
# % (info_tuple[5], info_tuple[6])
#get enclave path
name_str = read_from_memory(info_tuple[5], info_tuple[4])
if name_str == None:
return None
fmt = str(info_tuple[4]) + 's'
enclave_path = struct.unpack_from(fmt, name_str)[0].decode(encoding='UTF-8')
# get the stack addr list
stack_addr_list = []
tcs_addr_list = []
if SIZE == 4:
fmt = '3I'
elif SIZE == 8:
fmt = '3Q'
tcs_info_addr = info_tuple[2]
if tcs_info_addr == 0:
print ("Error: tcs info address = {0:x}".format(tcs_info_addr))
return None
while tcs_info_addr is not 0:
tcs_info_str = read_from_memory(tcs_info_addr, 3*SIZE)
if tcs_info_str == None:
return None
tcs_info_tuple = struct.unpack_from(fmt, tcs_info_str)
#get tcs struct data
tcs_t_str = read_from_memory(tcs_info_tuple[1], ENCLAVE_TCS_INFO_SIZE)
if tcs_t_str == None:
return None
tcs_t_tuple = struct.unpack_from(TCS_INFO_FMT, tcs_t_str)
if SIZE == 4:
td_fmt = '4I'
elif SIZE == 8:
td_fmt = '4Q'
#get thread_data_t address
td_addr = tcs_t_tuple[7] + info_tuple[1] #thread_data_t = tcs.of_base + debug_enclave_info.start_addr
td_str = read_from_memory(td_addr, (4*SIZE))
if td_str == None:
return None
td_tuple = struct.unpack_from(td_fmt, td_str)
#print ("thread_info:%#x, last_sp:%#x, stack_base_addr:%#x, stack_limit_addr:%#x" \
# % (td_tuple[0], td_tuple[1], td_tuple[2], td_tuple[3]));
stacksize = td_tuple[2] - td_tuple[3] #stack size = stack_base_addr - stack_limit_addr
stack_addr_list.append(td_tuple[3]) #use stack limit addr as stack base address
tcs_addr_list.append(tcs_info_tuple[1])
tcs_info_addr = tcs_info_tuple[0]
last_ocall_frame = tcs_info_tuple[2]
last_frame = last_ocall_frame
#print ("last_ocall_frame = {0:x}".format(last_ocall_frame))
while last_ocall_frame is not 0:
if SIZE == 4:
of_fmt = '4I'
elif SIZE == 8:
of_fmt = '4Q'
ocall_frame = read_from_memory(last_ocall_frame, 4*SIZE)
if ocall_frame == None:
return None
ocall_frame_tuple = struct.unpack_from(of_fmt, ocall_frame)
last_frame = ocall_frame_tuple[0]
last_trusted_ocall_frame = td_tuple[1]
#print ("last_trusted_ocall_frame = {0:x}".format(last_trusted_ocall_frame))
#print ("td_tuple[2] = {0:x}".format(td_tuple[2]))
#break
while last_trusted_ocall_frame != td_tuple[2]:
if SIZE == 4:
oc_fmt = '20I'
elif SIZE == 8:
oc_fmt = '20Q'
oc_str = read_from_memory(last_trusted_ocall_frame, 20*SIZE)
if oc_str == None:
return None
oc_tuple = struct.unpack_from(oc_fmt, oc_str)
last_trusted_ocall_frame = oc_tuple[6]
#print ("last_trusted_ocall_frame = {0:x}".format(last_trusted_ocall_frame))
#print ("ocall_frame_tuple[1] = {0:x}".format(ocall_frame_tuple[1]))
#print ("oc_tuple[18] = {0:x}".format(oc_tuple[18]))
#break
if ocall_frame_tuple[1] == oc_tuple[18]:
#ocall_frame.pre_last_frame = 0
#ocall_frame.ret = ocall_context.ocall_ret
#ocall_frame.xbp = ocall_context.xbp
gdb_cmd = "set *(uintptr_t *)%#x = 0" %(last_ocall_frame)
gdb.execute(gdb_cmd, False, True)
gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(last_ocall_frame+(2*SIZE), oc_tuple[11])
gdb.execute(gdb_cmd, False, True)
gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(last_ocall_frame+(3*SIZE), oc_tuple[19])
gdb.execute(gdb_cmd, False, True)
break
last_ocall_frame = last_frame
node = enclave_info(info_tuple[0], info_tuple[1], info_tuple[3], stack_addr_list, \
stacksize, enclave_path, info_tuple[6], tcs_addr_list)
return node
def handle_load_event():
"""Handle the enclave loading event.
Firstly, retrieve the enclave info node from register
"""
node = retrieve_enclave_info()
if node != None:
node.init_enclave_debug()
else:
return
def handle_unload_event():
node = retrieve_enclave_info()
if node != None:
node.fini_enclave_debug()
else:
return
def is_bp_in_urts():
try:
ip = gdb.parse_and_eval("$pc")
solib_name = gdb.solib_name(int(str(ip).split()[0], 16))
if(solib_name.find("libsgx_urts.so") == -1 and solib_name.find("libsgx_urts_sim.so") == -1 and solib_name.find("libsgx_aesm_service.so") == -1):
return False
else:
return True
#If exception happens, just assume it is bp in uRTS.
except:
return True
def init_enclaves_debug():
enclave_info_addr = gdb.parse_and_eval("*(void**)&g_debug_enclave_info_list")
while enclave_info_addr != 0:
node = retrieve_enclave_info(enclave_info_addr)
if node != None:
node.init_enclave_debug()
else:
return
enclave_info_addr = node.next_ei
return
class detach_enclaves (gdb.Command):
def __init__ (self):
gdb.Command.__init__ (self, "detach_enclaves", gdb.COMMAND_NONE)
def invoke (self, arg, from_tty):
#We reject the command from the input of terminal
if from_tty == True:
return
try:
enclave_info_addr = gdb.parse_and_eval("*(void**)&g_debug_enclave_info_list")
except:
return
while enclave_info_addr != 0:
node = retrieve_enclave_info(enclave_info_addr)
if node != None:
node.fini_enclave_debug()
else:
return
enclave_info_addr = node.next_ei
class UpdateOcallFrame(gdb.Breakpoint):
def __init__(self):
gdb.Breakpoint.__init__ (self, spec="notify_gdb_to_update", internal=1)
def stop(self):
bp_in_urts = is_bp_in_urts()
if bp_in_urts == True:
if SIZE == 4:
base_addr = gdb.parse_and_eval("base")
tcs_addr = gdb.parse_and_eval("tcs")
ocall_frame = gdb.parse_and_eval("of")
elif SIZE == 8:
base_addr = gdb.parse_and_eval("$rdi")
tcs_addr = gdb.parse_and_eval("$rsi")
ocall_frame = gdb.parse_and_eval("$rdx")
#print ("base_addr = {0:x}".format(int(base_addr)))
#print ("tcs_addr = {0:x}".format(int(tcs_addr)))
#print ("ocall_frame = {0:x}".format(int(ocall_frame)))
tcs_str = read_from_memory(tcs_addr, ENCLAVE_TCS_INFO_SIZE)
if tcs_str == None:
return False
tcs_tuple = struct.unpack_from(TCS_INFO_FMT, tcs_str)
offset = tcs_tuple[7]
if SIZE == 4:
td_fmt = '4I'
elif SIZE == 8:
td_fmt = '4Q'
td_str = read_from_memory(base_addr+offset, (4*SIZE))
if td_str == None:
return False
td_tuple = struct.unpack_from(td_fmt, td_str)
if SIZE == 4:
trusted_of_fmt = '20I'
elif SIZE == 8:
trusted_of_fmt = '20Q'
last_sp = td_tuple[1]
trusted_ocall_frame = read_from_memory(last_sp, (20*SIZE))
if trusted_ocall_frame == None:
return False
trusted_ocall_frame_tuple = struct.unpack_from(trusted_of_fmt, trusted_ocall_frame)
gdb_cmd = "set *(uintptr_t *)%#x = 0" %(ocall_frame)
gdb.execute(gdb_cmd, False, True)
gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(ocall_frame+(2*SIZE), trusted_ocall_frame_tuple[11])
gdb.execute(gdb_cmd, False, True)
gdb_cmd = "set *(uintptr_t *)%#x = %#x" %(ocall_frame+(3*SIZE), trusted_ocall_frame_tuple[19])
gdb.execute(gdb_cmd, False, True)
return False
class LoadEventBreakpoint(gdb.Breakpoint):
def __init__(self):
gdb.Breakpoint.__init__ (self, spec="sgx_debug_load_state_add_element", internal=1)
def stop(self):
bp_in_urts = is_bp_in_urts()
if bp_in_urts == True:
handle_load_event()
return False
class UnloadEventBreakpoint(gdb.Breakpoint):
def __init__(self):
gdb.Breakpoint.__init__ (self, spec="sgx_debug_unload_state_remove_element", internal=1)
def stop(self):
bp_in_urts = is_bp_in_urts()
if bp_in_urts == True:
handle_unload_event()
return False
def sgx_debugger_init():
print ("detect urts is loaded, initializing")
global SIZE
SIZE = gdb.parse_and_eval("sizeof(long)")
inited = 0
bps = gdb.breakpoints()
if None != bps:
for bp in bps:
if bp.location == "sgx_debug_load_state_add_element":
inited = 1
break
if inited == 0:
detach_enclaves()
gdb.execute("source gdb_sgx_cmd", False, True)
UpdateOcallFrame()
LoadEventBreakpoint()
UnloadEventBreakpoint()
gdb.events.exited.connect(exit_handler)
init_enclaves_debug()
def exit_handler(event):
# When the inferior exited, remove all enclave symbol
for key in ENCLAVES_ADDR.keys():
gdb.execute("remove-symbol-file -a %s" % (ENCLAVES_ADDR[key]), False, True)
ENCLAVES_ADDR.clear()
def newobj_handler(event):
solib_name = os.path.basename(event.new_objfile.filename)
if solib_name == 'libsgx_urts.so' or solib_name == 'libsgx_urts_sim.so' or solib_name == 'libsgx_aesm_service.so':
sgx_debugger_init()
return
if __name__ == "__main__":
gdb.events.new_objfile.connect(newobj_handler)
sgx_emmt.init_emmt()

View File

@ -0,0 +1,132 @@
#!/usr/bin/env python
#
# Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import traceback, errno, string, re, sys, time, readelf;
def GetLoadSymbolCommand(EnclaveFile, Base):
text = readelf.ReadElf(EnclaveFile)
if text == None:
return -1
SegsFile = StringIO(text)
try:
FileList = SegsFile.readlines()
n=4;
m=100;
Out = [[[] for ni in range(n)] for mi in range(m)]
i=0;
Out[99][2] = '0';
# Parse the readelf output file to extract the section names and
# their offsets and add the Proj base address.
for line in FileList:
list = line.split();
if(len(list) > 0):
SegOffset = -1;
# The readelf will put a space after the open bracket for single
# digit section numbers. This causes the line.split to create
# an extra element in the array for these lines.
if(re.match('\[\s*[0-9]+\]',list[0])):
SegOffset = 0;
if(re.match('\s*[0-9]+\]',list[1])):
SegOffset = 1;
if(SegOffset != -1):
if (list[SegOffset+1][0] == '.'):
# If it is the .text section, put it in a special place in the array
# because the 'add-symbol-file' command treats it differently.
#print "%#08x" % (int(list[SegOffset+3], 16))
if(list[SegOffset+1].find(".text") != -1):
Out[99][0] = "-s";
Out[99][1] = list[SegOffset+1];
Out[99][2] = str(int(list[SegOffset+3], 16) + int(Base, 10));
Out[99][3] = " ";
elif(int(list[SegOffset+3], 16) != 0):
Out[i][0] = "-s";
Out[i][1] = list[SegOffset+1];
Out[i][2] = str(int(list[SegOffset+3], 16) + int(Base, 10));
Out[i][3] = " ";
i = i+1;
if('0' != Out[99][2]):
# The last section must not have the '\' line continuation character.
Out[i-1][3] = '';
# Write the GDB 'add-symbol-file' command with all the arguments to the setup GDB command file.
# Note: The mandatory argument for the 'add-symbol-file' command is the .text section without a
# '-s .SectionName'. All other sections need the '-s .SectionName'.
gdbcmd = "add-symbol-file '" + EnclaveFile + "' " + '%(Location)#08x' % {'Location':int(Out[99][2])} + " -readnow "
for j in range(i):
gdbcmd += Out[j][0] + " " + Out[j][1] + " " + '%(Location)#08x' % {'Location' : int(Out[j][2])} + " " + Out[j][3]
else:
return -1
return gdbcmd
except:
print ("Error parsing enclave file. Check format of file.")
return -1
def GetUnloadSymbolCommand(EnclaveFile, Base):
text = readelf.ReadElf(EnclaveFile)
if text == None:
return -1
SegsFile = StringIO(text)
try:
FileList = SegsFile.readlines()
# Parse the readelf output file to extract the section names and
# their offsets and add the Proj base address.
for line in FileList:
list = line.split();
if(len(list) > 0):
SegOffset = -1;
# The readelf will put a space after the open bracket for single
# digit section numbers. This causes the line.split to create
# an extra element in the array for these lines.
if(re.match('\[\s*[0-9]+\]',list[0])):
SegOffset = 0;
if(re.match('\s*[0-9]+\]',list[1])):
SegOffset = 1;
if(SegOffset != -1):
if (list[SegOffset+1][0] == '.'):
# If it is the .text section, get the .text start address and plus enclave start address
if(list[SegOffset+1].find(".text") != -1):
return "remove-symbol-file -a " + str(int(list[SegOffset+3], 16) + int(Base, 10))
except:
print ("Error parsing enclave file. Check format of file.")
return -1

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python
#
# Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
import gdb, subprocess
def ReadElf(EnclaveFile):
prefix = gdb.execute("get_tc_prefix", False, True)
readelf_cmd = 'readelf'
if prefix.strip() != 'None':
readelf_cmd = prefix.strip() + 'readelf'
try:
text = subprocess.check_output([readelf_cmd,
'-W',
'-S',
EnclaveFile],
universal_newlines=True
)
except subprocess.CalledProcessError as e:
text = None
return text

View File

@ -0,0 +1,94 @@
#!/usr/bin/env python
#
# Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
import gdb
ENABLE_EMMT = 0
TC_PREFIX = None
TC_PREFIX_DONE = False
class enable_emmt (gdb.Command):
def __init__ (self):
gdb.Command.__init__ (self, "enable sgx_emmt", gdb.COMMAND_RUNNING)
def invoke (self, arg, from_tty):
global ENABLE_EMMT
ENABLE_EMMT = 1
class disable_emmt (gdb.Command):
def __init__ (self):
gdb.Command.__init__ (self, "disable sgx_emmt", gdb.COMMAND_RUNNING)
def invoke (self, arg, from_tty):
global ENABLE_EMMT
ENABLE_EMMT = 0
class show_emmt (gdb.Command):
def __init__ (self):
gdb.Command.__init__ (self, "show sgx_emmt", gdb.COMMAND_RUNNING)
def invoke (self, arg, from_tty):
global ENABLE_EMMT
if ENABLE_EMMT == 1:
print ("sgx_emmt enabled")
if ENABLE_EMMT == 0:
print ("sgx_emmt disabled")
class set_tc_prefix(gdb.Command):
def __init__ (self):
gdb.Command.__init__ (self, "set_tc_prefix", gdb.COMMAND_NONE)
def invoke (self, arg, from_tty):
global TC_PREFIX, TC_PREFIX_DONE
#For internal use, and don't allow input by gdb user
if TC_PREFIX_DONE == True:
return
TC_PREFIX = arg
TC_PREFIX_DONE = True
class get_tc_prefix(gdb.Command):
def __init__ (self):
gdb.Command.__init__ (self, "get_tc_prefix", gdb.COMMAND_NONE)
def invoke (self, arg, from_tty):
global TC_PREFIX
#For internal use, and don't allow output to tty
if from_tty == True:
return
print (TC_PREFIX)
def init_emmt():
enable_emmt()
disable_emmt()
show_emmt()
set_tc_prefix()
get_tc_prefix()

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "se_version.h"
#include "se_cdefs.h"
#define __CONCAT(x, y) x/**/y
#define SGX_PTRACE_VERSION_STR __CONCAT("SGX_PTRACE_VERSION_", STRFILEVER)
__attribute__((visibility("default")))
const char * sgx_ptrace_version = SGX_PTRACE_VERSION_STR;
SGX_ACCESS_VERSION(ptrace, 1)

View File

@ -0,0 +1,594 @@
/*
* Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "arch.h"
#include "thread_data.h"
#include "util.h"
#include "se_trace.h"
#include "se_memory.h"
#include <unistd.h>
#include <sys/ptrace.h>
#include <dlfcn.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdio.h>
#include <sys/user.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <elf.h>
#include <assert.h>
//NOTE: Need align with thread_data_t in RTS.
#define ELF32_SSA_FS_OFFSET 0x34
#ifdef __x86_64__
#define SSA2USER_REG(to, from, name) to->r##name = from.r##name
#define USER_REG2SSA(to, from, name) to.r##name = from->r##name
#else
#define SSA2USER_REG(to, from, name) to->e##name = from.e##name
#define USER_REG2SSA(to, from, name) to.e##name = from->e##name
#endif
#define XSTATE_MAX_SIZE 832
typedef enum _direction_t
{
FORWARD,
BACKWARD
} direction_t;
typedef long int (* ptrace_t)(enum __ptrace_request request, pid_t pid,
void *addr, void *data);
static ptrace_t g_sys_ptrace = NULL;
__attribute__((constructor)) void init()
{
g_sys_ptrace = (ptrace_t)dlsym(RTLD_NEXT, "ptrace");
}
#ifdef SE_DEBUG
static void dump_ssa_gregs(ssa_gpr_t* gpr) __attribute__((unused));
void dump_ssa_gregs(ssa_gpr_t* gpr)
{
SE_TRACE(SE_TRACE_DEBUG, "ssa generic registers:\n");
SE_TRACE(SE_TRACE_DEBUG, "xbx = %#lx\t", gpr->REG(bx));
SE_TRACE(SE_TRACE_DEBUG, "xcx = %#lx\t", gpr->REG(cx));
SE_TRACE(SE_TRACE_DEBUG, "xdx = %#lx\t", gpr->REG(dx));
SE_TRACE(SE_TRACE_DEBUG, "xsi = %#lx\t", gpr->REG(si));
SE_TRACE(SE_TRACE_DEBUG, "xdi = %#lx\t", gpr->REG(di));
SE_TRACE(SE_TRACE_DEBUG, "xbp = %#lx\t", gpr->REG(bp));
SE_TRACE(SE_TRACE_DEBUG, "xax = %#lx\t", gpr->REG(ax));
SE_TRACE(SE_TRACE_DEBUG, "xip = %#lx\t", gpr->REG(ip));
SE_TRACE(SE_TRACE_DEBUG, "xflags = %#lx\t", gpr->REG(flags));
SE_TRACE(SE_TRACE_DEBUG, "xsp = %#lx\t", gpr->REG(sp));
}
static void dump_regs(struct user_regs_struct *regs) __attribute__((unused));
void dump_regs(struct user_regs_struct *regs)
{
SE_TRACE(SE_TRACE_DEBUG, "user regisers:\n");
SE_TRACE(SE_TRACE_DEBUG, "xbx = %#x\t", regs->REG(bx));
SE_TRACE(SE_TRACE_DEBUG, "xcx = %#x\t", regs->REG(cx));
SE_TRACE(SE_TRACE_DEBUG, "xdx = %#x\t", regs->REG(dx));
SE_TRACE(SE_TRACE_DEBUG, "xsi = %#x\t", regs->REG(si));
SE_TRACE(SE_TRACE_DEBUG, "xdi = %#x\t", regs->REG(di));
SE_TRACE(SE_TRACE_DEBUG, "xbp = %#x\t", regs->REG(bp));
SE_TRACE(SE_TRACE_DEBUG, "xax = %#x\t", regs->REG(ax));
SE_TRACE(SE_TRACE_DEBUG, "xip = %#x\t", regs->REG(ip));
SE_TRACE(SE_TRACE_DEBUG, "xflags = %#x\t", regs->eflags);
SE_TRACE(SE_TRACE_DEBUG, "xsp = %#x\t", regs->REG(sp));
}
#else
#define dump_ssa_gregs(gpr)
#define dump_regs(regs)
#endif
#ifdef __x86_64__
static int get_exec_class(pid_t pid)
{
char filename[64];
int fd = -1;
unsigned char e_ident[EI_NIDENT];
snprintf(filename, 64, "/proc/%d/exe", pid);
fd = open(filename, O_RDONLY | O_LARGEFILE);
if(fd == -1)
return ELFCLASSNONE;
if(-1 == read(fd, e_ident, EI_NIDENT))
{
return ELFCLASSNONE;
}
close(fd);
return e_ident[EI_CLASS];
}
#endif
static inline uint32_t get_ssa_frame_size(pid_t pid, thread_data_t* td)
{
uint32_t ssa_frame_size = td->ssa_frame_size;
#ifdef __x86_64__
//on x64, we may debug elf32 enclave, we need refer to different offset in td field.
if(ELFCLASS32 == get_exec_class(pid))
{
ssa_frame_size = *GET_PTR(uint32_t, td, ELF32_SSA_FS_OFFSET);
}
#else
UNUSED(pid);
#endif
//When debug trts, ssa_frame_size in TD is not initialized, so the value will be 0.
//It is a limitation to debug trts. As work around, the default size is 1 page, so
//we can debug enclave from the start of enclave_entry.
if(0 == ssa_frame_size)
ssa_frame_size = 1;
return ssa_frame_size;
}
/*
*This function get the position/offset with SSA
* @pid, process id
* @tcs_addr, TCS start address
* @dir, calculate the position from start of SSA or from the end of SSA
* @offset, offset from the start
* @size, size of data from the postion that is going to be accessed
* @pos, the result of postion that the function output
* @return, TRUE on success, FALSE on fail. The result is copied to parameter pos
* */
static int get_ssa_pos(pid_t pid, long tcs_addr, direction_t dir, long offset, long size, long *pos)
{
tcs_t tcs;
thread_data_t td;
uint32_t ssa_frame_size = 0;
long addr = 0;
//read TCS;
if(!se_read_process_mem(pid, (void *)tcs_addr, (void *)&tcs, 72, NULL))
return FALSE;
//Align with RTS. We assume TD is next to TCS
long ssa_start = tcs_addr + TCS_SIZE;
//ossa point to the start address of SSA, and fs/gs point to the start address of TD.
long td_start = ssa_start - tcs.ossa + tcs.ofs_base;
//Read thread data; On x64, sizeof(thread_data_t) of elf64 is larger than elf32,
//so it won't miss any field if it is elf32 executable;
if(!se_read_process_mem(pid, (void *)td_start, (void *)&td, sizeof(thread_data_t), NULL))
return FALSE;
ssa_frame_size = get_ssa_frame_size(pid, &td);
//The request should not exceed ssa frame boundary.
if((offset + size) > (long)ssa_frame_size * SE_PAGE_SIZE)
return FALSE;
assert(tcs.cssa > 0);
//If it is required to calculate from the start of SSA
if(FORWARD == dir)
{
addr = ssa_start + (tcs.cssa - 1) * ssa_frame_size * SE_PAGE_SIZE + offset;
}
//If it is required to calculate from the end of SSA
else if(BACKWARD == dir)
{
addr = ssa_start + tcs.cssa * ssa_frame_size * SE_PAGE_SIZE - offset;
}
else
return FALSE;
*pos = addr;
return TRUE;
}
static inline int read_ssa(pid_t pid, long tcs_addr, direction_t dir, long offset, long size, void *buf)
{
long addr = 0;
if(!get_ssa_pos(pid, tcs_addr, dir, offset, size, &addr))
return FALSE;
//read the content of ssa
if(!se_read_process_mem(pid, (void *)addr, buf, size, NULL))
return FALSE;
return TRUE;
}
static inline int write_ssa(pid_t pid, long tcs_addr, direction_t dir, long offset, long size, void *buf)
{
long addr = 0;
if(!get_ssa_pos(pid, tcs_addr, dir, offset, size, &addr))
return FALSE;
//write the content of ssa
if(!se_write_process_mem(pid, (void *)addr, buf, size, NULL))
return FALSE;
return TRUE;
}
static inline int get_ssa_gpr(pid_t pid, long tcs_addr, ssa_gpr_t* gpr)
{
//read general registers. ssa_gpr_t is elf32/elf64 independent.
return read_ssa(pid, tcs_addr, BACKWARD, sizeof(ssa_gpr_t), sizeof(ssa_gpr_t), (void *)gpr);
}
static inline int set_ssa_gpr(pid_t pid, long tcs_addr, ssa_gpr_t* gpr)
{
//read general registers. ssa_gpr_t is elf32/elf64 independent.
return write_ssa(pid, tcs_addr, BACKWARD, sizeof(ssa_gpr_t), sizeof(ssa_gpr_t), (void *)gpr);
}
static inline int get_ssa_fpregs(pid_t pid, long tcs_addr, struct user_fpregs_struct* fpregs)
{
return read_ssa(pid, tcs_addr, FORWARD, 0, sizeof(struct user_fpregs_struct), (void *)fpregs);
}
static inline int set_ssa_fpregs(pid_t pid, long tcs_addr, struct user_fpregs_struct* fpregs)
{
return write_ssa(pid, tcs_addr, FORWARD, 0, sizeof(struct user_fpregs_struct), (void *)fpregs);
}
#if !defined(__x86_64__) && !defined(__x86_64)
static inline int get_ssa_fpxregs(pid_t pid, long tcs_addr, struct user_fpxregs_struct* fpxregs)
{
return read_ssa(pid, tcs_addr, FORWARD, 0, sizeof(struct user_fpxregs_struct), (void *)fpxregs);
}
static inline int set_ssa_fpxregs(pid_t pid, long tcs_addr, struct user_fpxregs_struct* fpxregs)
{
return write_ssa(pid, tcs_addr, FORWARD, 0, sizeof(struct user_fpxregs_struct), (void *)fpxregs);
}
#else
#define get_ssa_fpxregs get_ssa_fpregs
#define set_ssa_fpxregs set_ssa_fpregs
#define user_fpxregs_struct user_fpregs_struct
#endif
static inline int get_ssa_xstate(pid_t pid, long tcs_addr, int len, char *buf)
{
return read_ssa(pid, tcs_addr, FORWARD, 0, len, buf);
}
static inline int set_ssa_xstate(pid_t pid, long tcs_addr, int len, char *buf)
{
return write_ssa(pid, tcs_addr, FORWARD, 0, len, buf);
}
static int get_enclave_gregs(pid_t pid, struct user_regs_struct *regs, long tcs_addr)
{
ssa_gpr_t gpr;
if(!get_ssa_gpr(pid, tcs_addr, &gpr))
return -1;
//convert gpr to user_regs_struct.
SSA2USER_REG(regs, gpr, bx);
SSA2USER_REG(regs, gpr, cx);
SSA2USER_REG(regs, gpr, dx);
SSA2USER_REG(regs, gpr, si);
SSA2USER_REG(regs, gpr, di);
SSA2USER_REG(regs, gpr, bp);
SSA2USER_REG(regs, gpr, ax);
SSA2USER_REG(regs, gpr, ip);
regs->eflags = gpr.REG(flags);
SSA2USER_REG(regs, gpr, sp);
#ifdef __x86_64__
SSA2USER_REG(regs, gpr, 8);
SSA2USER_REG(regs, gpr, 9);
SSA2USER_REG(regs, gpr, 10);
SSA2USER_REG(regs, gpr, 11);
SSA2USER_REG(regs, gpr, 12);
SSA2USER_REG(regs, gpr, 13);
SSA2USER_REG(regs, gpr, 14);
SSA2USER_REG(regs, gpr, 15);
#endif
return 0;
}
static int set_enclave_gregs(pid_t pid, struct user_regs_struct *regs, long tcs_addr)
{
ssa_gpr_t gpr;
//Since there is some field won't be written, we need save it first
if(!get_ssa_gpr(pid, tcs_addr, &gpr))
return -1;
//convert gpr to user_regs_struct.
USER_REG2SSA(gpr, regs, bx);
USER_REG2SSA(gpr, regs, cx);
USER_REG2SSA(gpr, regs, dx);
USER_REG2SSA(gpr, regs, si);
USER_REG2SSA(gpr, regs, di);
USER_REG2SSA(gpr, regs, bp);
USER_REG2SSA(gpr, regs, ax);
USER_REG2SSA(gpr, regs, ip);
gpr.REG(flags) = regs->eflags;
USER_REG2SSA(gpr, regs, sp);
#ifdef __x86_64__
USER_REG2SSA(gpr, regs, 8);
USER_REG2SSA(gpr, regs, 9);
USER_REG2SSA(gpr, regs, 10);
USER_REG2SSA(gpr, regs, 11);
USER_REG2SSA(gpr, regs, 12);
USER_REG2SSA(gpr, regs, 13);
USER_REG2SSA(gpr, regs, 14);
USER_REG2SSA(gpr, regs, 15);
#endif
//write general registers to ssa
if(!set_ssa_gpr(pid, tcs_addr, &gpr))
return -1;
return 0;
}
static int is_eresume(pid_t pid, struct user_regs_struct *regs)
{
unsigned int instr;
if(!se_read_process_mem(pid, (void *)regs->REG(ip), (char *)&instr, sizeof(instr), NULL))
return FALSE;
if((ENCLU == (instr & 0xffffff))
&& (SE_ERESUME == regs->REG(ax)))
return TRUE;
return FALSE;
}
static long int get_regs(pid_t pid, void* addr, void* data)
{
int ret = 0;
if(!data)
return -1;
struct user_regs_struct *regs = (struct user_regs_struct *)data;
if(-1 == (ret = g_sys_ptrace(PTRACE_GETREGS, pid, addr, data)))
return -1;
if(is_eresume(pid, regs))
{
//If it is ERESUME instruction, set the real register value
if(-1 == get_enclave_gregs(pid, regs, regs->REG(bx)))
return -1;
else
{
return ret;
}
}
return ret;
}
static long int set_regs(pid_t pid, void* addr, void* data)
{
int ret = 0;
struct user_regs_struct aep_regs;
if(!data)
return -1;
if(-1 == g_sys_ptrace(PTRACE_GETREGS, pid, 0, (void*)&aep_regs))
return -1;
if(is_eresume(pid, &aep_regs))
{
struct user_regs_struct *regs = (struct user_regs_struct *)data;
//get tcs address
if(-1 == (ret = set_enclave_gregs(pid, regs, aep_regs.REG(bx))))
return -1;
else
return ret;
}
else
{
return g_sys_ptrace(PTRACE_SETREGS, pid, addr, data);
}
}
static long int get_fpregs(pid_t pid, void* addr, void* data, int extend)
{
int ret = 0;
if(!data)
return -1;
struct user_regs_struct regs;
if(-1 == (ret = g_sys_ptrace(PTRACE_GETREGS, pid, 0, &regs)))
return -1;
if(is_eresume(pid, &regs))
{
if(extend)
ret = get_ssa_fpxregs(pid, regs.REG(bx), (struct user_fpxregs_struct *)data);
else
ret = get_ssa_fpregs(pid, regs.REG(bx), (struct user_fpregs_struct *)data);
if(ret)
return 0;
else
return -1;
}
else
{
return g_sys_ptrace(PTRACE_GETFPREGS, pid, addr, data);
}
}
static long int set_fpregs(pid_t pid, void* addr, void* data, int extend)
{
int ret = 0;
if(!data)
return -1;
struct user_regs_struct regs;
if(-1 == (ret = g_sys_ptrace(PTRACE_GETREGS, pid, 0, &regs)))
return -1;
if(is_eresume(pid, &regs))
{
if(extend)
ret = set_ssa_fpxregs(pid, regs.REG(bx), (struct user_fpxregs_struct *)data);
else
ret = set_ssa_fpregs(pid, regs.REG(bx), (struct user_fpregs_struct *)data);
if(ret)
return 0;
else
return -1;
}
else
{
return g_sys_ptrace(PTRACE_GETFPREGS, pid, addr, data);
}
}
static long int get_regset(pid_t pid, void* addr, void* data)
{
int ret = 0;
unsigned long type = (unsigned long)addr;
if(!data)
return -1;
struct user_regs_struct regs;
if(-1 == (ret = g_sys_ptrace(PTRACE_GETREGS, pid, 0, &regs)))
return -1;
if(is_eresume(pid, &regs))
{
if(NT_X86_XSTATE != type)
{
SE_TRACE(SE_TRACE_WARNING, "unexpected type for PTRACE_GETREGSET\n");
return -1;
}
struct iovec *iov = (struct iovec *)data;
if(iov->iov_base && iov->iov_len
&& get_ssa_xstate(pid, regs.REG(bx), iov->iov_len, (char *)iov->iov_base))
{
return 0;
}
else
return -1;
}
else
{
return g_sys_ptrace(PTRACE_GETREGSET, pid, addr, data);
}
}
static long int set_regset(pid_t pid, void* addr, void* data)
{
int ret = 0;
unsigned long type = (unsigned long)addr;
if(!data)
return -1;
struct user_regs_struct regs;
if(-1 == (ret = g_sys_ptrace(PTRACE_GETREGS, pid, 0, &regs)))
return -1;
if(is_eresume(pid, &regs))
{
if(NT_X86_XSTATE != type)
{
SE_TRACE(SE_TRACE_WARNING, "unexpected type for PTRACE_SETREGSET\n");
return -1;
}
struct iovec *iov = (struct iovec *)data;
if(iov->iov_base && iov->iov_len
&& set_ssa_xstate(pid, regs.REG(bx), iov->iov_len, (char *)iov->iov_base))
{
return 0;
}
else
return -1;
}
else
{
return g_sys_ptrace(PTRACE_SETREGSET, pid, addr, data);
}
}
long int ptrace (enum __ptrace_request __request, ...)
{
pid_t pid;
void *addr, *data;
va_list ap;
va_start(ap, __request);
pid = va_arg(ap, pid_t);
addr = va_arg(ap, void *);
data = va_arg(ap, void *);
va_end(ap);
if(__request == PTRACE_GETREGS)
{
return get_regs(pid, addr, data);
}
else if(__request == PTRACE_SETREGS)
{
return set_regs(pid, addr, data);
}
#if 0
//some old system may require this command to get register
else if(__request == PTRACE_PEEKUSER)
{
}
#endif
else if(__request == PTRACE_GETFPREGS)
{
return get_fpregs(pid, addr, data, FALSE);
}
else if(__request == PTRACE_SETFPREGS)
{
return set_fpregs(pid, addr, data, FALSE);
}
else if(__request == PTRACE_GETFPXREGS)
{
return get_fpregs(pid, addr, data, TRUE);
}
else if(__request == PTRACE_SETFPXREGS)
{
return set_fpregs(pid, addr, data, TRUE);
}
//xstave for avx
else if(__request == PTRACE_GETREGSET)
{
return get_regset(pid, addr, data);
}
else if(__request == PTRACE_SETREGSET)
{
return set_regset(pid, addr, data);
}
//For other request just forward it to real ptrace call;
return g_sys_ptrace(__request, pid, addr, data);
}