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