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