470 likes | 482 Views
Shreds: Fine-grained Execution Units with Private Memory. Landon Cox February 21, 2018. Parts of a process. Threads Sequences of executing instructions Active: do things Address space Data the process uses as it runs Passive: acted upon by threads File descriptors
E N D
Shreds: Fine-grained Execution Units with Private Memory Landon Cox February 21, 2018
Parts of a process • Threads • Sequences of executing instructions • Active: do things • Address space • Data the process uses as it runs • Passive: acted upon by threads • File descriptors • Communication channels (e.g., files, sockets, pipes) • Passive: read-from/written-to by threads
Parts of a process Process Thread 1 Thread 2 File descriptors Page table Stack 1 Stack 2 Readable pages Writable pages TCP socket Open file Each thread has its own stack, but everything else is share: same pages, file descriptors
Parts of a process Threads are not well isolated from each other. Process Thread 1 Thread 2 File descriptors Page table Stack 1 Stack 2 Readable pages Writable pages TCP socket Open file Threads can run in parallel on different cores.
Parts of a process (revised) Process Thread 1 Thread 2 File descriptors Page table Stack 1 Stack 2 Readable pages Writable pages TCP socket Open file If one thread fails, entire process fails.
Parts of a process (revised) Process Thread 2 File descriptors Page table Stack 1 Stack 2 Readable pages Writable pages TCP socket Open file Compromising a thread, compromises all data.
Parts of a process (revised) Thread 2 Stack 1 Stack 2 Readable pages Writable pages TCP socket Open file Compromising a thread, compromises all data.
Parts of a process (revised) Thread 2 Stack 1 Stack 2 Readable pages Writable pages TCP socket Open file See: heartbleed, cloudbleed, etc.
Threads vs shreds • How do you define a thread’s work? • Pass in a starting method • The thread exits when the starting function exits • What part of the address space can a thread access? • A thread can access any read- or write-enabled page • All threads are bound by the same protections • A shred’s work can be more or less than a method • Enter a shred using: shred_enter • Exit a shred using: shred_exit • A shred can access secrets in a private memory pool (s-pool)
Shred protection guarantees • Exclusive access to an s-pool • Only associated shreds can access data in an s-pool • Other threads, unassociated shreds cannot access • No leaks • S-pool data cannot be copied w/o sanitization • Use static analysis to identify outgoing data flows • Untampered execution • Shred code cannot be changed or routed elsewhere • i.e., control-flow integrity w/i shred (including libs) S-driver S-compiler
Shred protection guarantees • Exclusive access to an s-pool • Only associated shreds can access data in an s-pool • Other threads, unassociated shreds cannot access S-driver
S-driver • ARM memory domains • Provide memory-access control independent of page protections • 4-bit tags specified in top-level page tables • Access level for each domain set via per-core register (DACR) • MMU checks domain access for virtual memory address • Three access levels specified in DACR • No-access mode: all accesses to domain memory fail • Manager mode: all access to domain memory are allowed • Client mode: all accesses obey page protections
Two-level table 4-bit flag in top-level entry 0 1 … ? 1023 Level 1 Domain 0 Domain 0 Domain 0 NULL NULL Level 2 0: PhysPage, Res, Prot 0: PhysPage, Res, Prot 1: PhysPage, Res, Prot 1: PhysPage, Res, Prot … … 1023: PhysPage, Res, Prot ? 1023: PhysPage, Res, Prot ?
Two-level table All memory under domain 0 0 1 … ? 1023 Level 1 Domain 0 Domain 0 Domain 0 NULL NULL Level 2 0: PhysPage, Res, Prot 0: PhysPage, Res, Prot 1: PhysPage, Res, Prot 1: PhysPage, Res, Prot … … 1023: PhysPage, Res, Prot ? 1023: PhysPage, Res, Prot ?
Two-level table Top 4MB now in domain 1 0 1 … ? 1023 Level 1 Domain 0 Domain 1 Domain 0 NULL NULL Level 2 0: PhysPage, Res, Prot 0: PhysPage, Res, Prot 1: PhysPage, Res, Prot 1: PhysPage, Res, Prot … … 1023: PhysPage, Res, Prot ? 1023: PhysPage, Res, Prot ?
Two-level table Can put other regions under other domains 0 1 … ? 1023 Level 1 Domain 0 Domain 1 Domain 2 NULL NULL Level 2 0: PhysPage, Res, Prot 0: PhysPage, Res, Prot 1: PhysPage, Res, Prot 1: PhysPage, Res, Prot … … 1023: PhysPage, Res, Prot ? 1023: PhysPage, Res, Prot ?
Two-level table 0 1 … ? 1023 Level 1 Domain 0 Domain 1 Domain 2 NULL NULL Level 2 0: PhysPage, Res, Prot 0: PhysPage, Res, Prot 1: PhysPage, Res, Prot 1: PhysPage, Res, Prot … … 1023: PhysPage, Res, Prot ? 1023: PhysPage, Res, Prot ? Each core has a 32-bit DACR
Two-level table 0 1 … ? 1023 Level 1 Domain 0 Domain 1 Domain 2 NULL NULL Level 2 0: PhysPage, Res, Prot 0: PhysPage, Res, Prot 1: PhysPage, Res, Prot 1: PhysPage, Res, Prot … … 1023: PhysPage, Res, Prot ? 1023: PhysPage, Res, Prot ? 16 domains x 2 mode bits
Two-level table 0 1 … ? 1023 Level 1 Domain 0 Domain 1 Domain 2 NULL NULL Level 2 0: PhysPage, Res, Prot 0: PhysPage, Res, Prot 1: PhysPage, Res, Prot 1: PhysPage, Res, Prot … … 1023: PhysPage, Res, Prot ? 1023: PhysPage, Res, Prot ? Mode bits encode client, no-access, manager modes
Two-level table 0 1 … ? 1023 Level 1 Domain 0 Domain 1 Domain 2 NULL NULL Level 2 0: PhysPage, Res, Prot 0: PhysPage, Res, Prot 1: PhysPage, Res, Prot 1: PhysPage, Res, Prot … … 1023: PhysPage, Res, Prot ? 1023: PhysPage, Res, Prot ? Note changing DACR does not require TLB flush!
Two-level table 0 1 … ? 1023 Level 1 Domain 0 Domain 1 Domain 2 NULL NULL Level 2 0: PhysPage, Res, Prot 0: PhysPage, Res, Prot 1: PhysPage, Res, Prot 1: PhysPage, Res, Prot … … 1023: PhysPage, Res, Prot ? 1023: PhysPage, Res, Prot ? Mode change should be faster than page change
Two-level table Problem with only 16 domains? 0 1 … ? 1023 Level 1 Domain 0 Domain 1 Domain 2 NULL NULL Level 2 0: PhysPage, Res, Prot 0: PhysPage, Res, Prot 1: PhysPage, Res, Prot 1: PhysPage, Res, Prot … … 1023: PhysPage, Res, Prot ? 1023: PhysPage, Res, Prot ?
Linux Page permissions Unused No access 15 14 … 10 9 8 7 6 5 4 3 2 1 0 Every s-pool is assigned a memory domain (e.g., 3-7)
Linux Page permissions Unused No access 15 14 … 10 9 8 7 6 5 4 3 2 1 0 Assignments change depending on if shred is active and on which core.
Linux Page permissions Unused No access 15 14 … 10 9 8 7 6 5 4 3 2 1 0 Each core gets an exclusive domain
15 14 … 10 9 8 7 6 5 4 3 2 1 0 All inactive shreds’ s-pools are tagged w/ red domain. While shred is active on core, its s-pool is tagged w/ core’s green domain.
Say we load shred 0 onto core 0. 15 14 … 10 9 8 7 6 5 4 3 2 1 0 S0
Which domain does S0’s s-pool need to be tagged with? 15 14 … 10 9 8 7 6 5 4 3 2 1 0 S0
Why will S0 be able to access its s-pool? 15 14 … 10 9 8 7 6 5 4 3 2 1 0 S0
Why can’t other shreds access S0’s s-pool? 15 14 … 10 9 8 7 6 5 4 3 2 1 0 S0
Can S0 run in parallel on > 1 core? 15 14 … 10 9 8 7 6 5 4 3 2 1 0 S0
How do we tag S0’s s-pool when it’s done? Why? 15 14 … 10 9 8 7 6 5 4 3 2 1 0 S0
What happens to the TLB on when an s-pool’s tag changes? 15 14 … 10 9 8 7 6 5 4 3 2 1 0 S0
Where does a shred’s stack have to reside? Why? 15 14 … 10 9 8 7 6 5 4 3 2 1 0 S0
inthttp_request_parse(server *srv, connection *con) { … /* inside the request parsing loop */ char *cur; /* current parsing offset */ char auth_str[] = "Authorization"; intauth_str_len = strlen(auth_str); if (strncmp(cur, auth_str, auth_str_len)==0){ shred_enter(AUTH_PASSWD_POOL); /* object holding passwd in spool */ data_string *ds = s_ds_init(); intpw_len = get_passwd_length(cur); cur += auth_str_len + 1; buffer_copy_string_len(ds->key, auth_str, auth_str_len); buffer_copy_string_len(ds->value, cur, pw_len); /* add ds to header pointer array */ array_insert_unique(parsed_headers, ds); /* only related shreds can deref ds */ /* wipe out passwd from input stream */ memset(cur, 0, pw_len); cur += pw_len; shred_exit(); } … }
inthttp_request_parse(server *srv, connection *con) { … /* inside the request parsing loop */ char *cur; /* current parsing offset */ char auth_str[] = "Authorization"; intauth_str_len = strlen(auth_str); if (strncmp(cur, auth_str, auth_str_len)==0){ shred_enter(AUTH_PASSWD_POOL); /* object holding passwd in spool */ data_string *ds = s_ds_init(); intpw_len = get_passwd_length(cur); cur += auth_str_len + 1; buffer_copy_string_len(ds->key, auth_str, auth_str_len); buffer_copy_string_len(ds->value, cur, pw_len); /* add ds to header pointer array */ array_insert_unique(parsed_headers, ds); /* only related shreds can deref ds */ /* wipe out passwd from input stream */ memset(cur, 0, pw_len); cur += pw_len; shred_exit(); } … } Parse authorization request.
inthttp_request_parse(server *srv, connection *con) { … /* inside the request parsing loop */ char *cur; /* current parsing offset */ char auth_str[] = "Authorization"; intauth_str_len = strlen(auth_str); if (strncmp(cur, auth_str, auth_str_len)==0){ shred_enter(AUTH_PASSWD_POOL); /* object holding passwd in spool */ data_string *ds = s_ds_init(); intpw_len = get_passwd_length(cur); cur += auth_str_len + 1; buffer_copy_string_len(ds->key, auth_str, auth_str_len); buffer_copy_string_len(ds->value, cur, pw_len); /* add ds to header pointer array */ array_insert_unique(parsed_headers, ds); /* only related shreds can deref ds */ /* wipe out passwd from input stream */ memset(cur, 0, pw_len); cur += pw_len; shred_exit(); } … } Enter authorization shred.
inthttp_request_parse(server *srv, connection *con) { … /* inside the request parsing loop */ char *cur; /* current parsing offset */ char auth_str[] = "Authorization"; intauth_str_len = strlen(auth_str); if (strncmp(cur, auth_str, auth_str_len)==0){ shred_enter(AUTH_PASSWD_POOL); /* object holding passwd in spool */ data_string *ds = s_ds_init(); intpw_len = get_passwd_length(cur); cur += auth_str_len + 1; buffer_copy_string_len(ds->key, auth_str, auth_str_len); buffer_copy_string_len(ds->value, cur, pw_len); /* add ds to header pointer array */ array_insert_unique(parsed_headers, ds); /* only related shreds can deref ds */ /* wipe out passwd from input stream */ memset(cur, 0, pw_len); cur += pw_len; shred_exit(); } … } Allocate a new string in the s-pool.
inthttp_request_parse(server *srv, connection *con) { … /* inside the request parsing loop */ char *cur; /* current parsing offset */ char auth_str[] = "Authorization"; intauth_str_len = strlen(auth_str); if (strncmp(cur, auth_str, auth_str_len)==0){ shred_enter(AUTH_PASSWD_POOL); /* object holding passwd in spool */ data_string *ds = s_ds_init(); intpw_len = get_passwd_length(cur); cur += auth_str_len + 1; buffer_copy_string_len(ds->key, auth_str, auth_str_len); buffer_copy_string_len(ds->value, cur, pw_len); /* add ds to header pointer array */ array_insert_unique(parsed_headers, ds); /* only related shreds can deref ds */ /* wipe out passwd from input stream */ memset(cur, 0, pw_len); cur += pw_len; shred_exit(); } … } Move input to the password data.
inthttp_request_parse(server *srv, connection *con) { … /* inside the request parsing loop */ char *cur; /* current parsing offset */ char auth_str[] = "Authorization"; intauth_str_len = strlen(auth_str); if (strncmp(cur, auth_str, auth_str_len)==0){ shred_enter(AUTH_PASSWD_POOL); /* object holding passwd in spool */ data_string *ds = s_ds_init(); intpw_len = get_passwd_length(cur); cur += auth_str_len + 1; buffer_copy_string_len(ds->key, auth_str, auth_str_len); buffer_copy_string_len(ds->value, cur, pw_len); /* add ds to header pointer array */ array_insert_unique(parsed_headers, ds); /* only related shreds can deref ds */ /* wipe out passwd from input stream */ memset(cur, 0, pw_len); cur += pw_len; shred_exit(); } … } Copy the password into the s-pool
inthttp_request_parse(server *srv, connection *con) { … /* inside the request parsing loop */ char *cur; /* current parsing offset */ char auth_str[] = "Authorization"; intauth_str_len = strlen(auth_str); if (strncmp(cur, auth_str, auth_str_len)==0){ shred_enter(AUTH_PASSWD_POOL); /* object holding passwd in spool */ data_string *ds = s_ds_init(); intpw_len = get_passwd_length(cur); cur += auth_str_len + 1; buffer_copy_string_len(ds->key, auth_str, auth_str_len); buffer_copy_string_len(ds->value, cur, pw_len); /* add ds to header pointer array */ array_insert_unique(parsed_headers, ds); /* only related shreds can deref ds */ /* wipe out passwd from input stream */ memset(cur, 0, pw_len); cur += pw_len; shred_exit(); } … } Mark the authorization header as parsed.
inthttp_request_parse(server *srv, connection *con) { … /* inside the request parsing loop */ char *cur; /* current parsing offset */ char auth_str[] = "Authorization"; intauth_str_len = strlen(auth_str); if (strncmp(cur, auth_str, auth_str_len)==0){ shred_enter(AUTH_PASSWD_POOL); /* object holding passwd in spool */ data_string *ds = s_ds_init(); intpw_len = get_passwd_length(cur); cur += auth_str_len + 1; buffer_copy_string_len(ds->key, auth_str, auth_str_len); buffer_copy_string_len(ds->value, cur, pw_len); /* add ds to header pointer array */ array_insert_unique(parsed_headers, ds); /* only related shreds can deref ds */ /* wipe out passwd from input stream */ memset(cur, 0, pw_len); cur += pw_len; shred_exit(); } … } Delete the password
inthttp_request_parse(server *srv, connection *con) { … /* inside the request parsing loop */ char *cur; /* current parsing offset */ char auth_str[] = "Authorization"; intauth_str_len = strlen(auth_str); if (strncmp(cur, auth_str, auth_str_len)==0){ shred_enter(AUTH_PASSWD_POOL); /* object holding passwd in spool */ data_string *ds = s_ds_init(); intpw_len = get_passwd_length(cur); cur += auth_str_len + 1; buffer_copy_string_len(ds->key, auth_str, auth_str_len); buffer_copy_string_len(ds->value, cur, pw_len); /* add ds to header pointer array */ array_insert_unique(parsed_headers, ds); /* only related shreds can deref ds */ /* wipe out passwd from input stream */ memset(cur, 0, pw_len); cur += pw_len; shred_exit(); } … } Advance the input data.
inthttp_request_parse(server *srv, connection *con) { … /* inside the request parsing loop */ char *cur; /* current parsing offset */ char auth_str[] = "Authorization"; intauth_str_len = strlen(auth_str); if (strncmp(cur, auth_str, auth_str_len)==0){ shred_enter(AUTH_PASSWD_POOL); /* object holding passwd in spool */ data_string *ds = s_ds_init(); intpw_len = get_passwd_length(cur); cur += auth_str_len + 1; buffer_copy_string_len(ds->key, auth_str, auth_str_len); buffer_copy_string_len(ds->value, cur, pw_len); /* add ds to header pointer array */ array_insert_unique(parsed_headers, ds); /* only related shreds can deref ds */ /* wipe out passwd from input stream */ memset(cur, 0, pw_len); cur += pw_len; shred_exit(); } … } Exit the shred.
Switch performance • Comparing switch times • Shred exit • Intra-process thread switch • Process switch • How does this compare to lwCs? • Which approach is better? When?
Course administration • Mid-term exam • One week from today • Will cover everything through today • Project 2 • Will be released later today (due after the mid-term) • Research Project • Suggestions have been posted