• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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/base/exec_region_elf_backed.h"
18 
19 #include <android/dlext.h>
20 #include <dlfcn.h>
21 #include <sys/mman.h>
22 
23 #include "berberis/base/bit_util.h"
24 #include "berberis/base/fd.h"
25 #include "berberis/base/mmap.h"
26 
27 // Note that we have to use absolute path for ANDROID_DLEXT_FORCE_LOAD to work correctly
28 // otherwise searching by soname will trigger and the flag will have no effect.
29 #if defined(__LP64__)
30 const constexpr char* kExecRegionLibraryPath = "/system/lib64/libberberis_exec_region.so";
31 #else
32 const constexpr char* kExecRegionLibraryPath = "/system/lib/libberberis_exec_region.so";
33 #endif
34 
35 const constexpr char* kRegionStartSymbolName = "exec_region_start";
36 const constexpr char* kRegionEndSymbolName = "exec_region_end";
37 
38 namespace berberis {
39 
Create(size_t size)40 ExecRegion ExecRegionElfBackedFactory::Create(size_t size) {
41   size = AlignUpPageSize(size);
42 
43   android_dlextinfo dlextinfo{.flags = ANDROID_DLEXT_FORCE_LOAD};
44   void* handle = android_dlopen_ext(kExecRegionLibraryPath, RTLD_NOW, &dlextinfo);
45   if (handle == nullptr) {
46     FATAL("Couldn't load \"%s\": %s", kExecRegionLibraryPath, dlerror());
47   }
48   void* region_start = dlsym(handle, kRegionStartSymbolName);
49   CHECK(region_start != nullptr);
50   auto region_start_addr = bit_cast<uintptr_t>(region_start);
51   CHECK(region_start_addr % kPageSize == 0);
52 
53   void* region_end = dlsym(handle, kRegionEndSymbolName);
54   CHECK(region_end != nullptr);
55   auto region_end_addr = bit_cast<uintptr_t>(region_end);
56   CHECK(region_end_addr % kPageSize == 0);
57   size_t region_size = region_end_addr - region_start_addr;
58   CHECK_GE(region_size, size);
59 
60   auto fd = CreateMemfdOrDie("exec");
61   FtruncateOrDie(fd, static_cast<off64_t>(region_size));
62 
63   ExecRegion result{
64       static_cast<uint8_t*>(MmapImplOrDie({.addr = region_start,
65                                            .size = region_size,
66                                            .prot = PROT_READ | PROT_EXEC,
67                                            .flags = MAP_FIXED | MAP_SHARED,
68                                            .fd = fd})),
69       static_cast<uint8_t*>(MmapImplOrDie(
70           {.size = region_size, .prot = PROT_READ | PROT_WRITE, .flags = MAP_SHARED, .fd = fd})),
71       region_size};
72 
73   CloseUnsafe(fd);
74   return result;
75 }
76 
77 }  // namespace berberis
78