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