1 // Copyright 2017 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 <elfload/elfload.h>
6 #include <fbl/array.h>
7 #include <lib/zx/process.h>
8 #include <lib/zx/vmar.h>
9 #include <lib/zx/vmo.h>
10 #include <limits.h>
11 #include <new>
12 #include <string.h>
13 #include <unittest/unittest.h>
14 #include <zircon/process.h>
15 #include <zircon/processargs.h>
16 #include <zircon/syscalls.h>
17
18 static const zx::vmo vdso_vmo{zx_take_startup_handle(PA_HND(PA_VMO_VDSO, 0))};
19
20 class ScratchPad {
21 public:
22 ScratchPad() = delete;
ScratchPad(const char * name)23 ScratchPad(const char* name) {
24 EXPECT_EQ(zx_process_create(
25 zx_job_default(),
26 name, static_cast<uint32_t>(strlen(name)), 0,
27 process_.reset_and_get_address(),
28 root_vmar_.reset_and_get_address()),
29 ZX_OK, "zx_process_create");
30 }
31
root_vmar() const32 const zx::vmar& root_vmar() const { return root_vmar_; }
vdso_base() const33 uintptr_t vdso_base() const { return vdso_base_; }
vdso_code_offset() const34 uintptr_t vdso_code_offset() const { return vdso_code_offset_; }
vdso_code_size() const35 uintptr_t vdso_code_size() const { return vdso_code_size_; }
vdso_code_address() const36 uintptr_t vdso_code_address() const {
37 return vdso_base_ + vdso_code_offset_;
38 }
vdso_total_size() const39 uintptr_t vdso_total_size() const {
40 return vdso_code_offset_ + vdso_code_size_;
41 }
42
load_vdso(zx::vmar * segments_vmar=nullptr,bool really_load=true)43 zx_status_t load_vdso(zx::vmar* segments_vmar = nullptr,
44 bool really_load = true) {
45 elf_load_header_t header;
46 uintptr_t phoff;
47 zx_status_t status = elf_load_prepare(vdso_vmo.get(), nullptr, 0,
48 &header, &phoff);
49 if (status == ZX_OK) {
50 fbl::Array<elf_phdr_t> phdrs(new elf_phdr_t[header.e_phnum],
51 header.e_phnum);
52 status = elf_load_read_phdrs(vdso_vmo.get(), phdrs.get(), phoff,
53 header.e_phnum);
54 if (status == ZX_OK) {
55 for (const auto& ph : phdrs) {
56 if (ph.p_type == PT_LOAD && (ph.p_type & PF_X)) {
57 vdso_code_offset_ = ph.p_vaddr;
58 vdso_code_size_ = ph.p_memsz;
59 }
60 }
61 if (really_load) {
62 status = elf_load_map_segments(
63 root_vmar_.get(), &header, phdrs.get(), vdso_vmo.get(),
64 segments_vmar ? segments_vmar->reset_and_get_address() : nullptr,
65 &vdso_base_, nullptr);
66 }
67 }
68 }
69 return status;
70 }
71
compute_vdso_sizes()72 zx_status_t compute_vdso_sizes() {
73 return load_vdso(nullptr, false);
74 }
75
76 private:
77 zx::process process_;
78 zx::vmar root_vmar_;
79 uintptr_t vdso_base_ = 0;
80 uintptr_t vdso_code_offset_ = 0;
81 uintptr_t vdso_code_size_ = 0;
82 };
83
vdso_map_twice_test()84 bool vdso_map_twice_test() {
85 BEGIN_TEST;
86
87 ScratchPad scratch(__func__);
88
89 // Load the vDSO once. That's on me.
90 EXPECT_EQ(scratch.load_vdso(), ZX_OK, "load vDSO into empty process");
91
92 // Load the vDSO twice. Can't get loaded again.
93 EXPECT_EQ(scratch.load_vdso(), ZX_ERR_ACCESS_DENIED, "load vDSO second time");
94
95 END_TEST;
96 }
97
vdso_map_change_test()98 bool vdso_map_change_test() {
99 BEGIN_TEST;
100
101 ScratchPad scratch(__func__);
102
103 // Load the vDSO and hold onto the sub-VMAR.
104 zx::vmar vdso_vmar;
105 EXPECT_EQ(scratch.load_vdso(&vdso_vmar), ZX_OK, "load vDSO");
106
107 // Changing protections on the code pages is forbidden.
108 EXPECT_EQ(vdso_vmar.protect(scratch.vdso_code_address(),
109 scratch.vdso_code_size(),
110 ZX_VM_PERM_READ),
111 ZX_ERR_ACCESS_DENIED, "zx_vmar_protect on vDSO code");
112
113 zx::vmo vmo;
114 ASSERT_EQ(zx::vmo::create(scratch.vdso_total_size(), 0, &vmo),
115 ZX_OK, "zx_vmo_create");
116
117 // Implicit unmapping by overwriting the mapping is forbidden.
118 uintptr_t addr = 0;
119 EXPECT_EQ(vdso_vmar.map(0, vmo, 0, scratch.vdso_total_size(),
120 ZX_VM_PERM_READ |
121 ZX_VM_SPECIFIC_OVERWRITE,
122 &addr),
123 ZX_ERR_ACCESS_DENIED, "zx_vmar_map to overmap vDSO");
124 EXPECT_EQ(addr, 0, "zx_vmar_map to overmap vDSO");
125
126 // Also forbidden if done from a parent VMAR.
127 zx_info_vmar_t root_vmar_info;
128 ASSERT_EQ(scratch.root_vmar().get_info(ZX_INFO_VMAR, &root_vmar_info,
129 sizeof(root_vmar_info),
130 nullptr, nullptr),
131 ZX_OK, "zx_object_get_info on root VMAR");
132 EXPECT_EQ(scratch.root_vmar().
133 map(scratch.vdso_base() - root_vmar_info.base, vmo,
134 0, scratch.vdso_total_size(),
135 ZX_VM_PERM_READ | ZX_VM_SPECIFIC_OVERWRITE,
136 &addr),
137 ZX_ERR_ACCESS_DENIED, "zx_vmar_map to overmap vDSO from root");
138 EXPECT_EQ(addr, 0, "zx_vmar_map to overmap vDSO from root");
139
140 // Explicit unmapping covering the vDSO code region is forbidden.
141 EXPECT_EQ(scratch.root_vmar().unmap(scratch.vdso_base(),
142 scratch.vdso_total_size()),
143 ZX_ERR_ACCESS_DENIED, "zx_vmar_unmap to unmap vDSO");
144
145 // Implicit unmapping by destroying a containing VMAR is forbidden.
146 EXPECT_EQ(vdso_vmar.destroy(),
147 ZX_ERR_ACCESS_DENIED, "zx_vmar_destroy to unmap vDSO");
148 EXPECT_EQ(scratch.root_vmar().destroy(),
149 ZX_ERR_ACCESS_DENIED, "zx_vmar_destroy on root to unmap vDSO");
150
151 END_TEST;
152 }
153
vdso_map_code_wrong_test()154 bool vdso_map_code_wrong_test() {
155 BEGIN_TEST;
156
157 ScratchPad scratch(__func__);
158
159 ASSERT_EQ(scratch.compute_vdso_sizes(), ZX_OK,
160 "cannot read vDSO program headers");
161
162 // Try to map the first page, which is not the code, as executable.
163 uintptr_t addr;
164 EXPECT_EQ(scratch.root_vmar().
165 map(0, vdso_vmo, 0, PAGE_SIZE,
166 ZX_VM_PERM_READ | ZX_VM_PERM_EXECUTE, &addr),
167 ZX_ERR_ACCESS_DENIED, "executable mapping of wrong part of vDSO");
168
169 // Try to map only part of the code, not the whole code segment.
170 ASSERT_GE(scratch.vdso_code_size(), PAGE_SIZE, "vDSO code < page??");
171 if (scratch.vdso_code_size() > PAGE_SIZE) {
172 ASSERT_EQ(scratch.vdso_code_size() % PAGE_SIZE, 0);
173 EXPECT_EQ(scratch.root_vmar().
174 map(0, vdso_vmo, scratch.vdso_code_offset(), PAGE_SIZE,
175 ZX_VM_PERM_READ | ZX_VM_PERM_EXECUTE, &addr),
176 ZX_ERR_ACCESS_DENIED,
177 "executable mapping of subset of vDSO code");
178 }
179
180 END_TEST;
181 }
182
183 BEGIN_TEST_CASE(vdso_tests)
184 RUN_TEST(vdso_map_twice_test);
185 RUN_TEST(vdso_map_code_wrong_test);
186 RUN_TEST(vdso_map_change_test);
END_TEST_CASE(vdso_tests)187 END_TEST_CASE(vdso_tests)
188
189 int main(int argc, char** argv) {
190 return unittest_run_all_tests(argc, argv) ? 0 : -1;
191 }
192