Skip to content
Merged
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
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
app
devmem2
*.vcd
8 changes: 8 additions & 0 deletions app/tracer/Enclave/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
asm_nop.S
encl
*.pem
*.a
*.s
*.so
*_u.*
*_t.*
108 changes: 108 additions & 0 deletions app/tracer/Enclave/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
CC = gcc
AR = ar
LD = gcc
EDGER = sgx_edger8r
SIGNER = sgx_sign
INCLUDE = -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc
T_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g -Os
U_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g
AR_FLAGS = rcs
OBJECTS = encl.o
LIB_SGX_TRTS = -lsgx_trts
LIB_SGX_TSERVICE = -lsgx_tservice

ifeq ($(M32), 1)
T_CFLAGS += -m32 -msse2 -DM32=1
U_CFLAGS += -m32 -msse2
LD_FLAGS = -m32
else
LIB_SUFX = 64
endif

ENCLAVE_LIBS = $(LIB_SGX_TRTS)
ENCLAVE_LIB_PARTS = -lsgx_tstdc -lsgx_tcrypto $(LIB_SGX_TSERVICE)
ENCLAVE = encl
PRIVATE_KEY = private_key.pem
PUBLIC_KEY = public_key.pem
KEY_SIZE = 3072
ENCLAVE_EDL = $(ENCLAVE).edl
ENCLAVE_CONFIG = $(ENCLAVE).config.xml
OUTPUT_T = $(ENCLAVE).so
OUTPUT_T_UNSIG = $(ENCLAVE).unsigned.so
OUTPUT_U = lib$(ENCLAVE)_proxy.a
LIB_DIRS = -L$(SGX_SDK)/lib$(LIB_SUFX)/
LD_FLAGS += -z noexecstack -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles \
-Wl,--whole-archive -Wl,--start-group $(ENCLAVE_LIBS) -Wl,--end-group \
-Wl,--no-whole-archive -Wl,--start-group $(ENCLAVE_LIB_PARTS) -Wl,--end-group \
-Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \
-Wl,-pie,-eenclave_entry -Wl,--export-dynamic \
-Wl,--defsym,__ImageBase=0
TRUSTED_OBJECTS = $(ENCLAVE)_t.o
UNTRUSTED_OBJECTS = $(ENCLAVE)_u.o
TRUSTED_CODE = $(ENCLAVE)_t.h $(ENCLAVE)_t.c
UNTRUSTED_CODE = $(ENCLAVE)_u.h $(ENCLAVE)_u.c

#.SILENT:
all: $(OUTPUT_T) $(OUTPUT_U)

$(OUTPUT_T) : $(TRUSTED_OBJECTS) $(OBJECTS) $(PRIVATE_KEY)
echo "$(INDENT)[LD] " $(OBJECTS) $(TRUSTED_OBJECTS) $(ENCLAVE_LIBS) $(ENCLAVE_LIBS_PARTS) $(OUTPUT_T_UNSIG)
$(LD) $(OBJECTS) $(TRUSTED_OBJECTS) $(LD_FLAGS) $(LIB_DIRS) -o $(OUTPUT_T_UNSIG)

echo "$(INDENT)[SGN]" $(OUTPUT_T_UNSIG)
$(SIGNER) sign -key $(PRIVATE_KEY) -enclave $(OUTPUT_T_UNSIG) -out $(OUTPUT_T) -config $(ENCLAVE_CONFIG) > /dev/null 2> /dev/null

$(OUTPUT_U) : $(UNTRUSTED_OBJECTS)
echo "$(INDENT)[AR] " $(OUTPUT_U)
$(AR) $(AR_FLAGS) $(OUTPUT_U) $(UNTRUSTED_OBJECTS)

%_t.o : $(subst .o,.c,$@) edger
echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(trusted edge)"
touch $(subst .o,.c,$@)
$(CC) -c $(INCLUDE) $(T_CFLAGS) $(subst .o,.c,$@)

%_u.o : $(subst .o,.c,$@) edger
echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(untrusted edge)"
touch $(subst .o,.c,$@)
$(CC) -c $(INCLUDE) $(U_CFLAGS) $(subst .o,.c,$@)

%.o : %.c edger
echo "$(INDENT)[CC] " $< "(core)"
$(CC) $(INCLUDE) $(T_CFLAGS) -c $<

%.o : %.S
echo "$(INDENT)[AS] " $< "(core)"
$(CC) $(INCLUDE) $(T_CFLAGS) -c $< -o $@

edger: $(ENCLAVE).edl
echo "$(INDENT)[GEN]" $(EDGER) $(ENCLAVE_EDL)
$(EDGER) $(ENCLAVE_EDL)

.PHONY: force_check
force_check:
true

.PHONY: scrub
scrub:
echo "$(INDENT)[RM] " $(PRIVATE_KEY) $(PUBLIC_KEY)
$(RM) $(PRIVATE_KEY) $(PUBLIC_KEY)

$(PRIVATE_KEY):
echo "$(INDENT)[GEN] $(PRIVATE_KEY) ($(KEY_SIZE) bits)"

# generate 3072 bit private RSA key
openssl genrsa -out $(PRIVATE_KEY) -3 $(KEY_SIZE)

echo "$(INDENT)[EXT] $(PUBLIC_KEY)"
# extract public key
openssl rsa -in $(PRIVATE_KEY) -pubout -out $(PUBLIC_KEY)

# sign enclave
#sgx_sign sign -key private_key.pem -enclave Enclave/encl.so -out encl.signed.so

.PHONY: clean
clean:
echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U)
$(RM) $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U)
echo "$(INDENT)[RM]" $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE)
$(RM) $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE)
25 changes: 25 additions & 0 deletions app/tracer/Enclave/encl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <stdint.h>
#include <string.h>

char __attribute__((aligned(0x1000))) page_a[4096];
char __attribute__((aligned(0x1000))) page_b[4096];

inline void __attribute__((always_inline)) mwrite(void *p)
{
asm volatile("movb $0, (%0)\n" : : "r"(p) :);
}

void dummy_enclave_fn(int s)
{
for ( int i = s; i > 0; i >>= 1)
{
if (i & 0x01)
{
mwrite(page_a);
}
else
{
mwrite(page_b);
}
}
}
10 changes: 10 additions & 0 deletions app/tracer/Enclave/encl.config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!-- Please refer to User's Guide for the explanation of each field -->
<EnclaveConfiguration>
<ProdID>0</ProdID>
<ISVSVN>0</ISVSVN>
<StackMaxSize>0x40000</StackMaxSize>
<HeapMaxSize>0x100000</HeapMaxSize>
<TCSNum>1</TCSNum>
<TCSPolicy>1</TCSPolicy>
<DisableDebug>0</DisableDebug>
</EnclaveConfiguration>
9 changes: 9 additions & 0 deletions app/tracer/Enclave/encl.edl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
enclave {

trusted {
public void dummy_enclave_fn( int s );
};

untrusted {
};
};
90 changes: 90 additions & 0 deletions app/tracer/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
LIBSGXSTEP_DIR = ../../
LIBSGXSTEP = $(LIBSGXSTEP_DIR)/libsgxstep
-include $(LIBSGXSTEP)/Makefile.config

ifeq ($(SGX_SDK),)
SGX_SDK = /opt/intel/sgxsdk
endif
export SGX_SDK
ifneq ($(SGX_SDK), /opt/intel/sgxsdk)
URTS_LD_LIBRARY_PATH = LD_LIBRARY_PATH=$(LIBSGXSTEP_DIR)/linux-sgx/psw/urts/linux
endif

ENCLAVE = Enclave
SUBDIRS = $(ENCLAVE) $(LIBSGXSTEP)

CC = gcc
AS = gcc
LD = gcc

ifeq ($(M32), 1)
ASFLAGS = -m32 -DM32=$(M32)
CFLAGS = -m32 -DM32=$(M32)
LDFLAGS = -m32
else
LIB_SUFX = 64
endif

CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \
-fno-common -Wno-attributes -g -D_GNU_SOURCE -O0
INCLUDE = -I$(SGX_SDK)/include/ -I$(LIBSGXSTEP_DIR)
LDFLAGS += -lsgx-step -lencl_proxy -lsgx_urts \
-lsgx_uae_service -pthread $(SUBDIRS:%=-L %) -L$(SGX_SDK)/lib$(LIB_SUFX)/ \
-L$(LIBSGXSTEP_DIR)/linux-sgx/psw/urts/linux -lelf

SOURCES = $(shell ls *.c)
OBJECTS = $(SOURCES:.c=.o)
OUTPUT = app

BUILDDIRS = $(SUBDIRS:%=build-%)
CLEANDIRS = $(SUBDIRS:%=clean-%)

ATTACK = 1
PARSE = nop
ifeq ($(STRLEN), 1)
ATTACK = 2
PARSE = strlen
endif
ifeq ($(ZIGZAG), 1)
ATTACK = 3
PARSE = zz
endif

ifeq ($(NUM),)
NUM = 100
endif
export NUM

CFLAGS += -DATTACK_SCENARIO=$(ATTACK) -DNUM_RUNS=$(NUM)

MAKEFLAGS += --silent

all: $(OUTPUT)

run: clean all
sudo $(URTS_LD_LIBRARY_PATH) ./app > out.txt
cat out.txt

$(OUTPUT): $(BUILDDIRS) $(OBJECTS)
echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT)
$(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT)

%.o : %.c
echo "$(INDENT)[CC] " $<
$(CC) $(CFLAGS) $(INCLUDE) -c $<

%.o : %.S
echo "$(INDENT)[AS] " $<
$(AS) $(ASFLAGS) $(INCLUDE) -c $< -o $@

clean: $(CLEANDIRS)
echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT)
rm -f $(OBJECTS) $(OUTPUT)

$(BUILDDIRS):
echo "$(INDENT)[===] $(@:build-%=%) [===]"
$(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" M32=$(M32) curr-dir=$(curr-dir)/$(@:build-%=%)

$(CLEANDIRS):
echo "$(INDENT)[===] $(@:clean-%=%) [===]"
$(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%)
113 changes: 113 additions & 0 deletions app/tracer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# SGX Tracer

A modular tracing framework for SGX enclave execution built on top of sgx-step. It allows fine-grained, per-step recording of enclave state including memory page access patterns, general purpose registers, and interrupt behavior.
Recorded data can be exported to the [Value Change Dump (VCD)](https://en.wikipedia.org/wiki/Value_change_dump) format for visualization in waveform viewers such as [GTKWave](http://gtkwave.sourceforge.net/).

---
## Modules

| Module | Enum | Description |
|--------|------|-------------|
| Page Tracker | `TRACK_PAGES` | Tracks access bit of specified enclave pages at each step |
| GPR Tracker | `TRACK_GPRS` | Records general purpose register values from the SSA GPRSGX region |
| IRQ Tracker | `TRACK_IRQ` | Records interrupt firing and timing information |

### Note
The `GPRS` capabilities of the tracer should only be used in *debug* enclaves and *not* production ones.

---

## API
### Initialization
To initialize the tracer use the following command:
```c
void sgx_tracer_init(sgx_tracer_t *t);
```
---
### Enabling Modules
#### Track everything for a set of modules
```c
void sgx_tracer_add_module(sgx_tracer_t *t, const track_type_t modules);
```

Enables the given modules and tracks all available items (all pages, all registers).

#### Track a specific module with specific items
```c
void sgx_tracer_init_mod(sgx_tracer_t *t, track_type_t opt, void *items, size_t num_of_items);
```

Enables a module but only tracks the specified items. Pass `NULL` for modules that do not require items (e.g. `TRACK_IRQ`).

---
### Per-Step Update
```c
void sgx_tracer_step(sgx_tracer_t *t);
```

Call this inside your SGX-Step interrupt handler to record the current state of all enabled modules. Each call advances the internal time step.
For the tracer to work properly this function call must be called when (with the help of sgx-step) a single step has been confidently performed.
This should be called within the user-defined AEP callback function.

---
### Exporting to VCD
```c
void sgx_tracer_vcd(sgx_tracer_t *t, const char *filename);
```

Open with GTKWave to visualize signal changes over time.

---
### Cleanup
```c
void sgx_tracer_destroy(sgx_tracer_t *t);
```

Frees all module state and allocated resources.

---

## Example Usage
### Track all GPRs + specific pages + IRQ
```c
sgx_tracer_t tracer;
sgx_tracer_init(&tracer);

void *pages[] = {code_adrs};
sgx_tracer_init_mod(&tracer, /*option=*/TRACK_PAGES, pages, /*num_of_pages=*/1);

sgx_tracer_add_module(&tracer, /*option=*/TRACK_GPRS | TRACK_IRQ);
```

### Track only a specific register

```c
sgx_tracer_t tracer;
sgx_tracer_init(&tracer);

enum gprsgx_offset regs[] = {RIP};
sgx_tracer_init_mod(&tracer, /*option=*/TRACK_GPRS, regs, /*num_of_regs=*/1);
```

### Export and cleanup
```c
sgx_tracer_vcd(&tracer, "trace.vcd");
sgx_tracer_destroy(&tracer);
```

---

## VCD Output
The generated `.vcd` file can be opened with GTKWave:

```bash
gtkwave trace.vcd
```

Signals are grouped by module. Each time step corresponds to one SGX-Step interrupt fired during enclave execution.

---

## GTKWave Visualization

![GTKWave Screenshot](page_access_pattern.png)
25 changes: 25 additions & 0 deletions app/tracer/example_trace.gtkw
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Thu May 21 18:19:44 2026
[*]
[dumpfile] "/home/panayiotis/Desktop/prs/sgx-step-tracer/app/tracer/trace.vcd"
[dumpfile_mtime] "Thu May 21 18:17:03 2026"
[dumpfile_size] 27928
[savefile] "/home/panayiotis/Desktop/prs/sgx-step-tracer/app/tracer/example_trace.gtkw"
[timestart] 24
[size] 1850 1016
[pos] -51 -51
*-1.308253 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] top.
[sst_width] 233
[signals_width] 102
[sst_expanded] 1
[sst_vpaned_height] 289
@4023
^>1 /home/panayiotis/Desktop/prs/sgx-step-tracer/tools/disasm/disasm
top.gprs_trace.RIP[63:0]
@28
top.page_trace.0x18000
top.page_trace.0x19000
[pattern_trace] 1
[pattern_trace] 0
Loading
Loading