Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Unified Diff: src/minsfi/trusted/loader.c

Issue 539683002: MinSFI: Add loader (Closed) Base URL: https://chromium.googlesource.com/native_client/src/native_client.git@master
Patch Set: Fixed nits Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/minsfi/trusted/entry.c ('k') | src/minsfi/trusted/state.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/minsfi/trusted/loader.c
diff --git a/src/minsfi/trusted/loader.c b/src/minsfi/trusted/loader.c
new file mode 100644
index 0000000000000000000000000000000000000000..e8750e73c57bf3b67bcfff404e2e52bf268a1dae
--- /dev/null
+++ b/src/minsfi/trusted/loader.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014 The Native Client Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <string.h>
+#include <sys/mman.h>
+
+#include "native_client/src/include/minsfi_priv.h"
+
+static inline bool IsPowerOfTwo(uint32_t x) {
+ return ((x != 0) && !(x & (x - 1)));
+}
+
+static inline bool IsAlignedPow2(uint32_t addr, uint32_t pow2) {
+ return !(addr & (pow2 - 1));
+}
+
+/* Round up to the nearest multiple of pow2 (some power of two). */
+static inline uint32_t RoundUpToMultiplePow2(uint32_t x, uint32_t pow2) {
+ return (x + pow2 - 1) & (~(pow2 - 1));
+}
+
+/*
+ * Checks that the region does form a valid interval inside the allocated
+ * subspace.
+ */
+static inline bool IsValidRegion(const MinsfiMemoryRegion *reg,
+ uint64_t subspace_size, uint32_t page_size) {
+ uint64_t region_start = reg->offset;
+ uint64_t region_end = region_start + reg->length;
+
+ /*
+ * Run the checks. Note that page alignment together with start != end imply
+ * that the region is at least one page in size
+ */
+ return (region_start < region_end) &&
+ (region_start <= subspace_size) &&
+ (region_end <= subspace_size) &&
+ IsAlignedPow2(region_start, page_size) &&
+ IsAlignedPow2(region_end, page_size);
+}
+
+/*
+ * Checks that region1 is followed by region2 with the given gap between them.
+ */
+static inline bool AreAdjacentRegions(const MinsfiMemoryRegion *region1,
+ const MinsfiMemoryRegion *region2,
+ uint32_t gap) {
+ return region1->offset + region1->length + gap == region2->offset;
+}
+
+static inline uint64_t AddressSubspaceSize(const MinsfiManifest *manifest) {
+ return (1LL << manifest->ptr_size);
+}
+
+/*
+ * Returns the amount of memory actually addressable by the sandbox, i.e. twice
+ * the size of the address subspace.
+ * See comments in the SandboxMemoryAccessess LLVM pass for more details.
+ */
+static inline size_t AddressableMemorySize(const MinsfiManifest *manifest) {
+ return AddressSubspaceSize(manifest) * 2;
+}
+
+bool MinsfiGenerateMemoryLayout(const MinsfiManifest *manifest,
+ uint32_t page_size, MinsfiMemoryLayout *mem) {
+ uint64_t subspace_size;
+
+ if (manifest->ptr_size < 20 || manifest->ptr_size > 32 ||
+ !IsPowerOfTwo(page_size))
+ return false;
+
+ subspace_size = AddressSubspaceSize(manifest);
+
+ /*
+ * Data segment is positioned at a fixed offset. The size of the region
+ * is rounded to the end of a page.
+ */
+ mem->dataseg.offset = manifest->dataseg_offset;
+ mem->dataseg.length = RoundUpToMultiplePow2(manifest->dataseg_size,
+ page_size);
+
+ /*
+ * Size of the stack is currently a fixed constant, located at the
+ * end of the address space.
+ */
+ mem->stack.length = 32 * page_size;
+ mem->stack.offset = subspace_size - mem->stack.length;
+
+ /*
+ * Heap fills the space between the data segment and the stack, separated
+ * by a guard page at each end. We check that it is at least one page long.
+ */
+ mem->heap.offset = mem->dataseg.offset + mem->dataseg.length + page_size;
+ mem->heap.length = mem->stack.offset - page_size - mem->heap.offset;
+
+ /*
+ * Verify that the memory layout is sane. This is important because
+ * we do not verify the parameters at the beginning of this function
+ * and therefore the values could have overflowed.
+ */
+ return IsValidRegion(&mem->dataseg, subspace_size, page_size) &&
+ IsValidRegion(&mem->heap, subspace_size, page_size) &&
+ IsValidRegion(&mem->stack, subspace_size, page_size) &&
+ AreAdjacentRegions(&mem->dataseg, &mem->heap, /*gap=*/ page_size) &&
+ AreAdjacentRegions(&mem->heap, &mem->stack, /*gap=*/ page_size);
+}
+
+/* Change the access rights of a given memory region to read/write. */
+static inline bool EnableMemoryRegion(char *mem_base,
+ const MinsfiMemoryRegion *reg) {
+ char *region_base = mem_base + reg->offset;
+ return region_base == mmap(region_base, reg->length,
+ PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
+}
+
+bool MinsfiInitSandbox(const MinsfiManifest *manifest, MinsfiSandbox *sb) {
+ /*
+ * Compute the boundaries of the data segment, heap and stack. Verify
+ * that they are sane.
+ */
+ if (!MinsfiGenerateMemoryLayout(manifest, getpagesize(), &sb->mem_layout))
+ return false;
+
+ /* Compute properties of the sandbox */
+ sb->mem_alloc_size = AddressableMemorySize(manifest);
+ sb->ptr_mask = AddressSubspaceSize(manifest) - 1;
+
+ /* Allocate memory for the sandbox's address subspace */
+ sb->mem_base = mmap(NULL, sb->mem_alloc_size,
+ PROT_NONE,
+ MAP_ANON | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
+ if (sb->mem_base == MAP_FAILED)
+ return false;
+
+ /*
+ * Change the rights of accessible pages to read/write. Unmap the whole
+ * memory region if the operation fails.
+ */
+ if (!EnableMemoryRegion(sb->mem_base, &sb->mem_layout.dataseg) ||
+ !EnableMemoryRegion(sb->mem_base, &sb->mem_layout.heap) ||
+ !EnableMemoryRegion(sb->mem_base, &sb->mem_layout.stack)) {
+ MinsfiUnmapSandbox(sb);
+ return false;
+ }
+
+ /* Copy the data segment template into the memory subspace. */
+ memcpy(sb->mem_base + sb->mem_layout.dataseg.offset,
+ manifest->dataseg_template, manifest->dataseg_size);
+
+ return true;
+}
+
+bool MinsfiUnmapSandbox(const MinsfiSandbox *sb) {
+ return munmap(sb->mem_base, sb->mem_alloc_size) == 0;
+}
« no previous file with comments | « src/minsfi/trusted/entry.c ('k') | src/minsfi/trusted/state.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698