Remove symbol cache (#2872)

It only caches one symbol now, and thus is unnecessary to use cache
anymore
This commit is contained in:
LoveSy 2023-12-06 19:54:15 +08:00 committed by GitHub
parent 6acdd1cf6b
commit 42190f1fb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 8 additions and 345 deletions

View File

@ -32,25 +32,6 @@ namespace SandHook {
}
namespace lspd {
struct SymbolCache {
std::atomic_flag initialized{};
void *do_dlopen;
SymbolCache() = default;
SymbolCache(const SymbolCache &other) :
do_dlopen(other.do_dlopen) {}
SymbolCache &operator=(const SymbolCache &other) {
new(this)SymbolCache(other);
return *this;
}
};
extern std::unique_ptr<SymbolCache> symbol_cache;
void InitSymbolCache(SymbolCache *other);
std::unique_ptr<const SandHook::ElfImg> &GetArt(bool release=false);
}

View File

@ -24,13 +24,13 @@
#include "native_api.h"
#include "logging.h"
#include "symbol_cache.h"
#include "utils/hook_helper.hpp"
#include <sys/mman.h>
#include <dobby.h>
#include <list>
#include <dlfcn.h>
#include "native_util.h"
#include "elf_util.h"
/*
@ -133,9 +133,11 @@ namespace lspd {
});
bool InstallNativeAPI(const lsplant::HookHandler & handler) {
LOGD("InstallNativeAPI: {}", symbol_cache->do_dlopen);
if (symbol_cache->do_dlopen) [[likely]] {
HookSymNoHandle(handler, symbol_cache->do_dlopen, do_dlopen);
auto *do_dlopen_sym = SandHook::ElfImg("/linker").getSymbAddress(
"__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv");
LOGD("InstallNativeAPI: {}", do_dlopen_sym);
if (do_dlopen_sym) [[likely]] {
HookSymNoHandle(handler, do_dlopen_sym, do_dlopen);
return true;
}
return false;

View File

@ -31,8 +31,6 @@
#include <logging.h>
namespace lspd {
std::unique_ptr<SymbolCache> symbol_cache = std::make_unique<SymbolCache>();
std::unique_ptr<const SandHook::ElfImg> &GetArt(bool release) {
static std::unique_ptr<const SandHook::ElfImg> kArtImg = nullptr;
if (release) {
@ -42,22 +40,4 @@ namespace lspd {
}
return kArtImg;
}
void InitSymbolCache(SymbolCache *other) {
LOGD("InitSymbolCache");
if (other && other->initialized.test(std::memory_order_acquire)) {
LOGD("Already initialized");
*symbol_cache = *other;
symbol_cache->initialized.test_and_set(std::memory_order_relaxed);
return;
}
symbol_cache->do_dlopen = SandHook::ElfImg("/linker").getSymbAddress(
"__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv");
symbol_cache->initialized.test_and_set(std::memory_order_relaxed);
if (other) {
*other = *symbol_cache;
other->initialized.test_and_set(std::memory_order_acq_rel);
}
}
} // namespace lspd

View File

@ -42,7 +42,6 @@ namespace lspd {
void onModuleLoaded() {
LOGI("onModuleLoaded: welcome to LSPosed!");
LOGI("onModuleLoaded: version v{} ({})", versionName, versionCode);
InitSymbolCache(nullptr);
MagiskLoader::Init();
ConfigImpl::Init();
}

View File

@ -30,251 +30,9 @@
#include "symbol_cache.h"
namespace lspd {
namespace {
ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags) {
int sent = sendmsg(sockfd, msg, flags);
if (sent < 0) {
PLOGE("sendmsg");
}
return sent;
}
ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
int rec = recvmsg(sockfd, msg, flags);
if (rec < 0) {
PLOGE("recvmsg");
}
return rec;
}
// Read exact same size as count
ssize_t xxread(int fd, void *buf, size_t count) {
size_t read_sz = 0;
ssize_t ret;
do {
ret = read(fd, (std::byte *) buf + read_sz, count - read_sz);
if (ret < 0) {
if (errno == EINTR)
continue;
PLOGE("read");
return ret;
}
read_sz += ret;
} while (read_sz != count && ret != 0);
if (read_sz != count) {
PLOGE("read ({} != {})", count, read_sz);
}
return read_sz;
}
// Write exact same size as count
ssize_t xwrite(int fd, const void *buf, size_t count) {
size_t write_sz = 0;
ssize_t ret;
do {
ret = write(fd, (std::byte *) buf + write_sz, count - write_sz);
if (ret < 0) {
if (errno == EINTR)
continue;
PLOGE("write");
return ret;
}
write_sz += ret;
} while (write_sz != count && ret != 0);
if (write_sz != count) {
PLOGE("write ({} != {})", count, write_sz);
}
return write_sz;
}
int send_fds(int sockfd, void *cmsgbuf, size_t bufsz, const int *fds, int cnt) {
iovec iov = {
.iov_base = &cnt,
.iov_len = sizeof(cnt),
};
msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
};
if (cnt) {
msg.msg_control = cmsgbuf;
msg.msg_controllen = bufsz;
cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * cnt);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * cnt);
}
return xsendmsg(sockfd, &msg, 0);
}
int send_fd(int sockfd, int fd) {
if (fd < 0) {
return send_fds(sockfd, nullptr, 0, nullptr, 0);
}
char cmsgbuf[CMSG_SPACE(sizeof(int))];
return send_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), &fd, 1);
}
void *recv_fds(int sockfd, char *cmsgbuf, size_t bufsz, int cnt) {
iovec iov = {
.iov_base = &cnt,
.iov_len = sizeof(cnt),
};
msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = cmsgbuf,
.msg_controllen = bufsz
};
xrecvmsg(sockfd, &msg, MSG_WAITALL);
cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
if (msg.msg_controllen != bufsz ||
cmsg == nullptr ||
cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) ||
cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS) {
return nullptr;
}
return CMSG_DATA(cmsg);
}
int recv_fd(int sockfd) {
char cmsgbuf[CMSG_SPACE(sizeof(int))];
void *data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
if (data == nullptr)
return -1;
int result;
memcpy(&result, data, sizeof(int));
return result;
}
int read_int(int fd) {
int val;
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
return -1;
return val;
}
void write_int(int fd, int val) {
if (fd < 0) return;
xwrite(fd, &val, sizeof(val));
}
int allow_unload = 0;
}
int allow_unload = 0;
int *allowUnload = &allow_unload;
class SharedMem {
inline static void *cutils = nullptr;
inline static int (*ashmem_create_region)(const char *name, std::size_t size) = nullptr;
inline static int (*ashmem_set_prot_region)(int fd, int prot) = nullptr;
inline static bool init = false;
static void Init() {
if (init) return;
cutils = dlopen("/system/lib" LP_SELECT("", "64") "/libcutils.so", 0);
ashmem_create_region = cutils ? reinterpret_cast<decltype(ashmem_create_region)>(
dlsym(cutils, "ashmem_create_region")) : nullptr;
ashmem_set_prot_region = cutils ? reinterpret_cast<decltype(ashmem_set_prot_region)>(
dlsym(cutils, "ashmem_set_prot_region")) : nullptr;
init = true;
}
int fd_ = -1;
std::size_t size_ = 0;
class MappedMem {
void *addr_ = nullptr;
std::size_t size_ = 0;
friend class SharedMem;
MappedMem(int fd, std::size_t size, int prot, int flags, off_t offset) : addr_(
mmap(nullptr, size, prot, flags, fd, offset)), size_(size) {
if (addr_ == MAP_FAILED) {
PLOGE("failed to mmap");
addr_ = nullptr;
size_ = 0;
}
}
MappedMem(const MappedMem &) = delete;
MappedMem &operator=(const MappedMem &other) = delete;
public:
MappedMem(MappedMem &&other) : addr_(other.addr_), size_(other.size_) {
other.addr_ = nullptr;
other.size_ = 0;
}
MappedMem &operator=(MappedMem &&other) {
new(this)MappedMem(std::move(other));
return *this;
}
constexpr operator bool() { return addr_; }
~MappedMem() {
if (addr_) {
munmap(addr_, size_);
}
}
constexpr auto size() const { return size_; }
constexpr auto get() const { return addr_; }
};
public:
MappedMem map(int prot, int flags, off_t offset) {
return {fd_, size_, prot, flags, offset};
}
constexpr bool ok() const { return fd_ > 0 && size_ > 0; }
SharedMem(std::string_view name, std::size_t size) {
Init();
if (ashmem_create_region && (fd_ = ashmem_create_region(name.data(), size)) > 0) {
size_ = size;
LOGD("using memfd");
} else {
LOGD("using tmp file");
auto *tmp = tmpfile();
if (tmp) {
fd_ = fileno(tmp);
ftruncate(fd_, size);
size_ = size;
}
}
}
void SetProt(int prot) {
ashmem_set_prot_region(fd_, prot);
}
SharedMem() : fd_(-1), size_(0) {
Init();
}
constexpr auto get() const { return fd_; }
constexpr auto size() const { return size_; }
};
class ZygiskModule : public zygisk::ModuleBase {
JNIEnv *env_;
zygisk::Api *api_;
@ -284,29 +42,6 @@ namespace lspd {
api_ = api;
MagiskLoader::Init();
ConfigImpl::Init();
auto companion = api->connectCompanion();
if (companion == -1) {
LOGE("Failed to connect to companion");
return;
}
if (int fd = -1, size = 0; (size = read_int(companion)) > 0 &&
(fd = recv_fd(companion)) != -1) {
if (auto addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
addr && addr != MAP_FAILED) {
InitSymbolCache(reinterpret_cast<SymbolCache *>(addr));
msync(addr, size, MS_SYNC);
munmap(addr, size);
} else {
InitSymbolCache(nullptr);
}
close(fd);
} else {
LOGE("Failed to read symbol fd");
InitSymbolCache(nullptr);
}
close(companion);
}
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
@ -338,36 +73,6 @@ namespace lspd {
if (*allowUnload) api_->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
}
};
SharedMem InitCompanion() {
LOGI("ZygiskCompanion: welcome to LSPosed!");
LOGI("ZygiskCompanion: version v{} ({})", versionName, versionCode);
SharedMem symbol{"symbol", sizeof(lspd::SymbolCache)};
if (!symbol.ok()) {
PLOGE("Failed to allocate shared mem");
return {};
}
if (auto symbol_map = symbol.map(PROT_WRITE, MAP_SHARED, 0); symbol_map) {
memcpy(symbol_map.get(), lspd::symbol_cache.get(), symbol_map.size());
}
return symbol;
}
void CompanionEntry(int client) {
using namespace std::string_literals;
static auto symbol = InitCompanion();
LOGD("Got cache with fd={} size={}", symbol.get(), symbol.size());
if (symbol.ok()) {
write_int(client, symbol.size());
send_fd(client, symbol.get());
} else write_int(client, -1);
close(client);
}
} //namespace lspd
REGISTER_ZYGISK_MODULE(lspd::ZygiskModule);
REGISTER_ZYGISK_COMPANION(lspd::CompanionEntry);

View File

@ -89,10 +89,6 @@ namespace lspd {
void
MagiskLoader::OnNativeForkSystemServerPre(JNIEnv *env) {
Service::instance()->InitService(env);
skip_ = !symbol_cache->initialized.test(std::memory_order_acquire);
if (skip_) [[unlikely]] {
LOGW("skip system server due to symbol cache");
}
setAllowUnload(skip_);
}
@ -167,7 +163,7 @@ namespace lspd {
Service::instance()->InitService(env);
const auto app_id = uid % PER_USER_RANGE;
JUTFString process_name(env, nice_name);
skip_ = !symbol_cache->initialized.test(std::memory_order_acquire);
skip_ = false;
if (!skip_ && !app_data_dir) {
LOGD("skip injecting into {} because it has no data dir", process_name.get());
skip_ = true;