1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <inttypes.h> 6#include <stdio.h> 7#include <stdlib.h> 8#include <string.h> 9 10#include <zircon/boot/bootdata.h> 11#include <zircon/process.h> 12#include <zircon/syscalls.h> 13#include <zircon/types.h> 14 15#include <fbl/algorithm.h> 16 17#include "bootfs.h" 18 19Bootfs::~Bootfs() = default; 20 21zx_status_t Bootfs::Create(zx::vmo vmo, Bootfs* bfs_out) { 22 bootfs_header_t hdr; 23 zx_status_t r = vmo.read(&hdr, 0, sizeof(hdr)); 24 if (r < 0) { 25 printf("bootfs_create: couldn't read boot_data - %d\n", r); 26 return r; 27 } 28 if (hdr.magic != BOOTFS_MAGIC) { 29 printf("bootfs_create: incorrect bootdata header: %x\n", hdr.magic); 30 return ZX_ERR_IO; 31 } 32 zx_vaddr_t addr; 33 if ((r = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo.get(), 0, 34 sizeof(hdr) + hdr.dirsize, 35 &addr)) < 0) { 36 printf("boofts_create: couldn't map directory: %d\n", r); 37 return r; 38 } 39 auto dir = reinterpret_cast<char*>(addr) + sizeof(hdr); 40 *bfs_out = Bootfs(fbl::move(vmo), hdr.dirsize, dir); 41 return ZX_OK; 42} 43 44void Bootfs::Destroy() { 45 vmo_.reset(); 46 zx_vmar_unmap(zx_vmar_root_self(), 47 (uintptr_t)dir_ - sizeof(bootfs_header_t), 48 MappingSize()); 49} 50 51zx_status_t Bootfs::Parse(Callback callback, void* cookie) { 52 size_t avail = dirsize_; 53 auto* p = static_cast<char*>(dir_); 54 zx_status_t r; 55 while (avail > sizeof(bootfs_entry_t)) { 56 auto e = reinterpret_cast<bootfs_entry_t*>(p); 57 size_t sz = BOOTFS_RECSIZE(e); 58 if ((e->name_len < 1) || (e->name_len > BOOTFS_MAX_NAME_LEN) || 59 (e->name[e->name_len - 1] != 0) || (sz > avail)) { 60 printf("bootfs: bogus entry!\n"); 61 return ZX_ERR_IO; 62 } 63 if ((r = callback(cookie, e)) != ZX_OK) { 64 return r; 65 } 66 p += sz; 67 avail -= sz; 68 } 69 return ZX_OK; 70} 71 72zx_status_t Bootfs::Open(const char* name, zx::vmo* vmo_out, uint32_t* size_out) { 73 size_t name_len = strlen(name) + 1; 74 size_t avail = dirsize_; 75 auto p = static_cast<char*>(dir_); 76 bootfs_entry_t* e; 77 while (avail > sizeof(bootfs_entry_t)) { 78 e = reinterpret_cast<bootfs_entry_t*>(p); 79 size_t sz = BOOTFS_RECSIZE(e); 80 if ((e->name_len < 1) || (e->name_len > BOOTFS_MAX_NAME_LEN) || 81 (e->name[e->name_len - 1] != 0) || (sz > avail)) { 82 printf("bootfs: bogus entry!\n"); 83 return ZX_ERR_IO; 84 } 85 if ((name_len == e->name_len) && (memcmp(name, e->name, name_len) == 0)) { 86 goto found; 87 } 88 p += sz; 89 avail -= sz; 90 } 91 printf("bootfs_open: '%s' not found\n", name); 92 return ZX_ERR_NOT_FOUND; 93 94found:; 95 zx::vmo vmo; 96 zx_status_t r; 97 98 // Clone a private copy of the file's subset of the bootfs VMO. 99 // TODO(mcgrathr): Create a plain read-only clone when the feature 100 // is implemented in the VM. 101 if ((r = vmo_.clone(ZX_VMO_CLONE_COPY_ON_WRITE, 102 e->data_off, e->data_len, &vmo)) != ZX_OK) { 103 return r; 104 } 105 106 vmo.set_property(ZX_PROP_NAME, name, name_len - 1); 107 108 // Drop unnecessary ZX_RIGHT_WRITE rights. 109 // TODO(mcgrathr): Should be superfluous with read-only zx_vmo_clone. 110 if ((r = vmo.replace(ZX_RIGHTS_BASIC | ZX_RIGHT_READ | 111 ZX_RIGHT_MAP | ZX_RIGHT_GET_PROPERTY, 112 &vmo)) != ZX_OK) { 113 return r; 114 } 115 116 // TODO(mdempsky): Restrict to bin/ and lib/. 117 if ((vmo.replace_as_executable(zx::handle(), &vmo)) != ZX_OK) { 118 return r; 119 } 120 121 *vmo_out = fbl::move(vmo); 122 if (size_out) { 123 *size_out = e->data_len; 124 } 125 return ZX_OK; 126} 127 128zx::vmo Bootfs::DuplicateVmo() { 129 zx::vmo duplicate; 130 vmo_.duplicate(ZX_RIGHT_SAME_RIGHTS, &duplicate); 131 return duplicate; 132} 133