1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "berberis/guest_loader/guest_loader.h"
18
19 #include <algorithm> // std::generate
20 #include <climits> // CHAR_BIT
21 #include <cstdint>
22 #include <cstdlib>
23 #include <functional> // std::ref
24 #include <mutex>
25 #include <random>
26 #include <thread>
27
28 #include "berberis/base/checks.h"
29 #include "berberis/base/config_globals.h" // SetMainExecutableRealPath
30 #include "berberis/base/stringprintf.h"
31 #include "berberis/base/tracing.h"
32 #include "berberis/guest_abi/guest_params.h"
33 #include "berberis/guest_os_primitives/guest_thread.h"
34 #include "berberis/guest_os_primitives/guest_thread_manager.h" // GetCurrentGuestThread
35 #include "berberis/guest_os_primitives/scoped_pending_signals.h"
36 #include "berberis/guest_state/guest_addr.h"
37 #include "berberis/guest_state/guest_state.h"
38 #include "berberis/kernel_api/sys_mman_emulation.h"
39 #include "berberis/proxy_loader/proxy_loader.h"
40 #include "berberis/runtime_primitives/host_function_wrapper_impl.h" // MakeTrampolineCallable
41 #include "berberis/runtime_primitives/runtime_library.h" // ExecuteGuestCall
42 #include "berberis/runtime_primitives/virtual_guest_call_frame.h"
43 #include "berberis/tiny_loader/tiny_loader.h"
44 #include "native_bridge_support/linker/static_tls_config.h"
45
46 #include "private/CFIShadow.h" // kLibraryAlignment
47
48 #include "app_process.h"
49 #include "guest_loader_impl.h"
50
51 namespace berberis {
52
53 namespace {
54
FindPtInterp(const LoadedElfFile * loaded_executable)55 const char* FindPtInterp(const LoadedElfFile* loaded_executable) {
56 const ElfPhdr* phdr_table = loaded_executable->phdr_table();
57 size_t phdr_count = loaded_executable->phdr_count();
58 ElfAddr load_bias = loaded_executable->load_bias();
59
60 for (size_t i = 0; i < phdr_count; ++i) {
61 const auto& phdr = phdr_table[i];
62 if (phdr.p_type == PT_INTERP) {
63 return reinterpret_cast<const char*>(load_bias + phdr.p_vaddr);
64 }
65 }
66
67 return nullptr;
68 }
69
FillRandomBuf(uint8_t * buf,size_t size)70 void FillRandomBuf(uint8_t* buf, size_t size) {
71 // arc4random was introduced in GLIBC 2.36
72 #if defined(__GLIBC__) && ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 36)))
73 // Fall back to implementation-defined stl random
74 std::random_device random_device("/dev/urandom");
75 std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t> engine(
76 random_device());
77 std::generate(buf, buf + size, std::ref(engine));
78 #else
79 // use arc4random for everything else
80 arc4random_buf(buf, size);
81 #endif
82 }
83
StartGuestExecutableImpl(size_t argc,const char * argv[],char * envp[],const LoadedElfFile * linker_elf_file,const LoadedElfFile * main_executable_elf_file,const LoadedElfFile * vdso_elf_file)84 [[noreturn]] void StartGuestExecutableImpl(size_t argc,
85 const char* argv[],
86 char* envp[],
87 const LoadedElfFile* linker_elf_file,
88 const LoadedElfFile* main_executable_elf_file,
89 const LoadedElfFile* vdso_elf_file) {
90 GuestAddr main_executable_entry_point = ToGuestAddr(main_executable_elf_file->entry_point());
91 GuestAddr entry_point;
92
93 if (linker_elf_file->is_loaded()) {
94 entry_point = ToGuestAddr(linker_elf_file->entry_point());
95 } else {
96 // This is static executable. Entry point override only makes sense for static executables.
97 uintptr_t entry_point_override = GetEntryPointOverride();
98 if (entry_point_override != 0) {
99 entry_point = ToGuestAddr(reinterpret_cast<void*>(entry_point_override));
100 } else {
101 entry_point = main_executable_entry_point;
102 }
103 }
104
105 uint8_t kRandomBytes[16];
106 FillRandomBuf(kRandomBytes, sizeof(kRandomBytes));
107
108 GuestThread* main_thread = GetCurrentGuestThread();
109 ThreadState* state = main_thread->state();
110
111 ScopedPendingSignalsEnabler scoped_pending_signals_enabler(main_thread);
112
113 CPUState& cpu = state->cpu;
114 ScopedVirtualGuestCallFrame virtual_guest_call_frame(&cpu, entry_point);
115
116 GuestAddr updated_stack = InitKernelArgs(GetStackRegister(cpu),
117 argc,
118 argv,
119 envp,
120 ToGuestAddr(linker_elf_file->base_addr()),
121 main_executable_entry_point,
122 ToGuestAddr(main_executable_elf_file->phdr_table()),
123 main_executable_elf_file->phdr_count(),
124 ToGuestAddr(vdso_elf_file->base_addr()),
125 &kRandomBytes);
126 SetStackRegister(cpu, updated_stack);
127
128 // Main thread's stack contains envp and aux that may be used by other threads.
129 // Prevent stack unmap on main thread exit so the data remains available.
130 main_thread->DisallowStackUnmap();
131
132 ExecuteGuestCall(state);
133
134 FATAL("program '%s' didn't exit()", argv[0]);
135 }
136
137 // ATTENTION: Assume guest and host integer and pointer types match.
138 class FormatBufferGuestParamsArgs {
139 public:
140 // Capture ephemeral GuestVAListParams into internal params_ variable.
141 // GuestVAListParams is ephemeral in most cases because it's either produced from GuestParams or
142 // from std::va_list argument.
FormatBufferGuestParamsArgs(GuestVAListParams && params)143 explicit FormatBufferGuestParamsArgs(GuestVAListParams&& params) : params_(params) {}
144
GetCStr()145 const char* GetCStr() { return params_.GetPointerParam<const char>(); }
GetPtrAsUInt()146 uintmax_t GetPtrAsUInt() { return params_.GetParam<GuestAddr>(); }
GetInt()147 intmax_t GetInt() { return params_.GetParam<int>(); }
GetLong()148 intmax_t GetLong() { return params_.GetParam<long>(); }
GetLongLong()149 intmax_t GetLongLong() { return params_.GetParam<long long>(); }
GetUInt()150 uintmax_t GetUInt() { return params_.GetParam<unsigned int>(); }
GetULong()151 uintmax_t GetULong() { return params_.GetParam<unsigned long>(); }
GetULongLong()152 uintmax_t GetULongLong() { return params_.GetParam<unsigned long long>(); }
GetChar()153 intmax_t GetChar() { return params_.GetParam<int>(); }
GetSizeT()154 uintmax_t GetSizeT() { return params_.GetParam<GuestAddr>(); }
155
156 private:
157 GuestVAListParams params_;
158 };
159
TraceCallback(HostCode callee,ThreadState * state)160 void TraceCallback(HostCode callee, ThreadState* state) {
161 UNUSED(callee);
162
163 if (Tracing::IsOn()) {
164 auto [format] = GuestParamsValues<void(const char*, ...)>(state);
165 FormatBufferGuestParamsArgs args{GuestParamsValues<void(const char*, ...)>(state)};
166 Tracing::TraceA(format, &args);
167 }
168 }
169
PostInitCallback(HostCode callee,ThreadState * state)170 void PostInitCallback(HostCode callee, ThreadState* state) {
171 UNUSED(callee, state);
172
173 AppProcessPostInit();
174 }
175
InterceptGuestSymbolCallback(HostCode callee,ThreadState * state)176 void InterceptGuestSymbolCallback(HostCode callee, ThreadState* state) {
177 UNUSED(callee);
178
179 // Function prototype used here is the signature of native_bridge_intercept_symbol
180 auto [addr, lib_name, sym_name] =
181 GuestParamsValues<void(GuestAddr, const char*, const char* name)>(state);
182 InterceptGuestSymbol(addr, lib_name, sym_name, kProxyPrefix);
183 }
184
ConfigStaticTlsCallback(HostCode callee,ThreadState * state)185 void ConfigStaticTlsCallback(HostCode callee, ThreadState* state) {
186 UNUSED(callee);
187
188 auto [config] = GuestParamsValues<void(const NativeBridgeStaticTlsConfig*)>(state);
189 state->thread->ConfigStaticTls(config);
190 }
191
GetHostPthreadCallback(HostCode callee,ThreadState * state)192 void GetHostPthreadCallback(HostCode callee, ThreadState* state) {
193 UNUSED(callee);
194
195 auto&& [ret] = GuestReturnReference<decltype(pthread_self)>(state);
196 ret = pthread_self();
197 }
198
InitializeVdso(const LoadedElfFile & vdso_elf_file,std::string * error_msg)199 bool InitializeVdso(const LoadedElfFile& vdso_elf_file, std::string* error_msg) {
200 if (!MakeElfSymbolTrampolineCallable(
201 vdso_elf_file, "vdso", "native_bridge_trace", TraceCallback, nullptr, error_msg)) {
202 return false;
203 }
204
205 if (!MakeElfSymbolTrampolineCallable(vdso_elf_file,
206 "vdso",
207 "native_bridge_intercept_symbol",
208 InterceptGuestSymbolCallback,
209 nullptr,
210 error_msg)) {
211 return false;
212 }
213
214 if (!MakeElfSymbolTrampolineCallable(
215 vdso_elf_file, "vdso", "native_bridge_post_init", PostInitCallback, nullptr, error_msg)) {
216 return false;
217 }
218
219 void* call_guest_addr = vdso_elf_file.FindSymbol("native_bridge_call_guest");
220 if (call_guest_addr == nullptr) {
221 *error_msg = "couldn't find \"native_bridge_call_guest\" symbol in vdso";
222 return false;
223 }
224 InitVirtualGuestCallFrameReturnAddress(ToGuestAddr(call_guest_addr));
225
226 return true;
227 }
228
InitializeLinker(LinkerCallbacks * linker_callbacks,const LoadedElfFile & linker_elf_file,std::string * error_msg)229 bool InitializeLinker(LinkerCallbacks* linker_callbacks,
230 const LoadedElfFile& linker_elf_file,
231 std::string* error_msg) {
232 if (!MakeElfSymbolTrampolineCallable(linker_elf_file,
233 "linker",
234 "__native_bridge_config_static_tls",
235 ConfigStaticTlsCallback,
236 nullptr,
237 error_msg)) {
238 return false;
239 }
240
241 if (!MakeElfSymbolTrampolineCallable(linker_elf_file,
242 "linker",
243 "__native_bridge_get_host_pthread",
244 GetHostPthreadCallback,
245 nullptr,
246 error_msg)) {
247 return false;
248 }
249
250 return InitializeLinkerCallbacks(linker_callbacks, linker_elf_file, error_msg) &&
251 InitializeLinkerCallbacksArch(linker_callbacks, linker_elf_file, error_msg);
252 }
253
254 std::mutex g_guest_loader_instance_mtx;
255 GuestLoader* g_guest_loader_instance;
256
257 } // namespace
258
259 GuestLoader::GuestLoader() = default;
260
261 GuestLoader::~GuestLoader() = default;
262
CreateInstance(const char * main_executable_path,const char * vdso_path,const char * loader_path,std::string * error_msg)263 GuestLoader* GuestLoader::CreateInstance(const char* main_executable_path,
264 const char* vdso_path,
265 const char* loader_path,
266 std::string* error_msg) {
267 std::lock_guard<std::mutex> lock(g_guest_loader_instance_mtx);
268 CHECK(g_guest_loader_instance == nullptr);
269
270 TRACE(
271 "GuestLoader::CreateInstance(main_executable_path=\"%s\", "
272 "vdso_path=\"%s\", loader_path=\"%s\")",
273 main_executable_path,
274 vdso_path,
275 loader_path);
276
277 std::unique_ptr<GuestLoader> instance(new GuestLoader());
278
279 if (!TinyLoader::LoadFromFile(main_executable_path,
280 kLibraryAlignment,
281 &MmapForGuest,
282 &MunmapForGuest,
283 &instance->executable_elf_file_,
284 error_msg)) {
285 return nullptr;
286 }
287
288 // For readlink(/proc/self/exe).
289 SetMainExecutableRealPath(main_executable_path);
290
291 instance->main_executable_path_ = main_executable_path;
292 // Initialize caller_addr_ to executable entry point.
293 instance->caller_addr_ = instance->executable_elf_file_.entry_point();
294
295 // Real pt_interp is only used to distinguish static executables.
296 bool is_static_executable = (FindPtInterp(&instance->executable_elf_file_) == nullptr);
297
298 if (TinyLoader::LoadFromFile(vdso_path,
299 kLibraryAlignment,
300 &MmapForGuest,
301 &MunmapForGuest,
302 &instance->vdso_elf_file_,
303 error_msg)) {
304 if (!InitializeVdso(instance->vdso_elf_file_, error_msg)) {
305 return nullptr;
306 }
307 } else {
308 if (!is_static_executable) {
309 return nullptr;
310 }
311 }
312
313 if (is_static_executable) {
314 InitializeLinkerCallbacksToStubs(&instance->linker_callbacks_);
315 if (instance->executable_elf_file_.e_type() == ET_DYN) {
316 // Special case - ET_DYN executable without PT_INTERP, consider linker.
317 TRACE("pretend running linker as main executable");
318 if (!InitializeLinker(
319 &instance->linker_callbacks_, instance->executable_elf_file_, error_msg)) {
320 // Not the right linker, warn and hope for the best.
321 TRACE("failed to init main executable as linker, running as is");
322 }
323 }
324 } else {
325 if (!TinyLoader::LoadFromFile(loader_path,
326 kLibraryAlignment,
327 &MmapForGuest,
328 &MunmapForGuest,
329 &instance->linker_elf_file_,
330 error_msg)) {
331 return nullptr;
332 }
333 if (!InitializeLinker(&instance->linker_callbacks_, instance->linker_elf_file_, error_msg)) {
334 return nullptr;
335 }
336 InitLinkerDebug(instance->linker_elf_file_);
337 }
338
339 g_guest_loader_instance = instance.release();
340 return g_guest_loader_instance;
341 }
342
GetInstance()343 GuestLoader* GuestLoader::GetInstance() {
344 std::lock_guard<std::mutex> lock(g_guest_loader_instance_mtx);
345 CHECK(g_guest_loader_instance != nullptr);
346 return g_guest_loader_instance;
347 }
348
StartGuestMainThread()349 void GuestLoader::StartGuestMainThread() {
350 std::thread t(StartGuestExecutableImpl,
351 1,
352 &main_executable_path_,
353 environ,
354 &linker_elf_file_,
355 &executable_elf_file_,
356 &vdso_elf_file_);
357 t.detach();
358 WaitForAppProcess();
359 }
360
StartGuestExecutable(size_t argc,const char * argv[],char * envp[])361 void GuestLoader::StartGuestExecutable(size_t argc, const char* argv[], char* envp[]) {
362 StartGuestExecutableImpl(
363 argc, argv, envp, &linker_elf_file_, &executable_elf_file_, &vdso_elf_file_);
364 }
365
StartAppProcessInNewThread(std::string * error_msg)366 GuestLoader* GuestLoader::StartAppProcessInNewThread(std::string* error_msg) {
367 GuestLoader* instance = CreateInstance(kAppProcessPath, kVdsoPath, kPtInterpPath, error_msg);
368 if (instance) {
369 instance->StartGuestMainThread();
370 }
371 return instance;
372 }
373
StartExecutable(const char * main_executable_path,const char * vdso_path,const char * loader_path,size_t argc,const char * argv[],char * envp[],std::string * error_msg)374 void GuestLoader::StartExecutable(const char* main_executable_path,
375 const char* vdso_path,
376 const char* loader_path,
377 size_t argc,
378 const char* argv[],
379 char* envp[],
380 std::string* error_msg) {
381 GuestLoader* instance = CreateInstance(main_executable_path,
382 vdso_path ? vdso_path : kVdsoPath,
383 loader_path ? loader_path : kPtInterpPath,
384 error_msg);
385 if (instance) {
386 instance->StartGuestExecutable(argc, argv, envp);
387 }
388 }
389
FindRDebug() const390 const struct r_debug* GuestLoader::FindRDebug() const {
391 if (executable_elf_file_.is_loaded() && executable_elf_file_.dynamic() != nullptr) {
392 for (const ElfDyn* d = executable_elf_file_.dynamic(); d->d_tag != DT_NULL; ++d) {
393 if (d->d_tag == DT_DEBUG) {
394 return reinterpret_cast<const struct r_debug*>(d->d_un.d_val);
395 }
396 }
397 }
398
399 return nullptr;
400 }
401
MakeElfSymbolTrampolineCallable(const LoadedElfFile & elf_file,const char * elf_file_label,const char * symbol_name,void (* callback)(HostCode,ThreadState *),HostCode arg,std::string * error_msg)402 bool MakeElfSymbolTrampolineCallable(const LoadedElfFile& elf_file,
403 const char* elf_file_label,
404 const char* symbol_name,
405 void (*callback)(HostCode, ThreadState*),
406 HostCode arg,
407 std::string* error_msg) {
408 void* symbol_addr = elf_file.FindSymbol(symbol_name);
409 if (symbol_addr == nullptr) {
410 *error_msg = StringPrintf("couldn't find \"%s\" symbol in %s", symbol_name, elf_file_label);
411 return false;
412 }
413 MakeTrampolineCallable(ToGuestAddr(symbol_addr), false, callback, arg, symbol_name);
414 return true;
415 }
416
417 } // namespace berberis
418