Skip to content
This repository has been archived by the owner on Jan 20, 2022. It is now read-only.

Segfault in enclave. #1748

Closed
Arslan8 opened this issue Aug 6, 2020 · 14 comments
Closed

Segfault in enclave. #1748

Arslan8 opened this issue Aug 6, 2020 · 14 comments
Assignees

Comments

@Arslan8
Copy link

Arslan8 commented Aug 6, 2020

Hi,
While doing generation based fuzzing on existing SGX programs, we saw that graphene-sgx enclave doesn't do proper NULL checking.

Description of the problem

Steps to reproduce

This generated code triggers the NULL access:
/*[[[cog import cog filename = "./temp" with open(filename) as f: for line in f.readlines(): cog.outl(line) ]]]*/ ret = ecall_enclave_start(NULL, 100, NULL, 100); if (ret != 0) printf("Failure Code: %d",ret); //[[[end]]]

Expected results

Since the enclave is expecting the arguments from untrusted runtime, this should result in invalid argument return value.

Actual results

Segmentation fault inside Enclave.

@mkow mkow self-assigned this Aug 6, 2020
@mkow
Copy link
Member

mkow commented Aug 6, 2020

I can't reproduce this issue. Are you sure you're running on an up-to-date version of Graphene?
For me such invocation prints Creating arguments failed and just exits.

@Arslan8
Copy link
Author

Arslan8 commented Aug 6, 2020

Hi @mkow, this is for Graphene-SGX... This was reproduced on the latest release tag: v1.0.1. I was unable to build head revision. Here's the backtrace i saw:

#0 _wordcopy_fwd_aligned (dstp=35361801776, srcp=0, len=12) at string/wordcopy.c:47
#1 0x000000083bb87df5 in memcpy (dstpp=0x83bba4630 <mem_pool+848>, srcpp=<optimized out>, len=100)
  at string/memcpy.c:41
#2 0x000000083bb82f15 in sgx_copy_to_enclave (ptr=ptr@entry=0x83bba4630 <mem_pool+848>, maxsize=maxsize@entry=100,
  uptr=uptr@entry=0x0, usize=usize@entry=100) at enclave_framework.c:89
#3 0x000000083bb7eb11 in make_argv_list (uptr_src=0x0, src_size=100) at db_main.c:164
#4 0x000000083bb7f3b3 in pal_linux_main (uptr_args=0x0, args_size=<optimized out>, uptr_env=0x0,
  env_size=<optimized out>, uptr_sec_info=<optimized out>) at db_main.c:329
#5 0x000000083bb8718c in enclave_entry () at enclave_entry.S:111
#6 0x0000000000000000 in ?? ()

@mkow
Copy link
Member

mkow commented Aug 6, 2020

Please test this on the current master, this bug was probably already fixed. v1.0.1 is 8 months old...

I was unable to build head revision.

Why?

@Arslan8
Copy link
Author

Arslan8 commented Aug 6, 2020

IIRC there were some compilation errors on the particular revision I checked out so instinctively I went to the latest release...anyhow let me try to run it on current head too.

@dimakuv
Copy link

dimakuv commented Aug 6, 2020

@Arslan8 That could be due to SGX SDK installing its own versions of ld, ar and so on. Check this: #1685.

@Arslan8
Copy link
Author

Arslan8 commented Aug 6, 2020

@dimakuv thanks for the pointer.. yeah I remember for Intel SGX-SSL I had to update those tools... I'll give it a try later tonight..

@mkow
Copy link
Member

mkow commented Sep 11, 2020

@Arslan8 Any updates on this?

@Arslan8
Copy link
Author

Arslan8 commented Sep 14, 2020

@mkow sorry for such a late response.. i got caught up with a deadline.. I was able to build v1.1 as well, the issue is still there:

arslan@arslan-OptiPlex-5050:~/Documents/graphene-head/graphene/Examples/bash$ /home/arslan/Documents/graphene-head/graphene/Runtime/pal-Linux-SGX init ./bash.manifest
Manifest file: file:bash.manifest.sgx
Inferred executable file: file:./bash
Token file: file:bash.token

ls

ls
Manifest file: file:bash.manifest.sgx
Inferred executable file: file:./bash
Token file: file:bash.token
Read token:
    valid:                 0x00000001
    attr.flags:            0x0000000000000006
    attr.xfrm:             0x000000000000001f
    mr_enclave:            28dfe6d1ccd9f29223dcb1b858d2fd0298a56d9e0a9f095ed2da4548e8c393a2
    mr_signer:             2a16e22070d9f9dcd20f344872b9a56a9b97f26caeaeb3e5cc00e94f1ef57b77
    LE cpu_svn:            05100204010200000000000000000000
    LE isv_prod_id:        20
    LE isv_svn:            05
    LE masked_misc_select: 0x00000000
    LE attr.flags:         0x0000000000000021
    LE attr.xfrm:          0x0000000000000000
enclave created:
    base:           0x0000000800000000
    size:           0x0000000010000000
    misc_select:    0x00000000
    attr.flags:     0x0000000000000007
    attr.xfrm:      0x000000000000001f
    ssa_frame_size: 1
    isv_prod_id:    0x00000000
    isv_svn:        0x00000000
adding pages to enclave: 0xfffe000-0x10000000 [REG:R--] (manifest) measured
adding pages to enclave: 0xfff6000-0xfffe000 [REG:RW-] (ssa) measured
adding pages to enclave: 0xfff2000-0xfff6000 [TCS:---] (tcs) measured
adding pages to enclave: 0xffee000-0xfff2000 [REG:RW-] (tls) measured
adding pages to enclave: 0xffae000-0xffee000 [REG:RW-] (stack) measured
adding pages to enclave: 0xff6e000-0xffae000 [REG:RW-] (stack) measured
adding pages to enclave: 0xff2e000-0xff6e000 [REG:RW-] (stack) measured
adding pages to enclave: 0xfeee000-0xff2e000 [REG:RW-] (stack) measured
adding pages to enclave: 0xfede000-0xfeee000 [REG:RW-] (sig_stack) measured
adding pages to enclave: 0xfece000-0xfede000 [REG:RW-] (sig_stack) measured
adding pages to enclave: 0xfebe000-0xfece000 [REG:RW-] (sig_stack) measured
adding pages to enclave: 0xfeae000-0xfebe000 [REG:RW-] (sig_stack) measured
adding pages to enclave: 0xba76000-0xbad6000 [REG:R-X] (code) measured
adding pages to enclave: 0xbad6000-0xbad9000 [REG:RW-] (data) measured
adding pages to enclave: 0xbad9000-0xfeae000 [REG:RW-] (bss) measured
adding pages to enclave: 0xb75c000-0xb860000 [REG:RWX] (code) measured
adding pages to enclave: 0xba5f000-0xba6c000 [REG:RW-] (data) measured
adding pages to enclave: 0xba6c000-0xba76000 [REG:RW-] (bss) measured
adding pages to enclave: 0x0-0xb75c000 [REG:RWX] (free)
enclave initializing:
    enclave id:   0x000000080ffff000
    mr_enclave:   28dfe6d1ccd9f29223dcb1b858d2fd0298a56d9e0a9f095ed2da4548e8c393a2
Seal key: 392b1069a257db56cc8820c0cd7f1324
ls
^C

i yet have to debug it, but the behavior looks similar..

@Arslan8
Copy link
Author

Arslan8 commented Sep 14, 2020

also as you can see there is no "Creating arguments failed" print.. is there maybe a log file where i could find this print?

@Arslan8
Copy link
Author

Arslan8 commented Sep 14, 2020

Here's the backtrace:

Program received signal SIGSEGV, Segmentation fault.
0x000000080baa551f in memcpy (dst=0x80bad8bd0 <g_mem_pool+848>, src=0x0, n=100) at string/memcpy.c:29
29	    __asm__ volatile("rep movsb" : "+D" (d) : "c"(n), "S"(src) : "cc", "memory");
(gdb) bt
#0  0x000000080baa551f in memcpy (dst=0x80bad8bd0 <g_mem_pool+848>, src=0x0, n=100) at string/memcpy.c:29
#1  0x000000080ba90994 in sgx_copy_to_enclave (ptr=0x80bad8bd0 <g_mem_pool+848>, maxsize=100, uptr=0x0, usize=100)
    at enclave_framework.c:106
#2  0x000000080ba864ba in make_argv_list (uptr_src=0x0, src_size=100) at db_main.c:143
#3  0x000000080ba87178 in pal_linux_main (uptr_args=0x0, args_size=100, uptr_env=0x0, env_size=100, 
    uptr_sec_info=0x55c44514c5c0 <pal_enclave+64>) at db_main.c:317
#4  0x000000080baa0800 in handle_ecall (ecall_index=0, ecall_args=0x7fff311377e0, exit_target=0x55c44513f4ea <sgx_raise+9>, 
    enclave_base_addr=0x800000000) at enclave_ecalls.c:101
#5  0x000000080baa00b1 in enclave_entry ()
#6  0x000000080ffee000 in ?? ()
#7  0x0000000000000000 in ?? ()

@Arslan8
Copy link
Author

Arslan8 commented Sep 14, 2020

Here's what i see on master:

#0  0x000000080baa5ab3 in memcpy (dest=0x80bad8bd0 <g_mem_pool+848>, src=0x0, count=100) at string/memcpy.c:18
#1  0x000000080ba90d35 in sgx_copy_to_enclave (ptr=0x80bad8bd0 <g_mem_pool+848>, maxsize=100, uptr=0x0, usize=100)
    at enclave_framework.c:97
#2  0x000000080ba866c5 in make_argv_list (uptr_src=0x0, src_size=100) at db_main.c:144
#3  0x000000080ba8738c in pal_linux_main (
    uptr_libpal_uri=0x560554ef08b5 "/home/arslan/Documents/graphene-head/graphene/Pal/src/host/Linux-SGX/libpal.so", 
    libpal_uri_len=78, uptr_args=0x0, args_size=100, uptr_env=0x0, env_size=100, uptr_sec_info=0x560554653608 <g_pal_enclave+72>)
    at db_main.c:321
#4  0x000000080baa0d88 in handle_ecall (ecall_index=0, ecall_args=0x7ffe2eb4f510, exit_target=0x560554646888 <sgx_raise+9>, 
    enclave_base_addr=0x800000000) at enclave_ecalls.c:115
#5  0x000000080baa0415 in enclave_entry ()
#6  0x000000080ffee000 in ?? ()
#7  0x0000000000000000 in ?? ()

Here the function prototype is changed, instead of running the fuzzer again, i just remain the new argument unchanged. I can run the fuzzer later when i get some time..but looks like its present on both the latest tag/release and master...
Here's the modified call, if you can't find it in the backtrace...

ecall_enclave_start(enclave->libpal_uri, NULL, 100, NULL, 100);

let me know if anything else is required from my side.. again sorry for such a long delay..

@mkow
Copy link
Member

mkow commented Sep 14, 2020

I was able to build v1.1 as well, the issue is still there:

Please use the current master, v1.1 is 2 months old and the results on it are probably meaningless, it's almost 100 commits old ;)

also as you can see there is no "Creating arguments failed" print.. is there maybe a log file where i could find this print?

here you go: https://github.com/oscarlab/graphene/blob/34b8eb1ec2b23d5538d8ede385eb1be50e29354d/Pal/src/host/Linux-SGX/db_main.c#L321-L325
Just use the up-to-date master ;)

Here the function prototype is changed, instead of running the fuzzer again, i just remain the new argument unchanged. I can run the fuzzer later when i get some time..but looks like its present on both the latest tag/release and master...

I verified the code and I think it's working as intended. In general, we can't verify if a pointer provided by untrusted runtime is valid or not, at least not without abusing hardware extensions like TSX. The only thing you can do in enclave is to dereference it and see what happens. And NULL isn't really a special value here - just an address which does not point to a readable memory.

Anyways, I don't think there's any security issue with implementing it this way, if you think otherwise then please explain why this may be a problem.

again sorry for such a long delay..

No worries :)

@Arslan8
Copy link
Author

Arslan8 commented Sep 14, 2020

Yeah, we agree that in general verifying a pointer is a hard problem. But a wild dereference in enclave could have adverse effects since that dereference is not protected by hardware memory protection constraints. In contrast what some projects (e.g. Intel SDK) do is that they glue the call with an untrusted lib, which does the dereferencing outside the enclave, while this would still crash the application, but the crash would be contained within the constraints of untrusted memory protections, i.e. it won't be able to access any enclave memory. On the other side, enclaves can use sgx_is_within_enclave to check things. Contact Discovery Enclave is a good example of this.

@mkow
Copy link
Member

mkow commented Sep 14, 2020

Yeah, we agree that in general verifying a pointer is a hard problem.

But not too hard, you can solve this with TSX. What I mean is that it's IMO not worth solving, because there's no gain from solving this issue.

But a wild dereference in enclave could have adverse effects since that dereference is not protected by hardware memory protection constraints.

What adverse effects? It's still protected by the standard x86 memory protection rules, plus we don't allow it to point inside the enclave (see sgx_copy_to_enclave()).

In contrast what some projects (e.g. Intel SDK) do is that they glue the call with an untrusted lib, which does the dereferencing outside the enclave, while this would still crash the application, but

If I understand you correctly, that would require us to jump out of enclave for every read, which would really trash the performance. And just to reiterate, maybe I'm missing something, but I don't see any security issues with our current approach.

the crash would be contained within the constraints of untrusted memory protections, i.e. it won't be able to access any enclave memory.

You can't access enclave memory this way, see sgx_copy_to_enclave() implementation.

On the other side, enclaves can use sgx_is_within_enclave to check things. Contact Discovery Enclave is a good example of this.

sgx_copy_to_enclave() uses our own analogues: sgx_is_completely_within_enclave() and sgx_is_completely_outside_enclave(). Have you read the implementation?

@mkow mkow closed this as completed Sep 24, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants