Skip to content

Commit

Permalink
[PAL/Linux-SGX] Disallow memfault handling with no faulting address r…
Browse files Browse the repository at this point in the history
…eported

Previously, Linux-SGX PAL propagated the memory fault exception with
address 0 anyway to LibOS/app even if no faulting address was actually
reported by SGX. This could happen when `sgx.use_exinfo` is disabled in
the manifest or the environment does not support EXINFO at all. However,
LibOS can't/shouldn't handle such case for security reasons.

This commit adds a check on whether the faulting address is reported
before handling a memory fault and we loudly fail if it's not.

Signed-off-by: Kailun Qin <kailun.qin@intel.com>
  • Loading branch information
kailun-qin committed Sep 18, 2023
1 parent b6fc88d commit 9f80c42
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 29 deletions.
46 changes: 27 additions & 19 deletions pal/regression/Exception.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,18 @@ static void handler2(bool is_in_pal, uintptr_t addr, PAL_CONTEXT* context) {
context->rip++;
}

static void handler3(bool is_in_pal, uintptr_t addr, PAL_CONTEXT* context) {
__UNUSED(is_in_pal);

pal_printf("Memory Fault Exception Handler: 0x%08lx, rip = 0x%08lx\n", addr, context->rip);
atomic_bool handler3_called = false;

while (*(unsigned char*)context->rip != 0x90)
context->rip++;
}

atomic_bool handler4_called = false;

static void handler4(bool is_in_pal, uintptr_t addr, PAL_CONTEXT* context) {
static void handler3(bool is_in_pal, uintptr_t addr, PAL_CONTEXT* context) {
__UNUSED(is_in_pal);

pal_printf("Arithmetic Exception Handler 4: 0x%" PRIx64 ", rip = 0x%" PRIx64 "\n", addr,
pal_printf("Arithmetic Exception Handler 3: 0x%" PRIx64 ", rip = 0x%" PRIx64 "\n", addr,
context->rip);

while (*(unsigned char*)context->rip != 0x90)
context->rip++;

handler4_called = true;
handler3_called = true;
}

static void red_zone_test(void) {
Expand Down Expand Up @@ -94,7 +85,7 @@ static void red_zone_test(void) {
:
: "rax", "rbx", "rcx", "rdx", "cc", "memory");

if (!handler4_called) {
if (!handler3_called) {
pal_printf("Exception handler was not called!\n");
return;
}
Expand All @@ -107,6 +98,20 @@ static void red_zone_test(void) {
pal_printf("Red zone test ok.\n");
}

#define INVALID_ADDR 0x1000

static void handler4(bool is_in_pal, uintptr_t addr, PAL_CONTEXT* context) {
__UNUSED(is_in_pal);

pal_printf("Memory Fault Exception Handler: 0x%08lx, rip = 0x%08lx\n", addr, context->rip);

if (addr != INVALID_ADDR)
pal_printf("Wrong faulting address: expected: 0x%08x, got: 0x%08lx\n", INVALID_ADDR, addr);

while (*(unsigned char*)context->rip != 0x90)
context->rip++;
}

int main(void) {
pal_printf("Stack in main: %p\n", get_stack());

Expand All @@ -128,12 +133,15 @@ int main(void) {
"nop\n"
::: "rax", "rbx", "rdx", "cc");

PalSetExceptionHandler(handler3, PAL_EVENT_MEMFAULT);
*(volatile long*)0x1000 = 0;
__asm__ volatile("nop");

PalSetExceptionHandler(handler4, PAL_EVENT_ARITHMETIC_ERROR);
PalSetExceptionHandler(handler3, PAL_EVENT_ARITHMETIC_ERROR);
red_zone_test();

/* For Gramine-SGX, memory fault exception handling test will error out and fail on machines
* that do not support EXINFO. We thus put it as the last test so that we could still check on
* the other tests in such case. */
PalSetExceptionHandler(handler4, PAL_EVENT_MEMFAULT);
*(volatile long*)INVALID_ADDR = 0;
__asm__ volatile("nop");

return 0;
}
3 changes: 3 additions & 0 deletions pal/regression/manifest.template
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ loader.insecure__use_cmdline_argv = true
sgx.debug = true
sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }}

# for Exception test (memfault handler)
sgx.use_exinfo = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }}

sgx.allowed_files = [
"file:test.txt", # for File2 test
"file:to_send.tmp", # for PalSendHandle test
Expand Down
26 changes: 16 additions & 10 deletions pal/regression/test_pal.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,26 +203,32 @@ def is_altstack_different_from_main_stack(self, output):

@unittest.skipUnless(ON_X86, "x86-specific")
def test_000_exception(self):
_, stderr = self.run_binary(['Exception'])
try:
_, stderr = self.run_binary(['Exception'])
if HAS_SGX and not HAS_EDMM:
self.fail('expected to return nonzero')
except subprocess.CalledProcessError as e:
if HAS_SGX and not HAS_EDMM:
self.assertNotEqual(e.returncode, 0)
stderr = e.stderr.decode()
else:
self.fail('expected to return zero')

self.assertTrue(self.is_altstack_different_from_main_stack(stderr))

# Exception Handling (Div-by-Zero)
self.assertIn('Arithmetic Exception Handler', stderr)

# Exception Handling (Memory Fault)
self.assertIn('Memory Fault Exception Handler', stderr)

# Exception Handler Swap
self.assertIn('Arithmetic Exception Handler 1', stderr)
self.assertIn('Arithmetic Exception Handler 2', stderr)

# Exception Handling (Set Context)
self.assertIn('Arithmetic Exception Handler 1', stderr)

# Exception Handling (Red zone)
self.assertIn('Arithmetic Exception Handler 3', stderr)
self.assertIn('Red zone test ok.', stderr)

if not HAS_SGX or HAS_EDMM:
# Exception Handling (Memory Fault)
self.assertIn('Memory Fault Exception Handler', stderr)
self.assertNotIn('Wrong faulting address', stderr)

class TC_20_SingleProcess(RegressionTestCase):
def test_000_exit_code(self):
with self.expect_returncode(112):
Expand Down
8 changes: 8 additions & 0 deletions pal/src/host/linux-sgx/pal_exception.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ void _PalExceptionHandler(unsigned int exit_info, sgx_cpu_context_t* uc,
PAL_CONTEXT ctx = { 0 };
save_pal_context(&ctx, uc, xregs_state);

bool has_hw_fault_address = false;

if (ei.info.valid) {
ctx.trapno = ei.info.vector;
/* Only these two exceptions save information in EXINFO. */
Expand All @@ -312,6 +314,7 @@ void _PalExceptionHandler(unsigned int exit_info, sgx_cpu_context_t* uc,
}
if (ei.info.vector == SGX_EXCEPTION_VECTOR_PF) {
ctx.cr2 = exinfo->maddr;
has_hw_fault_address = true;
}
}

Expand All @@ -321,6 +324,11 @@ void _PalExceptionHandler(unsigned int exit_info, sgx_cpu_context_t* uc,
addr = uc->rip;
break;
case PAL_EVENT_MEMFAULT:
if (!has_hw_fault_address) {
log_error("Tried to handle a memory fault with no faulting address reported by "
"SGX. Please consider enabling 'sgx.use_exinfo' in the manifest.");
_PalProcessExit(1);
}
addr = ctx.cr2;
break;
default:
Expand Down

0 comments on commit 9f80c42

Please sign in to comment.