1 #include "libc.h"
2 #include "threads_impl.h"
3 #include "setjmp_impl.h"
4 #include "zircon_impl.h"
5 #include <elf.h>
6 #include <stdatomic.h>
7 #include <string.h>
8 
9 #include <zircon/sanitizer.h>
10 #include <zircon/syscalls.h>
11 #include <runtime/message.h>
12 #include <runtime/processargs.h>
13 #include <runtime/thread.h>
14 
15 struct start_params {
16     int (*main)(int, char**, char**);
17     thrd_t td;
18     uint8_t* buffer;
19     zx_proc_args_t* procargs;
20     zx_handle_t* handles;
21     uint32_t* handle_info;
22     uint32_t nbytes, nhandles;
23 };
24 
25 // This gets called via inline assembly below, after switching onto
26 // the newly-allocated (safe) stack.
27 static _Noreturn void start_main(const struct start_params*)
28     __asm__("start_main") __attribute__((used));
start_main(const struct start_params * p)29 static void start_main(const struct start_params* p) {
30     uint32_t argc = p->procargs->args_num;
31     uint32_t envc = p->procargs->environ_num;
32     uint32_t namec = p->procargs->names_num;
33 
34     // Use a single contiguous buffer for argv and envp, with two
35     // extra words of terminator on the end.  In traditional Unix
36     // process startup, the stack contains argv followed immediately
37     // by envp and that's followed immediately by the auxiliary vector
38     // (auxv), which is in two-word pairs and terminated by zero
39     // words.  Some crufty programs might assume some of that layout,
40     // and it costs us nothing to stay consistent with it here.
41     char* args_and_environ[argc + 1 + envc + 1 + 2];
42     char** argv = &args_and_environ[0];
43     __environ = &args_and_environ[argc + 1];
44     char** dummy_auxv = &args_and_environ[argc + 1 + envc + 1];
45     dummy_auxv[0] = dummy_auxv[1] = 0;
46 
47     char* names[namec + 1];
48     zx_status_t status = zxr_processargs_strings(p->buffer, p->nbytes,
49                                                  argv, __environ, names);
50     if (status != ZX_OK) {
51         argc = namec = 0;
52         argv = __environ = NULL;
53     }
54 
55     __sanitizer_startup_hook(argc, argv, __environ,
56                              p->td->safe_stack.iov_base,
57                              p->td->safe_stack.iov_len);
58 
59     // Allow companion libraries a chance to claim handles, zeroing out
60     // handles[i] and handle_info[i] for handles they claim.
61     if (&__libc_extensions_init != NULL) {
62         __libc_extensions_init(p->nhandles, p->handles, p->handle_info,
63                                namec, names);
64     }
65 
66     // Give any unclaimed handles to zx_take_startup_handle(). This function
67     // takes ownership of the data, but not the memory: it assumes that the
68     // arrays are valid as long as the process is alive.
69     __libc_startup_handles_init(p->nhandles, p->handles, p->handle_info);
70 
71     // Run static constructors et al.
72     __libc_start_init();
73 
74     // Pass control to the application.
75     exit((*p->main)(argc, argv, __environ));
76 }
77 
__libc_start_main(void * arg,int (* main)(int,char **,char **))78 __NO_SAFESTACK _Noreturn void __libc_start_main(
79     void* arg, int (*main)(int, char**, char**)) {
80 
81     // Initialize stack-protector canary value first thing.  Do the setjmp
82     // manglers in the same call to avoid the overhead of two system calls.
83     // That means we need a temporary buffer on the stack, which we then
84     // want to clear out so the values don't leak there.
85     struct randoms {
86         uintptr_t stack_guard;
87         struct setjmp_manglers setjmp_manglers;
88     } randoms;
89     static_assert(sizeof(randoms) <= ZX_CPRNG_DRAW_MAX_LEN, "");
90     _zx_cprng_draw(&randoms, sizeof(randoms));
91     __stack_chk_guard = randoms.stack_guard;
92     __setjmp_manglers = randoms.setjmp_manglers;
93     // Zero the stack temporaries.
94     randoms = (struct randoms) {};
95     // Tell the compiler that the value is used, so it doesn't optimize
96     // out the zeroing as dead stores.
97     __asm__("# keepalive %0" :: "m"(randoms));
98 
99     // extract process startup information from channel in arg
100     zx_handle_t bootstrap = (uintptr_t)arg;
101 
102     struct start_params p = { .main = main };
103     zx_status_t status = zxr_message_size(bootstrap, &p.nbytes, &p.nhandles);
104     if (status != ZX_OK) {
105         p.nbytes = p.nhandles = 0;
106     }
107     ZXR_PROCESSARGS_BUFFER(buffer, p.nbytes);
108     zx_handle_t handles[p.nhandles];
109     p.buffer = buffer;
110     p.handles = handles;
111     if (status == ZX_OK) {
112         status = zxr_processargs_read(bootstrap, buffer, p.nbytes,
113                                       handles, p.nhandles,
114                                       &p.procargs, &p.handle_info);
115     }
116 
117     // Find the handles we're interested in among what we were given.
118     zx_handle_t main_thread_handle = ZX_HANDLE_INVALID;
119     for (uint32_t i = 0; i < p.nhandles; ++i) {
120         switch (PA_HND_TYPE(p.handle_info[i])) {
121         case PA_PROC_SELF:
122             // The handle will have been installed already by dynamic
123             // linker startup, but now we have another one.  They
124             // should of course be handles to the same process, but
125             // just for cleanliness switch to the "main" one.
126             if (__zircon_process_self != ZX_HANDLE_INVALID)
127                 _zx_handle_close(__zircon_process_self);
128             __zircon_process_self = handles[i];
129             handles[i] = ZX_HANDLE_INVALID;
130             p.handle_info[i] = 0;
131             break;
132 
133         case PA_JOB_DEFAULT:
134             // The default job provided to the process to use for
135             // creation of additional processes.  It may or may not
136             // be the job this process is a child of.  It may not
137             // be provided at all.
138             if (__zircon_job_default != ZX_HANDLE_INVALID)
139                 _zx_handle_close(__zircon_job_default);
140             __zircon_job_default = handles[i];
141             handles[i] = ZX_HANDLE_INVALID;
142             p.handle_info[i] = 0;
143             break;
144 
145         case PA_VMAR_ROOT:
146             // As above for PROC_SELF
147             if (__zircon_vmar_root_self != ZX_HANDLE_INVALID)
148                 _zx_handle_close(__zircon_vmar_root_self);
149             __zircon_vmar_root_self = handles[i];
150             handles[i] = ZX_HANDLE_INVALID;
151             p.handle_info[i] = 0;
152             break;
153 
154         case PA_THREAD_SELF:
155             main_thread_handle = handles[i];
156             handles[i] = ZX_HANDLE_INVALID;
157             p.handle_info[i] = 0;
158             break;
159         }
160     }
161 
162     atomic_store(&libc.thread_count, 1);
163 
164     // This consumes the thread handle and sets up the thread pointer.
165     p.td = __init_main_thread(main_thread_handle);
166 
167     // Switch to the allocated stack and call start_main(&p) there.  The
168     // original stack stays around just to hold the message buffer and handles
169     // array.  The new stack is whole pages, so it's sufficiently aligned.
170 
171 #ifdef __x86_64__
172     // The x86-64 ABI requires %rsp % 16 = 8 on entry.  The zero word
173     // at (%rsp) serves as the return address for the outermost frame.
174     __asm__("lea -8(%[base], %[len], 1), %%rsp\n"
175             "jmp start_main\n"
176             "# Target receives %[arg]" : :
177             [base]"r"(p.td->safe_stack.iov_base),
178             [len]"r"(p.td->safe_stack.iov_len),
179             "m"(p), // Tell the compiler p's fields are all still alive.
180             [arg]"D"(&p));
181 #elif defined(__aarch64__)
182     __asm__("add sp, %[base], %[len]\n"
183             "mov x0, %[arg]\n"
184             "b start_main" : :
185             [base]"r"(p.td->safe_stack.iov_base),
186             [len]"r"(p.td->safe_stack.iov_len),
187             "m"(p), // Tell the compiler p's fields are all still alive.
188             [arg]"r"(&p));
189 #else
190 #error what architecture?
191 #endif
192 
193     __builtin_unreachable();
194 }
195