1 // Copyright 2016 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <assert.h>
8 #include <err.h>
9 #include <inttypes.h>
10 #include <platform.h>
11 #include <trace.h>
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include <kernel/cmdline.h>
18 #include <vm/vm_object_paged.h>
19 #include <lib/console.h>
20 #include <lib/vdso.h>
21 #include <lk/init.h>
22 #include <mexec.h>
23 #include <object/channel_dispatcher.h>
24 #include <object/handle.h>
25 #include <object/job_dispatcher.h>
26 #include <object/message_packet.h>
27 #include <object/process_dispatcher.h>
28 #include <object/resource_dispatcher.h>
29 #include <object/thread_dispatcher.h>
30 #include <object/vm_address_region_dispatcher.h>
31 #include <object/vm_object_dispatcher.h>
32 
33 #include <zircon/processargs.h>
34 #include <zircon/stack.h>
35 
36 #if ENABLE_ENTROPY_COLLECTOR_TEST
37 #include <lib/crypto/entropy/quality_test.h>
38 #endif
39 
40 static const size_t stack_size = ZIRCON_DEFAULT_STACK_SIZE;
41 
42 #define STACK_VMO_NAME "userboot-initial-stack"
43 #define RAMDISK_VMO_NAME "userboot-raw-ramdisk"
44 #define CRASHLOG_VMO_NAME "crashlog"
45 
46 namespace {
47 
48 #include "userboot-code.h"
49 
50 // This is defined in assembly by userboot-image.S; userboot-code.h
51 // gives details about the image's size and layout.
52 extern "C" const char userboot_image[];
53 
54 class UserbootImage : private RoDso {
55 public:
UserbootImage(const VDso * vdso)56     explicit UserbootImage(const VDso* vdso)
57         : RoDso("userboot", userboot_image,
58                 USERBOOT_CODE_END, USERBOOT_CODE_START),
59           vdso_(vdso) {}
60 
61     // The whole userboot image consists of the userboot rodso image
62     // immediately followed by the vDSO image.  This returns the size
63     // of that combined image.
size() const64     size_t size() const {
65         return RoDso::size() + vdso_->size();
66     }
67 
Map(fbl::RefPtr<VmAddressRegionDispatcher> root_vmar,uintptr_t * vdso_base,uintptr_t * entry)68     zx_status_t Map(fbl::RefPtr<VmAddressRegionDispatcher> root_vmar,
69                     uintptr_t* vdso_base, uintptr_t* entry) {
70         // Create a VMAR (placed anywhere) to hold the combined image.
71         fbl::RefPtr<VmAddressRegionDispatcher> vmar;
72         zx_rights_t vmar_rights;
73         zx_status_t status = root_vmar->Allocate(0, size(),
74                                                  ZX_VM_CAN_MAP_READ |
75                                                  ZX_VM_CAN_MAP_WRITE |
76                                                  ZX_VM_CAN_MAP_EXECUTE |
77                                                  ZX_VM_CAN_MAP_SPECIFIC,
78                                                  &vmar, &vmar_rights);
79         if (status != ZX_OK)
80             return status;
81 
82         // Map userboot proper.
83         status = RoDso::Map(vmar, 0);
84         if (status == ZX_OK) {
85             *entry = vmar->vmar()->base() + USERBOOT_ENTRY;
86 
87             // Map the vDSO right after it.
88             *vdso_base = vmar->vmar()->base() + RoDso::size();
89             status = vdso_->Map(ktl::move(vmar), RoDso::size());
90         }
91         return status;
92     }
93 
94 private:
95     const VDso* vdso_;
96 };
97 
98 } // anonymous namespace
99 
100 
101 // Get a handle to a VM object, with full rights except perhaps for writing.
get_vmo_handle(fbl::RefPtr<VmObject> vmo,bool readonly,fbl::RefPtr<VmObjectDispatcher> * disp_ptr,Handle ** ptr)102 static zx_status_t get_vmo_handle(fbl::RefPtr<VmObject> vmo, bool readonly,
103                                   fbl::RefPtr<VmObjectDispatcher>* disp_ptr,
104                                   Handle** ptr) {
105     if (!vmo)
106         return ZX_ERR_NO_MEMORY;
107     zx_rights_t rights;
108     fbl::RefPtr<Dispatcher> dispatcher;
109     zx_status_t result = VmObjectDispatcher::Create(
110         ktl::move(vmo), &dispatcher, &rights);
111     if (result == ZX_OK) {
112         if (disp_ptr)
113             *disp_ptr = fbl::RefPtr<VmObjectDispatcher>::Downcast(dispatcher);
114         if (readonly)
115             rights &= ~ZX_RIGHT_WRITE;
116         if (ptr)
117             *ptr = Handle::Make(ktl::move(dispatcher), rights).release();
118     }
119     return result;
120 }
121 
get_job_handle(Handle ** ptr)122 static zx_status_t get_job_handle(Handle** ptr) {
123     zx_rights_t rights;
124     fbl::RefPtr<Dispatcher> dispatcher;
125     zx_status_t result = JobDispatcher::Create(
126         0u, GetRootJobDispatcher(), &dispatcher, &rights);
127     if (result == ZX_OK)
128         *ptr = Handle::Make(ktl::move(dispatcher), rights).release();
129     return result;
130 }
131 
get_resource_handle(Handle ** ptr)132 static zx_status_t get_resource_handle(Handle** ptr) {
133     zx_rights_t rights;
134     fbl::RefPtr<ResourceDispatcher> root;
135     zx_status_t result = ResourceDispatcher::Create(&root, &rights, ZX_RSRC_KIND_ROOT, 0, 0, 0,
136                                                     "root");
137     if (result == ZX_OK)
138         *ptr = Handle::Make(fbl::RefPtr<Dispatcher>(root.get()),
139                             rights).release();
140     return result;
141 }
142 
143 // Create a channel and write the bootstrap message down one side of
144 // it, returning the handle to the other side.
make_bootstrap_channel(fbl::RefPtr<ProcessDispatcher> process,MessagePacketPtr msg,zx_handle_t * out)145 static zx_status_t make_bootstrap_channel(
146     fbl::RefPtr<ProcessDispatcher> process,
147     MessagePacketPtr msg,
148     zx_handle_t* out) {
149     HandleOwner user_channel_handle;
150     fbl::RefPtr<ChannelDispatcher> kernel_channel;
151     *out = ZX_HANDLE_INVALID;
152     {
153         fbl::RefPtr<Dispatcher> mpd0, mpd1;
154         zx_rights_t rights;
155         zx_status_t status = ChannelDispatcher::Create(&mpd0, &mpd1, &rights);
156         if (status != ZX_OK)
157             return status;
158         user_channel_handle = Handle::Make(ktl::move(mpd0), rights);
159         kernel_channel = DownCastDispatcher<ChannelDispatcher>(&mpd1);
160     }
161 
162     // Here it goes!
163     zx_status_t status = kernel_channel->Write(ZX_KOID_INVALID, ktl::move(msg));
164     if (status != ZX_OK)
165         return status;
166 
167     zx_handle_t hv = process->MapHandleToValue(user_channel_handle);
168     process->AddHandle(ktl::move(user_channel_handle));
169 
170     *out = hv;
171     return ZX_OK;
172 }
173 
174 enum bootstrap_handle_index {
175     BOOTSTRAP_VDSO,
176     BOOTSTRAP_VDSO_LAST_VARIANT = BOOTSTRAP_VDSO + VDso::variants() - 1,
177     BOOTSTRAP_RAMDISK,
178     BOOTSTRAP_RESOURCE_ROOT,
179     BOOTSTRAP_STACK,
180     BOOTSTRAP_PROC,
181     BOOTSTRAP_THREAD,
182     BOOTSTRAP_JOB,
183     BOOTSTRAP_VMAR_ROOT,
184     BOOTSTRAP_CRASHLOG,
185 #if ENABLE_ENTROPY_COLLECTOR_TEST
186     BOOTSTRAP_ENTROPY_FILE,
187 #endif
188     BOOTSTRAP_HANDLES
189 };
190 
191 struct bootstrap_message {
192     zx_proc_args_t header;
193     uint32_t handle_info[BOOTSTRAP_HANDLES];
194     char cmdline[CMDLINE_MAX];
195 };
196 
prepare_bootstrap_message()197 static MessagePacketPtr prepare_bootstrap_message() {
198     const size_t data_size =
199         offsetof(struct bootstrap_message, cmdline) +
200         __kernel_cmdline_size;
201     bootstrap_message* msg =
202         static_cast<bootstrap_message*>(malloc(data_size));
203     if (msg == nullptr) {
204         return nullptr;
205     }
206 
207     memset(&msg->header, 0, sizeof(msg->header));
208     msg->header.protocol = ZX_PROCARGS_PROTOCOL;
209     msg->header.version = ZX_PROCARGS_VERSION;
210     msg->header.environ_off = offsetof(struct bootstrap_message, cmdline);
211     msg->header.environ_num = static_cast<uint32_t>(__kernel_cmdline_count);
212     msg->header.handle_info_off =
213         offsetof(struct bootstrap_message, handle_info);
214     for (int i = 0; i < BOOTSTRAP_HANDLES; ++i) {
215         uint32_t info = 0;
216         switch (static_cast<bootstrap_handle_index>(i)) {
217         case BOOTSTRAP_VDSO ... BOOTSTRAP_VDSO_LAST_VARIANT:
218             info = PA_HND(PA_VMO_VDSO, i - BOOTSTRAP_VDSO);
219             break;
220         case BOOTSTRAP_RAMDISK:
221             info = PA_HND(PA_VMO_BOOTDATA, 0);
222             break;
223         case BOOTSTRAP_RESOURCE_ROOT:
224             info = PA_HND(PA_RESOURCE, 0);
225             break;
226         case BOOTSTRAP_STACK:
227             info = PA_HND(PA_VMO_STACK, 0);
228             break;
229         case BOOTSTRAP_PROC:
230             info = PA_HND(PA_PROC_SELF, 0);
231             break;
232         case BOOTSTRAP_THREAD:
233             info = PA_HND(PA_THREAD_SELF, 0);
234             break;
235         case BOOTSTRAP_JOB:
236             info = PA_HND(PA_JOB_DEFAULT, 0);
237             break;
238         case BOOTSTRAP_VMAR_ROOT:
239             info = PA_HND(PA_VMAR_ROOT, 0);
240             break;
241         case BOOTSTRAP_CRASHLOG:
242             info = PA_HND(PA_VMO_KERNEL_FILE, 0);
243             break;
244 #if ENABLE_ENTROPY_COLLECTOR_TEST
245         case BOOTSTRAP_ENTROPY_FILE:
246             info = PA_HND(PA_VMO_KERNEL_FILE, 1);
247             break;
248 #endif
249         case BOOTSTRAP_HANDLES:
250             __builtin_unreachable();
251         }
252         msg->handle_info[i] = info;
253     }
254     memcpy(msg->cmdline, __kernel_cmdline, __kernel_cmdline_size);
255 
256     MessagePacketPtr packet;
257     uint32_t num_handles = BOOTSTRAP_HANDLES;
258     zx_status_t status =
259         MessagePacket::Create(msg, static_cast<uint32_t>(data_size), num_handles, &packet);
260     free(msg);
261     if (status != ZX_OK) {
262         return nullptr;
263     }
264     return packet;
265 }
266 
clog_to_vmo(const void * data,size_t off,size_t len,void * cookie)267 static void clog_to_vmo(const void* data, size_t off, size_t len, void* cookie) {
268     VmObject* vmo = static_cast<VmObject*>(cookie);
269     vmo->Write(data, off, len);
270 }
271 
272 // Converts platform crashlog into a VMO
crashlog_to_vmo(fbl::RefPtr<VmObject> * out)273 static zx_status_t crashlog_to_vmo(fbl::RefPtr<VmObject>* out) {
274     size_t size = platform_recover_crashlog(0, NULL, NULL);
275     fbl::RefPtr<VmObject> crashlog_vmo;
276     zx_status_t status = VmObjectPaged::Create(PMM_ALLOC_FLAG_ANY, 0u, size, &crashlog_vmo);
277     if (status != ZX_OK) {
278         return status;
279     }
280     platform_recover_crashlog(size, crashlog_vmo.get(), clog_to_vmo);
281     crashlog_vmo->set_name(CRASHLOG_VMO_NAME, sizeof(CRASHLOG_VMO_NAME) - 1);
282     mexec_stash_crashlog(crashlog_vmo);
283     *out = ktl::move(crashlog_vmo);
284     return ZX_OK;
285 }
286 
attempt_userboot()287 static zx_status_t attempt_userboot() {
288     size_t rsize;
289     void* rbase = platform_get_ramdisk(&rsize);
290     if (rbase)
291         dprintf(INFO, "userboot: ramdisk %#15zx @ %p\n", rsize, rbase);
292 
293     fbl::RefPtr<VmObject> stack_vmo;
294     zx_status_t status = VmObjectPaged::Create(PMM_ALLOC_FLAG_ANY, 0u, stack_size, &stack_vmo);
295     if (status != ZX_OK)
296         return status;
297     stack_vmo->set_name(STACK_VMO_NAME, sizeof(STACK_VMO_NAME) - 1);
298 
299     fbl::RefPtr<VmObject> rootfs_vmo;
300     status = VmObjectPaged::CreateFromROData(rbase, rsize, &rootfs_vmo);
301     if (status != ZX_OK)
302         return status;
303     rootfs_vmo->set_name(RAMDISK_VMO_NAME, sizeof(RAMDISK_VMO_NAME) - 1);
304 
305     fbl::RefPtr<VmObject> crashlog_vmo;
306     status = crashlog_to_vmo(&crashlog_vmo);
307     if (status != ZX_OK)
308         return status;
309 
310     // Prepare the bootstrap message packet.  This puts its data (the
311     // kernel command line) in place, and allocates space for its handles.
312     // We'll fill in the handles as we create things.
313     MessagePacketPtr msg = prepare_bootstrap_message();
314     if (!msg)
315         return ZX_ERR_NO_MEMORY;
316 
317     Handle** const handles = msg->mutable_handles();
318     DEBUG_ASSERT(msg->num_handles() == BOOTSTRAP_HANDLES);
319     status = get_vmo_handle(rootfs_vmo, false, nullptr,
320                             &handles[BOOTSTRAP_RAMDISK]);
321     fbl::RefPtr<VmObjectDispatcher> stack_vmo_dispatcher;
322     if (status == ZX_OK)
323         status = get_vmo_handle(stack_vmo, false, &stack_vmo_dispatcher,
324                                 &handles[BOOTSTRAP_STACK]);
325     if (status == ZX_OK)
326         status = get_vmo_handle(crashlog_vmo, true, nullptr,
327                                 &handles[BOOTSTRAP_CRASHLOG]);
328     if (status == ZX_OK)
329         status = get_resource_handle(&handles[BOOTSTRAP_RESOURCE_ROOT]);
330 
331     if (status == ZX_OK)
332         status = get_job_handle(&handles[BOOTSTRAP_JOB]);
333 
334 #if ENABLE_ENTROPY_COLLECTOR_TEST
335     if (status == ZX_OK) {
336         if (crypto::entropy::entropy_was_lost) {
337             status = ZX_ERR_INTERNAL;
338         } else {
339             status = get_vmo_handle(
340                     crypto::entropy::entropy_vmo,
341                     /* readonly */ true, /* disp_ptr */ nullptr,
342                     &handles[BOOTSTRAP_ENTROPY_FILE]);
343         }
344     }
345 #endif
346     if (status != ZX_OK)
347         return status;
348 
349     fbl::RefPtr<Dispatcher> proc_disp;
350     fbl::RefPtr<VmAddressRegionDispatcher> vmar;
351     zx_rights_t rights, vmar_rights;
352     status = ProcessDispatcher::Create(GetRootJobDispatcher(), "userboot", 0,
353                                        &proc_disp, &rights,
354                                        &vmar, &vmar_rights);
355     if (status != ZX_OK)
356         return status;
357 
358     handles[BOOTSTRAP_PROC] = Handle::Make(proc_disp, rights).release();
359 
360     auto proc = DownCastDispatcher<ProcessDispatcher>(&proc_disp);
361     ASSERT(proc);
362 
363     handles[BOOTSTRAP_VMAR_ROOT] = Handle::Make(vmar, vmar_rights).release();
364 
365     const VDso* vdso = VDso::Create();
366     for (size_t i = BOOTSTRAP_VDSO; i <= BOOTSTRAP_VDSO_LAST_VARIANT; ++i) {
367         HandleOwner vmo_handle =
368             vdso->vmo_handle(static_cast<VDso::Variant>(i - BOOTSTRAP_VDSO));
369         handles[i] = vmo_handle.release();
370     }
371 
372     UserbootImage userboot(vdso);
373     uintptr_t vdso_base = 0;
374     uintptr_t entry = 0;
375     status = userboot.Map(vmar, &vdso_base, &entry);
376     if (status != ZX_OK)
377         return status;
378 
379     // Map the stack anywhere.
380     fbl::RefPtr<VmMapping> stack_mapping;
381     status = vmar->Map(0,
382                        ktl::move(stack_vmo), 0, stack_size,
383                        ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
384                        &stack_mapping);
385     if (status != ZX_OK)
386         return status;
387 
388     uintptr_t stack_base = stack_mapping->base();
389     uintptr_t sp = compute_initial_stack_pointer(stack_base, stack_size);
390 
391     // Create the user thread and stash its handle for the bootstrap message.
392     fbl::RefPtr<ThreadDispatcher> thread;
393     {
394         fbl::RefPtr<Dispatcher> ut_disp;
395         // Make a copy of proc, as we need to a keep a copy for the
396         // bootstrap message.
397         status = ThreadDispatcher::Create(proc, 0, "userboot", &ut_disp, &rights);
398         if (status != ZX_OK)
399             return status;
400         handles[BOOTSTRAP_THREAD] = Handle::Make(ut_disp, rights).release();
401         thread = DownCastDispatcher<ThreadDispatcher>(&ut_disp);
402     }
403     DEBUG_ASSERT(thread);
404 
405     // All the handles are in place, so we can send the bootstrap message.
406     zx_handle_t hv;
407     status = make_bootstrap_channel(proc, ktl::move(msg), &hv);
408     if (status != ZX_OK)
409         return status;
410 
411     dprintf(SPEW, "userboot: %-23s @ %#" PRIxPTR "\n", "entry point", entry);
412 
413     // Start the process's initial thread.
414     status = thread->Start(entry, sp, static_cast<uintptr_t>(hv), vdso_base,
415                            /* initial_thread= */ true);
416     if (status != ZX_OK) {
417         printf("userboot: failed to start initial thread: %d\n", status);
418         return status;
419     }
420 
421     return ZX_OK;
422 }
423 
userboot_init(uint level)424 void userboot_init(uint level) {
425     attempt_userboot();
426 }
427 
428 LK_INIT_HOOK(userboot, userboot_init, LK_INIT_LEVEL_USER);
429