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

Commit

Permalink
[Pal] Report all preloaded ranges to LibOS
Browse files Browse the repository at this point in the history
Previously PALs could only report a predefined set of preloaded memory
ranges ("vdso" and "manifest"). Now they could report an arbitrary array
of such ranges.
This commit also adds reporting of "vvar" range on Linux PAL.

Signed-off-by: Borys Popławski <[email protected]>
  • Loading branch information
boryspoplawski committed May 7, 2021
1 parent a7bd32b commit 30fbb8d
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 57 deletions.
51 changes: 21 additions & 30 deletions LibOS/shim/src/bookkeep/shim_vma.c
Original file line number Diff line number Diff line change
Expand Up @@ -524,36 +524,27 @@ static int _bkeep_initial_vma(struct shim_vma* new_vma) {
static void* g_aslr_addr_top = NULL;

int init_vma(void) {
struct shim_vma init_vmas[] = {
{.begin = 0}, // vma for creation of memory manager
{
.begin = (uintptr_t)&__load_address,
.end = (uintptr_t)ALLOC_ALIGN_UP_PTR(&__load_address_end),
.prot = PROT_NONE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS | VMA_INTERNAL,
.file = NULL,
.offset = 0,
.comment = "LibOS",
},
{
.begin = (uintptr_t)ALLOC_ALIGN_DOWN_PTR(g_pal_control->manifest_preload.start),
.end = (uintptr_t)ALLOC_ALIGN_UP_PTR(g_pal_control->manifest_preload.end),
.prot = PROT_NONE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS | VMA_INTERNAL,
.file = NULL,
.offset = 0,
.comment = "manifest",
},
{
.begin = (uintptr_t)ALLOC_ALIGN_DOWN_PTR(g_pal_control->vdso_preload.start),
.end = (uintptr_t)ALLOC_ALIGN_UP_PTR(g_pal_control->vdso_preload.end),
.prot = PROT_NONE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS | VMA_INTERNAL,
.file = NULL,
.offset = 0,
.comment = "vDSO",
},
};
struct shim_vma init_vmas[2 + g_pal_control->preloaded_ranges_len];

init_vmas[0].begin = 0; // vma for creation of memory manager

init_vmas[1].begin = (uintptr_t)&__load_address;
init_vmas[1].end = (uintptr_t)ALLOC_ALIGN_UP_PTR(&__load_address_end);
init_vmas[1].prot = PROT_NONE;
init_vmas[1].flags = MAP_PRIVATE | MAP_ANONYMOUS | VMA_INTERNAL;
init_vmas[1].file = NULL;
init_vmas[1].offset = 0;
copy_comment(&init_vmas[1], "LibOS");

for (size_t i = 0; i < g_pal_control->preloaded_ranges_len; i++) {
init_vmas[2 + i].begin = ALLOC_ALIGN_DOWN(g_pal_control->preloaded_ranges[i].start);
init_vmas[2 + i].end = ALLOC_ALIGN_UP(g_pal_control->preloaded_ranges[i].end);
init_vmas[2 + i].prot = PROT_NONE;
init_vmas[2 + i].flags = MAP_PRIVATE | MAP_ANONYMOUS | VMA_INTERNAL;
init_vmas[2 + i].file = NULL;
init_vmas[2 + i].offset = 0;
copy_comment(&init_vmas[2 + i], g_pal_control->preloaded_ranges[i].comment);
}

spinlock_lock(&vma_tree_lock);
int ret = 0;
Expand Down
8 changes: 6 additions & 2 deletions Pal/include/pal/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,12 @@ typedef struct PAL_CONTROL_ {
PAL_BOL disable_aslr; /*!< disable ASLR (may be necessary for restricted environments) */
PAL_PTR_RANGE user_address; /*!< The range of user addresses */

PAL_PTR_RANGE manifest_preload; /*!< manifest was preloaded here */
PAL_PTR_RANGE vdso_preload; /*!< vDSO was preloaded here */
struct {
uintptr_t start;
uintptr_t end;
const char* comment;
}* preloaded_ranges; /*!< array of memory ranges which are preoccupied */
size_t preloaded_ranges_len;

/*
* Host information
Expand Down
23 changes: 23 additions & 0 deletions Pal/src/db_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,26 @@ int DkVirtualMemoryProtect(PAL_PTR addr, PAL_NUM size, PAL_FLG prot) {

return _DkVirtualMemoryProtect((void*)addr, size, prot);
}

int add_preloaded_range(uintptr_t start, uintptr_t end, const char* comment) {
size_t new_len = g_pal_control.preloaded_ranges_len + 1;
void* new_ranges = malloc(new_len * sizeof(*g_pal_control.preloaded_ranges));
if (!new_ranges) {
return -PAL_ERROR_NOMEM;
}

if (g_pal_control.preloaded_ranges_len) {
memcpy(new_ranges, g_pal_control.preloaded_ranges,
g_pal_control.preloaded_ranges_len * sizeof(*g_pal_control.preloaded_ranges));
}

free(g_pal_control.preloaded_ranges);
g_pal_control.preloaded_ranges = new_ranges;

g_pal_control.preloaded_ranges[g_pal_control.preloaded_ranges_len].start = start;
g_pal_control.preloaded_ranges[g_pal_control.preloaded_ranges_len].end = end;
g_pal_control.preloaded_ranges[g_pal_control.preloaded_ranges_len].comment = comment;
g_pal_control.preloaded_ranges_len++;

return 0;
}
8 changes: 6 additions & 2 deletions Pal/src/host/Linux-SGX/db_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -690,8 +690,12 @@ noreturn void pal_linux_main(char* uptr_libpal_uri, size_t libpal_uri_len, char*
uint64_t manifest_size = GET_ENCLAVE_TLS(manifest_size);
void* manifest_addr = g_enclave_top - ALIGN_UP_PTR_POW2(manifest_size, g_page_size);

g_pal_control.manifest_preload.start = (PAL_PTR)manifest_addr;
g_pal_control.manifest_preload.end = (PAL_PTR)manifest_addr + manifest_size;
ret = add_preloaded_range((uintptr_t)manifest_addr, (uintptr_t)manifest_addr + manifest_size,
"manifest");
if (ret < 0) {
log_error("Failed to initialize manifest preload range: %d\n", ret);
ocall_exit(1, /*is_exitgroup=*/true);
}

/* parse manifest */
char errbuf[256];
Expand Down
5 changes: 4 additions & 1 deletion Pal/src/host/Linux-SGX/pal_linux_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
#include "pal_error.h"

static int unix_to_pal_error_positive(int unix_errno) {
assert(unix_errno > 0);
assert(unix_errno >= 0);
switch (unix_errno) {
case 0:
return PAL_ERROR_SUCCESS;
static_assert(PAL_ERROR_SUCCESS == 0, "unexpected PAL_ERROR_SUCCESS value");
case ENOENT:
return PAL_ERROR_STREAMNOTEXIST;
case EINTR:
Expand Down
2 changes: 1 addition & 1 deletion Pal/src/host/Linux/db_exception.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ static void handle_sync_signal(int signum, siginfo_t* info, struct ucontext* uc)
bool in_vdso = is_in_vdso(rip);
log_error("*** Unexpected %s occurred inside %s (PID = %ld, TID = %ld, RIP = +0x%08lx)! ***\n",
name, in_vdso ? "VDSO" : "PAL", INLINE_SYSCALL(getpid, 0), INLINE_SYSCALL(gettid, 0),
rip - (in_vdso ? get_vdso_start() : (uintptr_t)TEXT_START));
rip - (in_vdso ? g_vdso_start : (uintptr_t)TEXT_START));

_DkProcessExit(1);
}
Expand Down
36 changes: 34 additions & 2 deletions Pal/src/host/Linux/db_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ noreturn void pal_linux_main(void* initial_rsp, void* fini_callback) {
uint64_t start_time;
ret = _DkSystemTimeQuery(&start_time);
if (ret < 0)
INIT_FAIL(unix_to_pal_error(-ret), "_DkSystemTimeQuery() failed");
INIT_FAIL(-ret, "_DkSystemTimeQuery() failed");

/* Initialize alloc_align as early as possible, a lot of PAL APIs depend on this being set. */
g_pal_state.alloc_align = _DkGetAllocationAlignment();
Expand Down Expand Up @@ -222,6 +222,38 @@ noreturn void pal_linux_main(void* initial_rsp, void* fini_callback) {
if (g_sysinfo_ehdr)
setup_vdso_map(g_sysinfo_ehdr);

uintptr_t vdso_start = 0;
uintptr_t vdso_end = 0;
uintptr_t vvar_start = 0;
uintptr_t vvar_end = 0;
ret = get_vdso_and_vvar_ranges(&vdso_start, &vdso_end, &vvar_start, &vvar_end);
if (ret < 0) {
INIT_FAIL(-ret, "getting vdso and vvar ranges failed");
}

if (!g_vdso_start && !g_vdso_end) {
/* We did not get vdso address from the auxiliary vector. */
g_vdso_start = vdso_start;
g_vdso_end = vdso_end;
}

if (g_vdso_start || g_vdso_end) {
ret = add_preloaded_range(g_vdso_start, g_vdso_end, "vdso");
if (ret < 0) {
INIT_FAIL(PAL_ERROR_NOMEM, "Out of memory");
}
} else {
log_warning("vdso address range not preloaded, is your system missing vdso?!\n");
}
if (vvar_start || vvar_end) {
ret = add_preloaded_range(vvar_start, vvar_end, "vvar");
if (ret < 0) {
INIT_FAIL(PAL_ERROR_NOMEM, "Out of memory");
}
} else {
log_warning("vvar address range not preloaded, is your system missing vvar?!\n");
}

if (!g_pal_sec.process_id)
g_pal_sec.process_id = INLINE_SYSCALL(getpid, 0);
g_linux_state.pid = g_pal_sec.process_id;
Expand All @@ -244,7 +276,7 @@ noreturn void pal_linux_main(void* initial_rsp, void* fini_callback) {

ret = read_text_file_to_cstr(manifest_path, &manifest);
if (ret < 0) {
INIT_FAIL(-ret, "Reading manifest failed");
INIT_FAIL(unix_to_pal_error(-ret), "Reading manifest failed");
}
} else {
// Children receive their argv and config via IPC.
Expand Down
80 changes: 80 additions & 0 deletions Pal/src/host/Linux/db_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "pal_internal.h"
#include "pal_linux.h"
#include "pal_linux_defs.h"
#include "pal_linux_error.h"

bool _DkCheckMemoryMappable(const void* addr, size_t size) {
return (addr < DATA_END && addr + size > TEXT_START);
Expand Down Expand Up @@ -123,3 +124,82 @@ unsigned long _DkMemoryAvailableQuota(void) {
return 0;
return quota * 1024;
}

static void parse_line(const char* line, uintptr_t* start_ptr, uintptr_t* end_ptr) {
char* next = NULL;
long start = strtol(line, &next, 16);
long end = 0;
if (next && next[0] == '-') {
end = strtol(next + 1, NULL, 16);
}
if (start >= 0 && end > 0) {
*start_ptr = (uintptr_t)start;
*end_ptr = (uintptr_t)end;
}
}

/* This function is very fragile w.r.t. "/proc/self/maps" file format. */
int get_vdso_and_vvar_ranges(uintptr_t* vdso_start, uintptr_t* vdso_end, uintptr_t* vvar_start,
uintptr_t* vvar_end) {
int fd = INLINE_SYSCALL(open, 3, "/proc/self/maps", O_RDONLY, 0);
if (fd < 0) {
return unix_to_pal_error(fd);
}

const char* vdso_str = "[vdso]";
const size_t vdso_str_len = strlen(vdso_str);
const char* vvar_str = "[vvar]";
const size_t vvar_str_len = strlen(vvar_str);

int ret = 0;
/* Arbitrary size, must be big enough to hold lines containing "vdso" and "vvar". */
char buf[0x100];
size_t size = 0;
ssize_t got = 0;
do {
/* There should be no failures or partial reads from this fd. */
got = INLINE_SYSCALL(read, 3, fd, buf + size, sizeof(buf) - 1 - size);
if (got < 0) {
ret = unix_to_pal_error(got);
goto out;
}
size += (size_t)got;
buf[size] = '\0';

char* line_end = strchr(buf, '\n');
if (!line_end) {
line_end = buf + size;
}
assert(line_end < buf + sizeof(buf));
*line_end = '\0';

uintptr_t start = 0;
uintptr_t end = 0;
if (!memcmp(vdso_str, line_end - vdso_str_len, vdso_str_len)) {
parse_line(buf, &start, &end);
if (start || end) {
*vdso_start = start;
*vdso_end = end;
}
}
if (!memcmp(vvar_str, line_end - vvar_str_len, vvar_str_len)) {
parse_line(buf, &start, &end);
if (start || end) {
*vvar_start = start;
*vvar_end = end;
}
}

size_t new_size = 0;
if (buf + size > line_end + 1) {
new_size = buf + size - (line_end + 1);
memmove(buf, line_end + 1, new_size);
}
size = new_size;
} while (size > 0 || got > 0);

out:;
int tmp_ret = unix_to_pal_error(INLINE_SYSCALL(close, 1, fd));
return ret ?: tmp_ret;
}

24 changes: 7 additions & 17 deletions Pal/src/host/Linux/db_rtld.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,11 @@
#include "pal_linux.h"
#include "pal_rtld.h"

static uintptr_t vdso_start = 0;
static uintptr_t vdso_end = 0;

uintptr_t get_vdso_start(void) {
return vdso_start;
}
uintptr_t g_vdso_start = 0;
uintptr_t g_vdso_end = 0;

bool is_in_vdso(uintptr_t addr) {
return (vdso_start || vdso_end) && vdso_start <= addr && addr < vdso_end;
return (g_vdso_start || g_vdso_end) && g_vdso_start <= addr && addr < g_vdso_end;
}

void _DkDebugMapAdd(const char* name, void* addr) {
Expand Down Expand Up @@ -76,8 +72,8 @@ void setup_vdso_map(ElfW(Addr) addr) {
switch (ph->p_type) {
case PT_LOAD:
load_offset = addr + (ElfW(Addr))ph->p_offset - (ElfW(Addr))ph->p_vaddr;
vdso_start = (uintptr_t)addr;
vdso_end = ALIGN_UP(vdso_start + (size_t)ph->p_memsz, PAGE_SIZE);
g_vdso_start = (uintptr_t)addr;
g_vdso_end = ALIGN_UP(g_vdso_start + (size_t)ph->p_memsz, PAGE_SIZE);
pt_loads_count++;
break;
case PT_DYNAMIC:
Expand All @@ -89,8 +85,8 @@ void setup_vdso_map(ElfW(Addr) addr) {
if (pt_loads_count != 1) {
log_warning("The VDSO has %lu PT_LOAD segments, but only 1 was expected.\n",
pt_loads_count);
vdso_start = 0;
vdso_end = 0;
g_vdso_start = 0;
g_vdso_end = 0;
return;
}

Expand Down Expand Up @@ -128,10 +124,4 @@ void setup_vdso_map(ElfW(Addr) addr) {
sym = do_lookup_map(NULL, gettime, fast_hash, hash, &vdso_map);
if (sym)
g_linux_state.vdso_clock_gettime = (void*)(load_offset + sym->st_value);

if (vdso_start || vdso_end) {
/* vDSO occupies some memory region, need to inform the LibOS so it reflects it in VMAs */
g_pal_control.vdso_preload.start = (PAL_PTR)vdso_start;
g_pal_control.vdso_preload.end = (PAL_PTR)vdso_end;
}
}
6 changes: 5 additions & 1 deletion Pal/src/host/Linux/pal_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,12 @@ int clone(int (*__fn)(void* __arg), void* __child_stack, int __flags, const void
/* PAL main function */
noreturn void pal_linux_main(void* initial_rsp, void* fini_callback);

uintptr_t get_vdso_start(void);
extern uintptr_t g_vdso_start;
extern uintptr_t g_vdso_end;
bool is_in_vdso(uintptr_t addr);
/* Parse "/proc/self/maps" and return addres ranges for "vdso" and "vvar". */
int get_vdso_and_vvar_ranges(uintptr_t* vdso_start, uintptr_t* vdso_end, uintptr_t* vvar_start,
uintptr_t* vvar_end);

struct link_map;
void setup_pal_map(struct link_map* map);
Expand Down
5 changes: 4 additions & 1 deletion Pal/src/host/Linux/pal_linux_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
#include "pal_error.h"

static int unix_to_pal_error_positive(int unix_errno) {
assert(unix_errno > 0);
assert(unix_errno >= 0);
switch (unix_errno) {
case 0:
return PAL_ERROR_SUCCESS;
static_assert(PAL_ERROR_SUCCESS == 0, "unexpected PAL_ERROR_SUCCESS value");
case ENOENT:
return PAL_ERROR_STREAMNOTEXIST;
case EINTR:
Expand Down
2 changes: 2 additions & 0 deletions Pal/src/pal_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ extern struct pal_internal_state g_pal_state;

extern PAL_CONTROL g_pal_control;

int add_preloaded_range(uintptr_t start, uintptr_t end, const char* comment);

#define IS_ALLOC_ALIGNED(addr) IS_ALIGNED_POW2(addr, g_pal_state.alloc_align)
#define IS_ALLOC_ALIGNED_PTR(addr) IS_ALIGNED_PTR_POW2(addr, g_pal_state.alloc_align)
#define ALLOC_ALIGN_UP(addr) ALIGN_UP_POW2(addr, g_pal_state.alloc_align)
Expand Down

0 comments on commit 30fbb8d

Please sign in to comment.