You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
fix: zygiskd companion, companion responses, write fd function and early client close
This commit fixes numerous issues in zygiskd code: The zygiskd companion code not loading the right entry, the companion not sending the correct responses, the write fd function not working properly and early client close when connecting to the companion.
This commit is contained in:
@@ -1,221 +1,263 @@
|
|||||||
#include <linux/un.h>
|
#include <linux/un.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "daemon.h"
|
#include "daemon.h"
|
||||||
#include "dl.h"
|
#include "dl.h"
|
||||||
#include "socket_utils.h"
|
#include "socket_utils.h"
|
||||||
|
|
||||||
namespace zygiskd {
|
namespace zygiskd {
|
||||||
static std::string TMP_PATH;
|
static std::string TMP_PATH;
|
||||||
void Init(const char *path) {
|
void Init(const char *path) {
|
||||||
TMP_PATH = path;
|
TMP_PATH = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetTmpPath() {
|
||||||
|
return TMP_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Connect(uint8_t retry) {
|
||||||
|
retry++;
|
||||||
|
|
||||||
|
int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||||
|
struct sockaddr_un addr = {
|
||||||
|
.sun_family = AF_UNIX,
|
||||||
|
.sun_path = { 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
auto socket_path = TMP_PATH + kCPSocketName;
|
||||||
|
strcpy(addr.sun_path, socket_path.c_str());
|
||||||
|
socklen_t socklen = sizeof(addr);
|
||||||
|
|
||||||
|
while (--retry) {
|
||||||
|
int r = connect(fd, (struct sockaddr *)&addr, socklen);
|
||||||
|
if (r == 0) return fd;
|
||||||
|
if (retry) {
|
||||||
|
PLOGE("Retrying to connect to zygiskd, sleep 1s");
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetTmpPath() {
|
close(fd);
|
||||||
return TMP_PATH;
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PingHeartbeat() {
|
||||||
|
int fd = Connect(5);
|
||||||
|
if (fd == -1) {
|
||||||
|
PLOGE("Connect to zygiskd");
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Connect(uint8_t retry) {
|
socket_utils::write_u8(fd, (uint8_t) SocketAction::PingHeartBeat);
|
||||||
int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
|
||||||
struct sockaddr_un addr = {
|
|
||||||
.sun_family = AF_UNIX,
|
|
||||||
.sun_path = { 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
auto socket_path = TMP_PATH + kCPSocketName;
|
close(fd);
|
||||||
strcpy(addr.sun_path, socket_path.c_str());
|
|
||||||
socklen_t socklen = sizeof(addr);
|
|
||||||
|
|
||||||
while (retry--) {
|
return true;
|
||||||
int r = connect(fd, reinterpret_cast<struct sockaddr*>(&addr), socklen);
|
}
|
||||||
if (r == 0) return fd;
|
|
||||||
if (retry) {
|
int RequestLogcatFd() {
|
||||||
PLOGE("Retrying to connect to zygiskd, sleep 1s");
|
int fd = Connect(1);
|
||||||
sleep(1);
|
if (fd == -1) {
|
||||||
}
|
PLOGE("RequestLogcatFd");
|
||||||
}
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_utils::write_u8(fd, (uint8_t) SocketAction::RequestLogcatFd);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetProcessFlags(uid_t uid) {
|
||||||
|
int fd = Connect(1);
|
||||||
|
if (fd == -1) {
|
||||||
|
PLOGE("GetProcessFlags");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetProcessFlags);
|
||||||
|
socket_utils::write_u32(fd, uid);
|
||||||
|
|
||||||
|
uint32_t res = socket_utils::read_u32(fd);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Module> ReadModules() {
|
||||||
|
std::vector<Module> modules;
|
||||||
|
int fd = Connect(1);
|
||||||
|
if (fd == -1) {
|
||||||
|
PLOGE("ReadModules");
|
||||||
|
|
||||||
|
return modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_utils::write_u8(fd, (uint8_t) SocketAction::ReadModules);
|
||||||
|
size_t len = socket_utils::read_usize(fd);
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
std::string name = socket_utils::read_string(fd);
|
||||||
|
int module_fd = socket_utils::recv_fd(fd);
|
||||||
|
modules.emplace_back(name, module_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectCompanion(size_t index) {
|
||||||
|
int fd = Connect(1);
|
||||||
|
if (fd == -1) {
|
||||||
|
PLOGE("ConnectCompanion");
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_utils::write_u8(fd, (uint8_t) SocketAction::RequestCompanionSocket);
|
||||||
|
socket_utils::write_usize(fd, index);
|
||||||
|
|
||||||
|
uint8_t res = socket_utils::read_u8(fd);
|
||||||
|
|
||||||
|
if (res == 1) return fd;
|
||||||
|
else {
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetModuleDir(size_t index) {
|
||||||
|
int fd = Connect(1);
|
||||||
|
if (fd == -1) {
|
||||||
|
PLOGE("GetModuleDir");
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetModuleDir);
|
||||||
|
socket_utils::write_usize(fd, index);
|
||||||
|
int nfd = socket_utils::recv_fd(fd);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return nfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZygoteRestart() {
|
||||||
|
int fd = Connect(1);
|
||||||
|
if (fd == -1) {
|
||||||
|
if (errno == ENOENT) LOGD("Could not notify ZygoteRestart (maybe it hasn't been created)");
|
||||||
|
else PLOGE("Could not notify ZygoteRestart");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!socket_utils::write_u8(fd, (uint8_t) SocketAction::ZygoteRestart))
|
||||||
|
PLOGE("Failed to request ZygoteRestart");
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemServerStarted() {
|
||||||
|
int fd = Connect(1);
|
||||||
|
if (fd == -1) PLOGE("Failed to report system server started");
|
||||||
|
else {
|
||||||
|
if (!socket_utils::write_u8(fd, (uint8_t) SocketAction::SystemServerStarted))
|
||||||
|
PLOGE("Failed to report system server started");
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetInfo(struct zygote_info *info) {
|
||||||
|
/* TODO: Optimize and avoid re-connect twice here */
|
||||||
|
int fd = Connect(1);
|
||||||
|
|
||||||
|
if (fd != -1) {
|
||||||
|
info->running = true;
|
||||||
|
|
||||||
|
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetInfo);
|
||||||
|
|
||||||
|
int flags = socket_utils::read_u32(fd);
|
||||||
|
|
||||||
|
if (flags & (1 << 27)) {
|
||||||
|
info->root_impl = ZYGOTE_ROOT_IMPL_APATCH;
|
||||||
|
} else if (flags & (1 << 29)) {
|
||||||
|
info->root_impl = ZYGOTE_ROOT_IMPL_KERNELSU;
|
||||||
|
} else if (flags & (1 << 30)) {
|
||||||
|
info->root_impl = ZYGOTE_ROOT_IMPL_MAGISK;
|
||||||
|
} else {
|
||||||
|
info->root_impl = ZYGOTE_ROOT_IMPL_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->pid = socket_utils::read_u32(fd);
|
||||||
|
|
||||||
|
info->modules = (struct zygote_modules *)malloc(sizeof(struct zygote_modules));
|
||||||
|
if (info->modules == NULL) {
|
||||||
|
info->modules->modules_count = 0;
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PingHeartbeat() {
|
return;
|
||||||
UniqueFd fd = Connect(5);
|
}
|
||||||
if (fd == -1) {
|
|
||||||
PLOGE("Connect to zygiskd");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::PingHeartBeat);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int RequestLogcatFd() {
|
info->modules->modules_count = socket_utils::read_usize(fd);
|
||||||
int fd = Connect(1);
|
|
||||||
if (fd == -1) {
|
|
||||||
PLOGE("RequestLogcatFd");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::RequestLogcatFd);
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t GetProcessFlags(uid_t uid) {
|
if (info->modules->modules_count == 0) {
|
||||||
UniqueFd fd = Connect(1);
|
info->modules->modules = NULL;
|
||||||
if (fd == -1) {
|
|
||||||
PLOGE("GetProcessFlags");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetProcessFlags);
|
|
||||||
socket_utils::write_u32(fd, uid);
|
|
||||||
|
|
||||||
return socket_utils::read_u32(fd);
|
close(fd);
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Module> ReadModules() {
|
return;
|
||||||
std::vector<Module> modules;
|
}
|
||||||
UniqueFd fd = Connect(1);
|
|
||||||
if (fd == -1) {
|
|
||||||
PLOGE("ReadModules");
|
|
||||||
return modules;
|
|
||||||
}
|
|
||||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::ReadModules);
|
|
||||||
size_t len = socket_utils::read_usize(fd);
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
|
||||||
std::string name = socket_utils::read_string(fd);
|
|
||||||
int module_fd = socket_utils::recv_fd(fd);
|
|
||||||
modules.emplace_back(name, module_fd);
|
|
||||||
}
|
|
||||||
return modules;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConnectCompanion(size_t index) {
|
info->modules->modules = (char **)malloc(sizeof(char *) * info->modules->modules_count);
|
||||||
int fd = Connect(1);
|
if (info->modules->modules == NULL) {
|
||||||
if (fd == -1) {
|
free(info->modules);
|
||||||
PLOGE("ConnectCompanion");
|
info->modules = NULL;
|
||||||
return -1;
|
info->modules->modules_count = 0;
|
||||||
}
|
|
||||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::RequestCompanionSocket);
|
close(fd);
|
||||||
socket_utils::write_usize(fd, index);
|
|
||||||
if (socket_utils::read_u8(fd) == 1) {
|
return;
|
||||||
return fd;
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < info->modules->modules_count; i++) {
|
||||||
|
/* INFO by ThePedroo: Ugly solution to read with std::string existance (temporary) */
|
||||||
|
std::string name = socket_utils::read_string(fd);
|
||||||
|
|
||||||
|
char module_path[PATH_MAX];
|
||||||
|
snprintf(module_path, sizeof(module_path), "/data/adb/modules/%s/module.prop", name.c_str());
|
||||||
|
|
||||||
|
FILE *module_prop = fopen(module_path, "r");
|
||||||
|
if (module_prop == NULL) {
|
||||||
|
info->modules->modules[i] = strdup(name.c_str());
|
||||||
} else {
|
} else {
|
||||||
close(fd);
|
char line[1024];
|
||||||
return -1;
|
while (fgets(line, sizeof(line), module_prop) != NULL) {
|
||||||
}
|
if (strncmp(line, "name=", 5) == 0) {
|
||||||
}
|
info->modules->modules[i] = strndup(line + 5, strlen(line) - 6);
|
||||||
|
|
||||||
int GetModuleDir(size_t index) {
|
break;
|
||||||
UniqueFd fd = Connect(1);
|
|
||||||
if (fd == -1) {
|
|
||||||
PLOGE("GetModuleDir");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetModuleDir);
|
|
||||||
socket_utils::write_usize(fd, index);
|
|
||||||
return socket_utils::recv_fd(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZygoteRestart() {
|
|
||||||
UniqueFd fd = Connect(1);
|
|
||||||
if (fd == -1) {
|
|
||||||
if (errno == ENOENT) {
|
|
||||||
LOGD("Could not notify ZygoteRestart (maybe it hasn't been created)");
|
|
||||||
} else {
|
|
||||||
PLOGE("Could not notify ZygoteRestart");
|
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!socket_utils::write_u8(fd, (uint8_t) SocketAction::ZygoteRestart)) {
|
|
||||||
PLOGE("Failed to request ZygoteRestart");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemServerStarted() {
|
|
||||||
UniqueFd fd = Connect(1);
|
|
||||||
if (fd == -1) {
|
|
||||||
PLOGE("Failed to report system server started");
|
|
||||||
} else {
|
|
||||||
if (!socket_utils::write_u8(fd, (uint8_t) SocketAction::SystemServerStarted)) {
|
|
||||||
PLOGE("Failed to report system server started");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetInfo(struct zygote_info *info) {
|
|
||||||
/* TODO: Optimize and avoid re-connect twice here */
|
|
||||||
int fd = Connect(1);
|
|
||||||
|
|
||||||
if (fd != -1) {
|
|
||||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetInfo);
|
|
||||||
|
|
||||||
int flags = socket_utils::read_u32(fd);
|
|
||||||
|
|
||||||
if (flags & (1 << 27)) {
|
|
||||||
info->root_impl = ZYGOTE_ROOT_IMPL_APATCH;
|
|
||||||
} else if (flags & (1 << 29)) {
|
|
||||||
info->root_impl = ZYGOTE_ROOT_IMPL_KERNELSU;
|
|
||||||
} else if (flags & (1 << 30)) {
|
|
||||||
info->root_impl = ZYGOTE_ROOT_IMPL_MAGISK;
|
|
||||||
} else {
|
|
||||||
info->root_impl = ZYGOTE_ROOT_IMPL_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
info->modules = (struct zygote_modules *)malloc(sizeof(struct zygote_modules));
|
|
||||||
if (info->modules == NULL) {
|
|
||||||
info->modules->modules_count = 0;
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
info->modules->modules_count = socket_utils::read_usize(fd);
|
|
||||||
|
|
||||||
if (info->modules->modules_count == 0) {
|
|
||||||
info->modules->modules = NULL;
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
info->modules->modules = (char **)malloc(sizeof(char *) * info->modules->modules_count);
|
|
||||||
if (info->modules->modules == NULL) {
|
|
||||||
free(info->modules);
|
|
||||||
info->modules = NULL;
|
|
||||||
info->modules->modules_count = 0;
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < info->modules->modules_count; i++) {
|
|
||||||
/* INFO by ThePedroo: Ugly solution to read with std::string existance (temporary) */
|
|
||||||
std::string name = socket_utils::read_string(fd);
|
|
||||||
|
|
||||||
char module_path[PATH_MAX];
|
|
||||||
snprintf(module_path, sizeof(module_path), "/data/adb/modules/%s/module.prop", name.c_str());
|
|
||||||
|
|
||||||
FILE *module_prop = fopen(module_path, "r");
|
|
||||||
if (module_prop == NULL) {
|
|
||||||
info->modules->modules[i] = strdup(name.c_str());
|
|
||||||
} else {
|
|
||||||
char line[1024];
|
|
||||||
while (fgets(line, sizeof(line), module_prop) != NULL) {
|
|
||||||
if (strncmp(line, "name=", 5) == 0) {
|
|
||||||
info->modules->modules[i] = strndup(line + 5, strlen(line) - 6);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(module_prop);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
close(fd);
|
fclose(module_prop);
|
||||||
} else info->running = false;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
} else info->running = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,131 +5,133 @@
|
|||||||
#include "socket_utils.h"
|
#include "socket_utils.h"
|
||||||
|
|
||||||
namespace socket_utils {
|
namespace socket_utils {
|
||||||
|
ssize_t xread(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 (%zu != %zu)", count, read_sz);
|
||||||
|
}
|
||||||
|
return read_sz;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t xread(int fd, void* buf, size_t count) {
|
size_t xwrite(int fd, const void* buf, size_t count) {
|
||||||
size_t read_sz = 0;
|
size_t write_sz = 0;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
do {
|
do {
|
||||||
ret = read(fd, (std::byte*) buf + read_sz, count - read_sz);
|
ret = write(fd, (std::byte*) buf + write_sz, count - write_sz);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno == EINTR) continue;
|
if (errno == EINTR) continue;
|
||||||
PLOGE("read");
|
PLOGE("write");
|
||||||
return ret;
|
return write_sz;
|
||||||
}
|
|
||||||
read_sz += ret;
|
|
||||||
} while (read_sz != count && ret != 0);
|
|
||||||
if (read_sz != count) {
|
|
||||||
PLOGE("read (%zu != %zu)", count, read_sz);
|
|
||||||
}
|
}
|
||||||
return read_sz;
|
write_sz += ret;
|
||||||
|
} while (write_sz != count && ret != 0);
|
||||||
|
if (write_sz != count) {
|
||||||
|
PLOGE("write (%zu != %zu)", count, write_sz);
|
||||||
}
|
}
|
||||||
|
return write_sz;
|
||||||
|
}
|
||||||
|
|
||||||
size_t xwrite(int fd, const void* buf, size_t count) {
|
ssize_t xrecvmsg(int sockfd, struct msghdr* msg, int flags) {
|
||||||
size_t write_sz = 0;
|
int rec = recvmsg(sockfd, msg, flags);
|
||||||
ssize_t ret;
|
if (rec < 0) PLOGE("recvmsg");
|
||||||
do {
|
return rec;
|
||||||
ret = write(fd, (std::byte*) buf + write_sz, count - write_sz);
|
}
|
||||||
if (ret < 0) {
|
|
||||||
if (errno == EINTR) continue;
|
|
||||||
PLOGE("write");
|
|
||||||
return write_sz;
|
|
||||||
}
|
|
||||||
write_sz += ret;
|
|
||||||
} while (write_sz != count && ret != 0);
|
|
||||||
if (write_sz != count) {
|
|
||||||
PLOGE("write (%zu != %zu)", count, write_sz);
|
|
||||||
}
|
|
||||||
return write_sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t xrecvmsg(int sockfd, struct msghdr* msg, int flags) {
|
template<typename T>
|
||||||
int rec = recvmsg(sockfd, msg, flags);
|
inline T read_exact_or(int fd, T fail) {
|
||||||
if (rec < 0) PLOGE("recvmsg");
|
T res;
|
||||||
return rec;
|
return sizeof(T) == xread(fd, &res, sizeof(T)) ? res : fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* recv_fds(int sockfd, char* cmsgbuf, size_t bufsz, int cnt) {
|
template<typename T>
|
||||||
iovec iov = {
|
inline bool write_exact(int fd, T val) {
|
||||||
.iov_base = &cnt,
|
return sizeof(T) == xwrite(fd, &val, sizeof(T));
|
||||||
.iov_len = sizeof(cnt),
|
}
|
||||||
};
|
|
||||||
msghdr msg = {
|
|
||||||
.msg_iov = &iov,
|
|
||||||
.msg_iovlen = 1,
|
|
||||||
.msg_control = cmsgbuf,
|
|
||||||
.msg_controllen = bufsz
|
|
||||||
};
|
|
||||||
|
|
||||||
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
uint8_t read_u8(int fd) {
|
||||||
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
|
return read_exact_or<uint8_t>(fd, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (msg.msg_controllen != bufsz ||
|
uint32_t read_u32(int fd) {
|
||||||
cmsg == nullptr ||
|
return read_exact_or<uint32_t>(fd, 0);
|
||||||
// TODO: pass from rust: 20, expected: 16
|
}
|
||||||
// cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) ||
|
|
||||||
cmsg->cmsg_level != SOL_SOCKET ||
|
|
||||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CMSG_DATA(cmsg);
|
size_t read_usize(int fd) {
|
||||||
}
|
return read_exact_or<size_t>(fd, 0);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
bool write_usize(int fd, size_t val) {
|
||||||
inline T read_exact_or(int fd, T fail) {
|
return write_exact<size_t>(fd, val);
|
||||||
T res;
|
}
|
||||||
return sizeof(T) == xread(fd, &res, sizeof(T)) ? res : fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
std::string read_string(int fd) {
|
||||||
inline bool write_exact(int fd, T val) {
|
size_t len = read_usize(fd);
|
||||||
return sizeof(T) == xwrite(fd, &val, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t read_u8(int fd) {
|
char buf[len + 1];
|
||||||
return read_exact_or<uint8_t>(fd, 0);
|
xread(fd, buf, len);
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t read_u32(int fd) {
|
buf[len] = '\0';
|
||||||
return read_exact_or<uint32_t>(fd, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t read_usize(int fd) {
|
return buf;
|
||||||
return read_exact_or<size_t>(fd, 0);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool write_usize(int fd, size_t val) {
|
bool write_u8(int fd, uint8_t val) {
|
||||||
return write_exact<size_t>(fd, val);
|
return write_exact<uint8_t>(fd, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string read_string(int fd) {
|
void* recv_fds(int sockfd, char* cmsgbuf, size_t bufsz, int cnt) {
|
||||||
auto len = read_usize(fd);
|
iovec iov = {
|
||||||
char buf[len + 1];
|
.iov_base = &cnt,
|
||||||
buf[len] = '\0';
|
.iov_len = sizeof(cnt),
|
||||||
xread(fd, buf, len);
|
};
|
||||||
return buf;
|
msghdr msg = {
|
||||||
}
|
.msg_iov = &iov,
|
||||||
|
.msg_iovlen = 1,
|
||||||
|
.msg_control = cmsgbuf,
|
||||||
|
.msg_controllen = bufsz
|
||||||
|
};
|
||||||
|
|
||||||
bool write_u8(int fd, uint8_t val) {
|
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
||||||
return write_exact<uint8_t>(fd, val);
|
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
|
||||||
}
|
|
||||||
|
|
||||||
bool write_u32(int fd, uint32_t val) {
|
if (msg.msg_controllen != bufsz ||
|
||||||
return write_exact<uint32_t>(fd, val);
|
cmsg == nullptr ||
|
||||||
}
|
// TODO: pass from rust: 20, expected: 16
|
||||||
|
// cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) ||
|
||||||
|
cmsg->cmsg_level != SOL_SOCKET ||
|
||||||
|
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool write_string(int fd, std::string_view str) {
|
return CMSG_DATA(cmsg);
|
||||||
return write_usize(fd, str.size()) && str.size() == xwrite(fd, str.data(), str.size());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int recv_fd(int sockfd) {
|
int recv_fd(int sockfd) {
|
||||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||||
|
|
||||||
void* data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
|
void* data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
|
||||||
if (data == nullptr) return -1;
|
if (data == nullptr) return -1;
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
memcpy(&result, data, sizeof(int));
|
memcpy(&result, data, sizeof(int));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool write_u32(int fd, uint32_t val) {
|
||||||
|
return write_exact<uint32_t>(fd, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool write_string(int fd, std::string_view str) {
|
||||||
|
return write_usize(fd, str.size()) && str.size() == xwrite(fd, str.data(), str.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ fun getLatestNDKPath(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get 2nd latest version
|
// get 2nd latest version
|
||||||
val ndkVersion = ndkDir.toFile().listFiles().filter { it.isDirectory }.map { it.name }.sorted().reversed().getOrNull(1)
|
val ndkVersion = ndkDir.toFile().listFiles().filter { it.isDirectory }.map { it.name }.sorted().reversed().getOrNull(2)
|
||||||
return ndkPath + "/" + ndkVersion
|
return ndkPath + "/" + ndkVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
@@ -19,6 +20,11 @@
|
|||||||
|
|
||||||
typedef void (*zygisk_companion_entry_func)(int);
|
typedef void (*zygisk_companion_entry_func)(int);
|
||||||
|
|
||||||
|
struct companion_module_thread_args {
|
||||||
|
int fd;
|
||||||
|
zygisk_companion_entry_func entry;
|
||||||
|
};
|
||||||
|
|
||||||
zygisk_companion_entry_func load_module(int fd) {
|
zygisk_companion_entry_func load_module(int fd) {
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
|
snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
|
||||||
@@ -30,101 +36,100 @@ zygisk_companion_entry_func load_module(int fd) {
|
|||||||
return (zygisk_companion_entry_func)entry;
|
return (zygisk_companion_entry_func)entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *call_entry(void *restrict arg) {
|
void *entry_thread(void *arg) {
|
||||||
int fd = *((int *)arg);
|
struct companion_module_thread_args *args = (struct companion_module_thread_args *)arg;
|
||||||
|
|
||||||
|
int fd = args->fd;
|
||||||
|
zygisk_companion_entry_func module_entry = args->entry;
|
||||||
|
|
||||||
struct stat st0;
|
struct stat st0;
|
||||||
if (fstat(fd, &st0) == -1) {
|
fstat(fd, &st0);
|
||||||
LOGE("Failed to stat client fd\n");
|
|
||||||
|
|
||||||
free(arg);
|
LOGI("New companion thread (inside the thread!).\n - Client fd: %d\n", fd);
|
||||||
|
|
||||||
exit(0);
|
module_entry(fd);
|
||||||
}
|
|
||||||
entry(fd);
|
|
||||||
|
|
||||||
// Only close client if it is the same file so we don't
|
/* TODO: Is this even necessary? */
|
||||||
// accidentally close a re-used file descriptor.
|
|
||||||
// This check is required because the module companion
|
|
||||||
// handler could've closed the file descriptor already.
|
|
||||||
struct stat st1;
|
struct stat st1;
|
||||||
if (fstat(fd, &st1) == -1) {
|
if (fstat(fd, &st1) != -1) {
|
||||||
LOGE("Failed to stat client fd\n");
|
if (st0.st_dev != st1.st_dev || st0.st_ino != st1.st_ino) {
|
||||||
|
close(fd);
|
||||||
|
|
||||||
free(arg);
|
LOGI("Client fd has been replaced. Bye!\n");
|
||||||
|
}
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st0.st_dev != st1.st_dev || st0.st_ino != st1.st_ino) {
|
free(args);
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(arg);
|
pthread_exit(NULL);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entry(int fd) {
|
void entry(int fd) {
|
||||||
LOGI("companion entry fd: |%d|\n", fd);
|
LOGI("New companion entry.\n - Client fd: %d\n", fd);
|
||||||
|
|
||||||
char name[256 + 1];
|
char name[256];
|
||||||
ssize_t ret = read_string(fd, name, sizeof(name) - 1);
|
ssize_t ret = read_string(fd, name, sizeof(name));
|
||||||
if (ret == -1) return;
|
if (ret == -1) {
|
||||||
|
LOGE("Failed to read module name\n");
|
||||||
|
|
||||||
name[ret] = '\0';
|
uint8_t response = 2;
|
||||||
|
|
||||||
LOGI("Companion process requested for `%s`\n", name);
|
|
||||||
|
|
||||||
int library_fd;
|
|
||||||
recv_fd(fd, &library_fd);
|
|
||||||
|
|
||||||
LOGI("Library fd: %d\n", library_fd);
|
|
||||||
|
|
||||||
zygisk_companion_entry_func entry = load_module(library_fd);
|
|
||||||
|
|
||||||
LOGI("Library loaded\n");
|
|
||||||
|
|
||||||
close(library_fd);
|
|
||||||
|
|
||||||
LOGI("Library closed\n");
|
|
||||||
|
|
||||||
if (entry == NULL) {
|
|
||||||
LOGI("No companion entry for: %s\n", name);
|
|
||||||
|
|
||||||
uint8_t response = 0;
|
|
||||||
write(fd, &response, sizeof(response));
|
write(fd, &response, sizeof(response));
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Companion process created for: %s\n", name);
|
LOGI(" - Module name: `%.*s`\n", (int)ret, name);
|
||||||
|
|
||||||
uint8_t response = 1;
|
int library_fd = gread_fd(fd);
|
||||||
write(fd, &response, sizeof(response));
|
if (library_fd == -1) {
|
||||||
|
LOGE("Failed to receive library fd\n");
|
||||||
|
|
||||||
|
uint8_t response = 2;
|
||||||
|
write(fd, &response, sizeof(response));
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI(" - Library fd: %d\n", library_fd);
|
||||||
|
|
||||||
|
zygisk_companion_entry_func module_entry = load_module(library_fd);
|
||||||
|
close(library_fd);
|
||||||
|
|
||||||
|
if (module_entry == NULL) {
|
||||||
|
LOGI("No companion module entry for module: %.*s\n", (int)ret, name);
|
||||||
|
|
||||||
|
write_int(fd, 0);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
write_int(fd, 1);
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!check_unix_socket(fd, true)) {
|
if (!check_unix_socket(fd, true)) {
|
||||||
LOGI("Something went wrong. Bye!\n");
|
LOGI("Something went wrong in companion. Bye!\n");
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int *client_fd = malloc(sizeof(int));
|
struct companion_module_thread_args *args = malloc(sizeof(struct companion_module_thread_args));
|
||||||
recv_fd(fd, client_fd);
|
args->entry = module_entry;
|
||||||
|
|
||||||
|
if ((args->fd = gread_fd(fd)) == -1) {
|
||||||
|
LOGE("Failed to receive client fd\n");
|
||||||
|
|
||||||
LOGI("New companion request from module \"%s\" with fd \"%d\"\n", name, *client_fd);
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
write(fd, &response, sizeof(response));
|
LOGI("New companion request.\n - Module name: %.*s\n - Client fd: %d\n", (int)ret, name, args->fd);
|
||||||
|
|
||||||
LOGI("Creating new thread for companion request\n");
|
|
||||||
|
|
||||||
|
write_uint8_t(args->fd, 1);
|
||||||
|
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
pthread_create(&thread, NULL, call_entry, (void *)client_fd);
|
pthread_create(&thread, NULL, entry_thread, args);
|
||||||
pthread_detach(thread);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,51 @@
|
|||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <libgen.h>
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#include "companion.h"
|
||||||
|
#include "dl.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#define ANDROID_NAMESPACE_TYPE_SHARED 0x2
|
#define ANDROID_NAMESPACE_TYPE_SHARED 0x2
|
||||||
#define ANDROID_DLEXT_USE_NAMESPACE 0x200
|
#define ANDROID_DLEXT_USE_NAMESPACE 0x200
|
||||||
|
|
||||||
struct AndroidNamespace {
|
typedef struct AndroidNamespace {
|
||||||
u_int8_t _unused[0];
|
unsigned char _unused[0];
|
||||||
};
|
} AndroidNamespace;
|
||||||
|
|
||||||
struct AndroidDlextinfo {
|
typedef struct AndroidDlextinfo {
|
||||||
u_int64_t flags;
|
uint64_t flags;
|
||||||
void *reserved_addr;
|
void *reserved_addr;
|
||||||
size_t reserved_size;
|
size_t reserved_size;
|
||||||
int relro_fd;
|
int relro_fd;
|
||||||
int library_fd;
|
int library_fd;
|
||||||
off64_t library_fd_offset;
|
off64_t library_fd_offset;
|
||||||
struct AndroidNamespace *library_namespace;
|
AndroidNamespace *library_namespace;
|
||||||
};
|
} AndroidDlextinfo;
|
||||||
|
|
||||||
void *android_dlopen_ext(const char *filename, int flags, const struct AndroidDlextinfo *extinfo);
|
extern void *android_dlopen_ext(const char *filename, int flags, const AndroidDlextinfo *extinfo);
|
||||||
|
|
||||||
void *android_dlopen(char *restrict path, uint32_t flags) {
|
typedef AndroidNamespace *(*AndroidCreateNamespaceFn)(
|
||||||
|
const char *name,
|
||||||
|
const char *ld_library_path,
|
||||||
|
const char *default_library_path,
|
||||||
|
uint64_t type,
|
||||||
|
const char *permitted_when_isolated_path,
|
||||||
|
AndroidNamespace *parent,
|
||||||
|
const void *caller_addr
|
||||||
|
);
|
||||||
|
|
||||||
|
void *android_dlopen(char *path, int flags) {
|
||||||
char *dir = dirname(path);
|
char *dir = dirname(path);
|
||||||
struct AndroidDlextinfo info = {
|
struct AndroidDlextinfo info = {
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
@@ -35,24 +57,32 @@ void *android_dlopen(char *restrict path, uint32_t flags) {
|
|||||||
.library_namespace = NULL,
|
.library_namespace = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
void *android_create_namespace_fn = dlsym(RTLD_DEFAULT, "__loader_android_create_namespace");
|
void *handle = dlsym(RTLD_DEFAULT, "__loader_android_create_namespace");
|
||||||
|
AndroidCreateNamespaceFn android_create_namespace_fn = (AndroidCreateNamespaceFn)handle;
|
||||||
|
|
||||||
if (android_create_namespace_fn != NULL) {
|
AndroidNamespace *ns = android_create_namespace_fn(
|
||||||
void *ns = ((void *(*)(const char *, const char *, const char *, u_int32_t, void *, void *, void *))android_create_namespace_fn)(
|
path,
|
||||||
path,
|
dir,
|
||||||
dir,
|
NULL,
|
||||||
NULL,
|
ANDROID_NAMESPACE_TYPE_SHARED,
|
||||||
ANDROID_NAMESPACE_TYPE_SHARED,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
(const void *)&android_dlopen
|
||||||
(void *)&android_dlopen
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if (ns != NULL) {
|
if (ns != NULL) {
|
||||||
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||||
info.library_namespace = ns;
|
info.library_namespace = ns;
|
||||||
}
|
|
||||||
|
LOGI("Open %s with namespace %p\n", path, (void *)ns);
|
||||||
|
} else {
|
||||||
|
LOGI("Cannot create namespace for %s\n", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return android_dlopen_ext(path, flags, &info);
|
void *result = android_dlopen_ext(path, flags, &info);
|
||||||
|
if (result == NULL) {
|
||||||
|
LOGE("Failed to dlopen %s: %s\n", path, dlerror());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#ifndef DL_H
|
#ifndef DL_H
|
||||||
#define DL_H
|
#define DL_H
|
||||||
|
|
||||||
void *android_dlopen(char *restrict path, u_int32_t flags);
|
void *android_dlopen(char *path, int flags);
|
||||||
|
|
||||||
#endif /* DL_H */
|
#endif /* DL_H */
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ int main(int argc, char *argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
root_impls_setup();
|
root_impls_setup();
|
||||||
zygiskd_start();
|
zygiskd_start(argv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ bool _apatch_get_package_config(struct packages_config *restrict config) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char line[1024];
|
char line[1024 * 2];
|
||||||
/* INFO: Skip the CSV header */
|
/* INFO: Skip the CSV header */
|
||||||
fgets(line, sizeof(line), fp);
|
fgets(line, sizeof(line), fp);
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,10 @@
|
|||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
/* INFO 50ms wait */
|
||||||
|
// #define ALLOW_WAIT_ON_DEBUG() usleep(500 * 1000)
|
||||||
|
#define ALLOW_WAIT_ON_DEBUG() {}
|
||||||
|
|
||||||
bool switch_mount_namespace(pid_t pid) {
|
bool switch_mount_namespace(pid_t pid) {
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
|
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
|
||||||
@@ -192,82 +196,114 @@ int unix_listener_from_path(char *restrict path) {
|
|||||||
return socket_fd;
|
return socket_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t send_fd(int sockfd, int fd) {
|
ssize_t gwrite_fd(int fd, int sendfd) {
|
||||||
char control_buf[CMSG_SPACE(sizeof(int))];
|
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||||
memset(control_buf, 0, sizeof(control_buf));
|
char buf[1] = { 0 };
|
||||||
|
|
||||||
int cnt = 1;
|
|
||||||
struct iovec iov = {
|
struct iovec iov = {
|
||||||
.iov_base = &cnt,
|
.iov_base = buf,
|
||||||
.iov_len = sizeof(cnt)
|
.iov_len = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct msghdr msg = {
|
struct msghdr msg = {
|
||||||
.msg_iov = &iov,
|
.msg_iov = &iov,
|
||||||
.msg_iovlen = 1,
|
.msg_iovlen = 1,
|
||||||
.msg_control = control_buf,
|
.msg_control = cmsgbuf,
|
||||||
.msg_controllen = sizeof(control_buf)
|
.msg_controllen = sizeof(cmsgbuf)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||||
|
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||||
cmsg->cmsg_level = SOL_SOCKET;
|
cmsg->cmsg_level = SOL_SOCKET;
|
||||||
cmsg->cmsg_type = SCM_RIGHTS;
|
cmsg->cmsg_type = SCM_RIGHTS;
|
||||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
|
||||||
|
|
||||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
|
memcpy(CMSG_DATA(cmsg), &sendfd, sizeof(int));
|
||||||
|
|
||||||
ssize_t sent_bytes = sendmsg(sockfd, &msg, 0);
|
ssize_t ret = sendmsg(fd, &msg, 0);
|
||||||
if (sent_bytes == -1) {
|
if (ret == -1) {
|
||||||
LOGE("Failed to send fd: %s\n", strerror(errno));
|
LOGE("sendmsg: %s\n", strerror(errno));
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sent_bytes;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t recv_fd(int sockfd, int *restrict fd) {
|
int gread_fd(int fd) {
|
||||||
char control_buf[CMSG_SPACE(sizeof(int))];
|
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||||
memset(control_buf, 0, sizeof(control_buf));
|
char buf[1] = { 0 };
|
||||||
|
|
||||||
int cnt = 1;
|
|
||||||
struct iovec iov = {
|
struct iovec iov = {
|
||||||
.iov_base = &cnt,
|
.iov_base = buf,
|
||||||
.iov_len = sizeof(cnt)
|
.iov_len = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct msghdr msg = {
|
struct msghdr msg = {
|
||||||
.msg_iov = &iov,
|
.msg_iov = &iov,
|
||||||
.msg_iovlen = 1,
|
.msg_iovlen = 1,
|
||||||
.msg_control = control_buf,
|
.msg_control = cmsgbuf,
|
||||||
.msg_controllen = sizeof(control_buf)
|
.msg_controllen = sizeof(cmsgbuf)
|
||||||
};
|
};
|
||||||
|
|
||||||
ssize_t received_bytes = recvmsg(sockfd, &msg, 0);
|
ssize_t ret = recvmsg(fd, &msg, 0);
|
||||||
if (received_bytes == -1) {
|
if (ret == -1) {
|
||||||
LOGE("Failed to read fd: %s\n", strerror(errno));
|
LOGE("recvmsg: %s\n", strerror(errno));
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||||
memcpy(fd, CMSG_DATA(cmsg), sizeof(int));
|
if (cmsg == NULL) {
|
||||||
|
LOGE("CMSG_FIRSTHDR: %s\n", strerror(errno));
|
||||||
return received_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t write_string(int fd, const char *restrict str) {
|
|
||||||
size_t len = strlen(str);
|
|
||||||
|
|
||||||
ssize_t written_bytes = write(fd, &len, sizeof(len));
|
|
||||||
if (written_bytes != sizeof(len)) {
|
|
||||||
LOGE("Failed to write string length: %s\n", strerror(errno));
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
written_bytes = write(fd, str, len);
|
int sendfd;
|
||||||
if ((size_t)written_bytes != len) {
|
memcpy(&sendfd, CMSG_DATA(cmsg), sizeof(int));
|
||||||
|
|
||||||
|
return sendfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define write_func(type) \
|
||||||
|
ssize_t write_## type(int fd, type val) { \
|
||||||
|
ALLOW_WAIT_ON_DEBUG(); \
|
||||||
|
\
|
||||||
|
return write(fd, &val, sizeof(type)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define read_func(type) \
|
||||||
|
ssize_t read_## type(int fd, type *val) { \
|
||||||
|
return read(fd, val, sizeof(type)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
write_func(int)
|
||||||
|
read_func(int)
|
||||||
|
|
||||||
|
write_func(size_t)
|
||||||
|
read_func(size_t)
|
||||||
|
|
||||||
|
write_func(uint32_t)
|
||||||
|
read_func(uint32_t)
|
||||||
|
|
||||||
|
write_func(uint8_t)
|
||||||
|
read_func(uint8_t)
|
||||||
|
|
||||||
|
ssize_t write_string(int fd, const char *restrict str) {
|
||||||
|
size_t len[1];
|
||||||
|
len[0] = strlen(str);
|
||||||
|
|
||||||
|
ALLOW_WAIT_ON_DEBUG();
|
||||||
|
|
||||||
|
ssize_t written_bytes = write(fd, &len, sizeof(size_t));
|
||||||
|
if (written_bytes != sizeof(size_t)) {
|
||||||
|
LOGE("Failed to write string length: Not all bytes were written (%zd != %zu).\n", written_bytes, sizeof(size_t));
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
written_bytes = write(fd, str, len[0]);
|
||||||
|
if ((size_t)written_bytes != len[0]) {
|
||||||
LOGE("Failed to write string: Not all bytes were written.\n");
|
LOGE("Failed to write string: Not all bytes were written.\n");
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@@ -279,9 +315,9 @@ ssize_t write_string(int fd, const char *restrict str) {
|
|||||||
ssize_t read_string(int fd, char *restrict str, size_t len) {
|
ssize_t read_string(int fd, char *restrict str, size_t len) {
|
||||||
size_t str_len_buf[1];
|
size_t str_len_buf[1];
|
||||||
|
|
||||||
ssize_t read_bytes = read(fd, &str_len_buf, sizeof(str_len_buf));
|
ssize_t read_bytes = read(fd, &str_len_buf, sizeof(size_t));
|
||||||
if (read_bytes != (ssize_t)sizeof(str_len_buf)) {
|
if (read_bytes != (ssize_t)sizeof(size_t)) {
|
||||||
LOGE("Failed to read string length: %s\n", strerror(errno));
|
LOGE("Failed to read string length: Not all bytes were read (%zd != %zu).\n", read_bytes, sizeof(size_t));
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -296,7 +332,7 @@ ssize_t read_string(int fd, char *restrict str, size_t len) {
|
|||||||
|
|
||||||
read_bytes = read(fd, str, str_len);
|
read_bytes = read(fd, str, str_len);
|
||||||
if (read_bytes != (ssize_t)str_len) {
|
if (read_bytes != (ssize_t)str_len) {
|
||||||
LOGE("Failed to read string: Not all bytes were read (%zd != %zu).\n", read_bytes, str_len);
|
LOGE("Failed to read string: Promised bytes doesn't exist (%zd != %zu).\n", read_bytes, str_len);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -349,7 +385,7 @@ bool check_unix_socket(int fd, bool block) {
|
|||||||
int timeout = block ? -1 : 0;
|
int timeout = block ? -1 : 0;
|
||||||
poll(&pfd, 1, timeout);
|
poll(&pfd, 1, timeout);
|
||||||
|
|
||||||
return (pfd.revents & !POLLIN) != 0 ? false : true;
|
return pfd.revents & ~POLLIN ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* INFO: Cannot use restrict here as execv does not have restrict */
|
/* INFO: Cannot use restrict here as execv does not have restrict */
|
||||||
|
|||||||
@@ -14,10 +14,16 @@
|
|||||||
FILE *CONCAT(fpl, __LINE__) = fopen("/data/local/tmp/zygiskd.log", "a"); fprintf(CONCAT(fpl, __LINE__), __VA_ARGS__); fclose(CONCAT(fpl, __LINE__))
|
FILE *CONCAT(fpl, __LINE__) = fopen("/data/local/tmp/zygiskd.log", "a"); fprintf(CONCAT(fpl, __LINE__), __VA_ARGS__); fclose(CONCAT(fpl, __LINE__))
|
||||||
|
|
||||||
#define LOGE(...) \
|
#define LOGE(...) \
|
||||||
__android_log_print(ANDROID_LOG_INFO , lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \
|
__android_log_print(ANDROID_LOG_ERROR , lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \
|
||||||
printf(__VA_ARGS__); \
|
printf(__VA_ARGS__); \
|
||||||
FILE *CONCAT(fpl, __LINE__) = fopen("/data/local/tmp/zygiskd.log", "a"); fprintf(CONCAT(fpl, __LINE__), __VA_ARGS__); fclose(CONCAT(fpl, __LINE__))
|
FILE *CONCAT(fpl, __LINE__) = fopen("/data/local/tmp/zygiskd.log", "a"); fprintf(CONCAT(fpl, __LINE__), __VA_ARGS__); fclose(CONCAT(fpl, __LINE__))
|
||||||
|
|
||||||
|
#define write_func_def(type) \
|
||||||
|
ssize_t write_## type(int fd, type val)
|
||||||
|
|
||||||
|
#define read_func_def(type) \
|
||||||
|
ssize_t read_## type(int fd, type *val)
|
||||||
|
|
||||||
bool switch_mount_namespace(pid_t pid);
|
bool switch_mount_namespace(pid_t pid);
|
||||||
|
|
||||||
void get_property(const char *name, char *restrict output);
|
void get_property(const char *name, char *restrict output);
|
||||||
@@ -30,9 +36,25 @@ int chcon(const char *path, const char *restrict context);
|
|||||||
|
|
||||||
int unix_listener_from_path(char *path);
|
int unix_listener_from_path(char *path);
|
||||||
|
|
||||||
ssize_t send_fd(int sockfd, int fd);
|
// ssize_t send_fd(int sockfd, int fd);
|
||||||
|
|
||||||
ssize_t recv_fd(int sockfd, int *restrict fd);
|
// int recv_fd(int sockfd);
|
||||||
|
|
||||||
|
ssize_t gwrite_fd(int fd, int sendfd);
|
||||||
|
|
||||||
|
int gread_fd(int fd);
|
||||||
|
|
||||||
|
write_func_def(int);
|
||||||
|
read_func_def(int);
|
||||||
|
|
||||||
|
write_func_def(size_t);
|
||||||
|
read_func_def(size_t);
|
||||||
|
|
||||||
|
write_func_def(uint32_t);
|
||||||
|
read_func_def(uint32_t);
|
||||||
|
|
||||||
|
write_func_def(uint8_t);
|
||||||
|
read_func_def(uint8_t);
|
||||||
|
|
||||||
ssize_t write_string(int fd, const char *restrict str);
|
ssize_t write_string(int fd, const char *restrict str);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <sys/sendfile.h>
|
#include <sys/sendfile.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
@@ -173,26 +174,10 @@ static void load_modules(enum Architecture arch, struct Context *restrict contex
|
|||||||
|
|
||||||
char arch_str[32];
|
char arch_str[32];
|
||||||
switch (arch) {
|
switch (arch) {
|
||||||
case ARM32: {
|
case ARM64: { strcpy(arch_str, "arm64-v8a"); break; }
|
||||||
strcpy(arch_str, "armeabi-v7a");
|
case X86_64: { strcpy(arch_str, "x86_64"); break; }
|
||||||
|
case ARM32: { strcpy(arch_str, "armeabi-v7a"); break; }
|
||||||
break;
|
case X86: { strcpy(arch_str, "x86"); break; }
|
||||||
}
|
|
||||||
case ARM64: {
|
|
||||||
strcpy(arch_str, "arm64-v8a");
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case X86: {
|
|
||||||
strcpy(arch_str, "x86");
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case X86_64: {
|
|
||||||
strcpy(arch_str, "x86_64");
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Loading modules for architecture: %s\n", arch_str);
|
LOGI("Loading modules for architecture: %s\n", arch_str);
|
||||||
@@ -258,7 +243,9 @@ static int create_daemon_socket(void) {
|
|||||||
return unix_listener_from_path(PATH_CP_NAME);
|
return unix_listener_from_path(PATH_CP_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spawn_companion(char *restrict name, int lib_fd) {
|
static int spawn_companion(char *restrict argv[], char *restrict name, int lib_fd) {
|
||||||
|
LOGI("Spawning a new companion...\n");
|
||||||
|
|
||||||
int sockets[2];
|
int sockets[2];
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
|
||||||
LOGE("Failed creating socket pair.\n");
|
LOGE("Failed creating socket pair.\n");
|
||||||
@@ -269,11 +256,7 @@ static int spawn_companion(char *restrict name, int lib_fd) {
|
|||||||
int daemon_fd = sockets[0];
|
int daemon_fd = sockets[0];
|
||||||
int companion_fd = sockets[1];
|
int companion_fd = sockets[1];
|
||||||
|
|
||||||
LOGI("Companion fd: %d\n", companion_fd);
|
|
||||||
LOGI("Daemon fd: %d\n", daemon_fd);
|
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
LOGI("Forked: %d\n", pid);
|
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
LOGE("Failed forking companion: %s\n", strerror(errno));
|
LOGE("Failed forking companion: %s\n", strerror(errno));
|
||||||
|
|
||||||
@@ -284,66 +267,83 @@ static int spawn_companion(char *restrict name, int lib_fd) {
|
|||||||
} else if (pid > 0) {
|
} else if (pid > 0) {
|
||||||
close(companion_fd);
|
close(companion_fd);
|
||||||
|
|
||||||
LOGI("Waiting for companion to start (%d)\n", pid);
|
|
||||||
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
waitpid(pid, &status, 0);
|
waitpid(pid, &status, 0);
|
||||||
|
|
||||||
LOGI("Companion exited with status %d\n", status);
|
|
||||||
|
|
||||||
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
|
||||||
if (write_string(daemon_fd, name) == -1) {
|
if (write_string(daemon_fd, name) == -1) {
|
||||||
LOGE("Failed sending module name\n");
|
LOGE("Failed writing module name.\n");
|
||||||
|
|
||||||
|
close(daemon_fd);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (send_fd(daemon_fd, lib_fd) == -1) {
|
if (gwrite_fd(daemon_fd, lib_fd) == -1) {
|
||||||
LOGE("Failed sending lib fd\n");
|
LOGE("Failed sending library fd.\n");
|
||||||
|
|
||||||
|
close(daemon_fd);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Sent module name and lib fd\n");
|
|
||||||
|
|
||||||
uint8_t response_buf[1];
|
uint8_t response = 0;
|
||||||
ssize_t ret = read(daemon_fd, &response_buf, sizeof(response_buf));
|
ssize_t ret = read_uint8_t(daemon_fd, &response);
|
||||||
ASSURE_SIZE_READ_WR("companion", "response", ret, sizeof(response_buf));
|
if (ret <= 0) {
|
||||||
|
LOGE("Failed reading companion response.\n");
|
||||||
LOGI("Companion response: %hhu\n", response_buf[0]);
|
|
||||||
|
|
||||||
if (response_buf[0] == 0) {
|
|
||||||
close(daemon_fd);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
} else if (response_buf[0] == 1) return daemon_fd;
|
|
||||||
else {
|
|
||||||
LOGE("Invalid response from companion: %hhu\n", response_buf[0]);
|
|
||||||
|
|
||||||
close(daemon_fd);
|
close(daemon_fd);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOGI("Companion response: %hhu\n", response);
|
||||||
|
|
||||||
|
switch (response) {
|
||||||
|
/* INFO: Even without any entry, we should still just deal with it */
|
||||||
|
case 0: { return -2; }
|
||||||
|
case 1: { return daemon_fd; }
|
||||||
|
/* TODO: Should we be closing daemon socket here? (in non-0-and-1 case) */
|
||||||
|
default: {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* TODO: Should we be closing daemon socket here? */
|
||||||
} else {
|
} else {
|
||||||
LOGE("Exited with status %d\n", status);
|
LOGE("Exited with status %d\n", status);
|
||||||
|
|
||||||
close(daemon_fd);
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* INFO: if pid == 0: */
|
/* INFO: if pid == 0: */
|
||||||
} else {
|
} else {
|
||||||
LOGI("Companion started\n");
|
|
||||||
/* INFO: There is no case where this will fail with a valid fd. */
|
/* INFO: There is no case where this will fail with a valid fd. */
|
||||||
fcntl(companion_fd, F_SETFD, 0);
|
/* INFO: Remove FD_CLOEXEC flag to avoid closing upon exec */
|
||||||
|
if (fcntl(companion_fd, F_SETFD, 0) == -1) {
|
||||||
|
LOGE("Failed removing FD_CLOEXEC flag: %s\n", strerror(errno));
|
||||||
|
|
||||||
|
close(companion_fd);
|
||||||
|
close(daemon_fd);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *process = argv[0];
|
||||||
|
char nice_name[256];
|
||||||
|
char *last = strrchr(process, '/');
|
||||||
|
if (last == NULL) {
|
||||||
|
snprintf(nice_name, sizeof(nice_name), "%s", process);
|
||||||
|
} else {
|
||||||
|
snprintf(nice_name, sizeof(nice_name), "%s", last + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char process_name[256];
|
||||||
|
snprintf(process_name, sizeof(process_name), "%s-%s", nice_name, name);
|
||||||
|
|
||||||
char companion_fd_str[32];
|
char companion_fd_str[32];
|
||||||
snprintf(companion_fd_str, 32, "%d", companion_fd);
|
snprintf(companion_fd_str, sizeof(companion_fd_str), "%d", companion_fd);
|
||||||
|
|
||||||
LOGI("Executing companion...\n");
|
char *eargv[] = { process_name, "companion", companion_fd_str, NULL };
|
||||||
|
if (non_blocking_execv(ZYGISKD_PATH, eargv) == -1) {
|
||||||
char *argv[] = { ZYGISKD_FILE, "companion", companion_fd_str, NULL };
|
|
||||||
if (non_blocking_execv(ZYGISKD_PATH, argv) == -1) {
|
|
||||||
LOGE("Failed executing companion: %s\n", strerror(errno));
|
LOGE("Failed executing companion: %s\n", strerror(errno));
|
||||||
|
|
||||||
close(companion_fd);
|
close(companion_fd);
|
||||||
@@ -351,8 +351,6 @@ static int spawn_companion(char *restrict name, int lib_fd) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Bye bye!\n");
|
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +360,7 @@ struct __attribute__((__packed__)) MsgHead {
|
|||||||
char data[0];
|
char data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
void zygiskd_start(void) {
|
void zygiskd_start(char *restrict argv[]) {
|
||||||
LOGI("Welcome to ReZygisk %s!\n", ZKSU_VERSION);
|
LOGI("Welcome to ReZygisk %s!\n", ZKSU_VERSION);
|
||||||
|
|
||||||
enum RootImpl impl = get_impl();
|
enum RootImpl impl = get_impl();
|
||||||
@@ -517,10 +515,8 @@ void zygiskd_start(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Accepted client: %d\n", client_fd);
|
uint8_t action8 = 0;
|
||||||
|
ssize_t len = read_uint8_t(client_fd, &action8);
|
||||||
uint8_t buf[1];
|
|
||||||
ssize_t len = read(client_fd, buf, sizeof(buf));
|
|
||||||
if (len == -1) {
|
if (len == -1) {
|
||||||
LOGE("read: %s\n", strerror(errno));
|
LOGE("read: %s\n", strerror(errno));
|
||||||
|
|
||||||
@@ -531,17 +527,22 @@ void zygiskd_start(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Action: %hhu\n", buf[0]);
|
enum DaemonSocketAction action = (enum DaemonSocketAction)action8;
|
||||||
enum DaemonSocketAction action = (enum DaemonSocketAction)buf[0];
|
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case PingHeartbeat: {
|
case PingHeartbeat: {
|
||||||
|
LOGI("ZD-- PingHeartbeat\n");
|
||||||
|
|
||||||
enum DaemonSocketAction msgr = ZYGOTE_INJECTED;
|
enum DaemonSocketAction msgr = ZYGOTE_INJECTED;
|
||||||
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
|
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
|
||||||
|
|
||||||
|
LOGI("ZD++ PingHeartbeat\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ZygoteRestart: {
|
case ZygoteRestart: {
|
||||||
|
LOGI("ZD-- ZygoteRestart\n");
|
||||||
|
|
||||||
for (int i = 0; i < context.len; i++) {
|
for (int i = 0; i < context.len; i++) {
|
||||||
if (context.modules[i].companion != -1) {
|
if (context.modules[i].companion != -1) {
|
||||||
close(context.modules[i].companion);
|
close(context.modules[i].companion);
|
||||||
@@ -549,36 +550,40 @@ void zygiskd_start(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOGI("ZD++ ZygoteRestart\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SystemServerStarted: {
|
case SystemServerStarted: {
|
||||||
|
LOGI("ZD-- SystemServerStarted\n");
|
||||||
|
|
||||||
enum DaemonSocketAction msgr = SYSTEM_SERVER_STARTED;
|
enum DaemonSocketAction msgr = SYSTEM_SERVER_STARTED;
|
||||||
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
|
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
|
||||||
|
|
||||||
|
LOGI("ZD++ SystemServerStarted\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* TODO: May need to move to another thread? :/ */
|
|
||||||
case RequestLogcatFd: {
|
case RequestLogcatFd: {
|
||||||
uint8_t level_buf[1];
|
uint8_t level = 0;
|
||||||
ssize_t ret = read(client_fd, &level_buf, sizeof(level_buf));
|
ssize_t ret = read_uint8_t(client_fd, &level);
|
||||||
ASSURE_SIZE_READ_BREAK("RequestLogcatFd", "level", ret, sizeof(level_buf));
|
ASSURE_SIZE_READ_BREAK("RequestLogcatFd", "level", ret, sizeof(level));
|
||||||
|
|
||||||
uint8_t level = level_buf[0];
|
|
||||||
|
|
||||||
char tag[128 + 1];
|
char tag[128 + 1];
|
||||||
ret = read_string(client_fd, tag, sizeof(tag) - 1);
|
ret = read_string(client_fd, tag, sizeof(tag) - 1);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
LOGE("Failed reading tag\n");
|
LOGE("Failed reading logcat tag.\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
tag[ret] = '\0';
|
tag[ret] = '\0';
|
||||||
|
|
||||||
|
/* INFO: Non-NULL terminated */
|
||||||
char message[1024];
|
char message[1024];
|
||||||
ret = read_string(client_fd, message, sizeof(message));
|
ret = read_string(client_fd, message, sizeof(message));
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
LOGE("Failed reading message\n");
|
LOGE("Failed reading logcat message.\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -588,13 +593,11 @@ void zygiskd_start(void) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GetProcessFlags: {
|
case GetProcessFlags: {
|
||||||
LOGI("Getting process flags\n");
|
LOGI("ZD-- GetProcessFlags\n");
|
||||||
|
|
||||||
uint32_t uid_buf[1];
|
uint32_t uid = 0;
|
||||||
ssize_t ret = read(client_fd, &uid_buf, sizeof(uid_buf));
|
ssize_t ret = read_uint32_t(client_fd, &uid);
|
||||||
ASSURE_SIZE_READ_BREAK("GetProcessFlags", "uid", ret, sizeof(uid_buf));
|
ASSURE_SIZE_READ_BREAK("GetProcessFlags", "uid", ret, sizeof(uid));
|
||||||
|
|
||||||
uint32_t uid = uid_buf[0];
|
|
||||||
|
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
if (uid_is_manager(uid)) {
|
if (uid_is_manager(uid)) {
|
||||||
@@ -608,8 +611,6 @@ void zygiskd_start(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Flags for uid %d: %d\n", uid, flags);
|
|
||||||
|
|
||||||
switch (get_impl()) {
|
switch (get_impl()) {
|
||||||
case None: { break; }
|
case None: { break; }
|
||||||
case Multiple: { break; }
|
case Multiple: { break; }
|
||||||
@@ -630,17 +631,17 @@ void zygiskd_start(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = write(client_fd, &flags, sizeof(flags));
|
ret = write_int(client_fd, flags);
|
||||||
ASSURE_SIZE_WRITE_BREAK("GetProcessFlags", "flags", ret, sizeof(flags));
|
ASSURE_SIZE_WRITE_BREAK("GetProcessFlags", "flags", ret, sizeof(flags));
|
||||||
|
|
||||||
LOGI("Sent flags\n");
|
LOGI("ZD++ GetProcessFlags\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GetInfo: {
|
case GetInfo: {
|
||||||
uint32_t flags = 0;
|
LOGI("ZD-- GetInfo\n");
|
||||||
|
|
||||||
LOGI("Getting info\n");
|
uint32_t flags = 0;
|
||||||
|
|
||||||
switch (get_impl()) {
|
switch (get_impl()) {
|
||||||
case None: { break; }
|
case None: { break; }
|
||||||
@@ -662,72 +663,52 @@ void zygiskd_start(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Flags: %d\n", flags);
|
ssize_t ret = write_size_t(client_fd, flags);
|
||||||
|
|
||||||
ssize_t ret = write(client_fd, &flags, sizeof(flags));
|
|
||||||
ASSURE_SIZE_WRITE_BREAK("GetInfo", "flags", ret, sizeof(flags));
|
ASSURE_SIZE_WRITE_BREAK("GetInfo", "flags", ret, sizeof(flags));
|
||||||
|
|
||||||
uint32_t pid = getpid();
|
uint32_t pid = getpid();
|
||||||
|
ret = write_uint32_t(client_fd, pid);
|
||||||
LOGI("Getting pid: %d\n", pid);
|
|
||||||
|
|
||||||
ret = write(client_fd, &pid, sizeof(pid));
|
|
||||||
ASSURE_SIZE_WRITE_BREAK("GetInfo", "pid", ret, sizeof(pid));
|
ASSURE_SIZE_WRITE_BREAK("GetInfo", "pid", ret, sizeof(pid));
|
||||||
|
|
||||||
LOGI("Sent pid\n");
|
|
||||||
|
|
||||||
size_t modules_len = context.len;
|
size_t modules_len = context.len;
|
||||||
ret = write(client_fd, &modules_len, sizeof(modules_len));
|
ret = write_size_t(client_fd, modules_len);
|
||||||
|
|
||||||
for (size_t i = 0; i < modules_len; i++) {
|
for (size_t i = 0; i < modules_len; i++) {
|
||||||
write_string(client_fd, context.modules[i].name);
|
write_string(client_fd, context.modules[i].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOGI("ZD++ GetInfo\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ReadModules: {
|
case ReadModules: {
|
||||||
LOGI("Reading modules to stream\n");
|
LOGI("ZD-- ReadModules\n");
|
||||||
|
|
||||||
size_t clen = context.len;
|
size_t clen = context.len;
|
||||||
ssize_t ret = write(client_fd, &clen, sizeof(clen));
|
ssize_t ret = write_size_t(client_fd, clen);
|
||||||
ASSURE_SIZE_WRITE_BREAK("ReadModules", "len", ret, sizeof(clen));
|
ASSURE_SIZE_WRITE_BREAK("ReadModules", "len", ret, sizeof(clen));
|
||||||
|
|
||||||
for (size_t i = 0; i < clen; i++) {
|
for (size_t i = 0; i < clen; i++) {
|
||||||
LOGI("Hey, we're talking about: %zu, with name and lib_fd: %s, %d\n", i, context.modules[i].name, context.modules[i].lib_fd);
|
if (write_string(client_fd, context.modules[i].name) == -1) break;
|
||||||
|
if (gwrite_fd(client_fd, context.modules[i].lib_fd) == -1) break;
|
||||||
if (write_string(client_fd, context.modules[i].name) == -1) {
|
|
||||||
LOGE("Failed writing module name\n");
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (send_fd(client_fd, context.modules[i].lib_fd) == -1) {
|
|
||||||
LOGE("Failed sending lib fd\n");
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Finished reading modules to stream\n");
|
LOGI("ZD++ ReadModules\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RequestCompanionSocket: {
|
case RequestCompanionSocket: {
|
||||||
LOGI("Requesting companion socket\n");
|
LOGI("ZD-- RequestCompanionSocket\n");
|
||||||
|
|
||||||
size_t index_buf[1];
|
|
||||||
ssize_t ret = read(client_fd, &index_buf, sizeof(index_buf));
|
|
||||||
ASSURE_SIZE_READ_BREAK("RequestCompanionSocket", "index", ret, sizeof(index_buf));
|
|
||||||
|
|
||||||
size_t index = index_buf[0];
|
size_t index = 0;
|
||||||
|
ssize_t ret = read_size_t(client_fd, &index);
|
||||||
|
ASSURE_SIZE_READ_BREAK("RequestCompanionSocket", "index", ret, sizeof(index));
|
||||||
|
|
||||||
struct Module *module = &context.modules[index];
|
struct Module *module = &context.modules[index];
|
||||||
|
|
||||||
if (module->companion != -1) {
|
if (module->companion != -1) {
|
||||||
LOGI("Companion for module `%s` already exists\n", module->name);
|
|
||||||
|
|
||||||
if (!check_unix_socket(module->companion, false)) {
|
if (!check_unix_socket(module->companion, false)) {
|
||||||
LOGE("Poll companion for module `%s` crashed\n", module->name);
|
LOGE(" Poll companion for module \"%s\" crashed\n", module->name);
|
||||||
|
|
||||||
close(module->companion);
|
close(module->companion);
|
||||||
module->companion = -1;
|
module->companion = -1;
|
||||||
@@ -735,74 +716,74 @@ void zygiskd_start(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (module->companion == -1) {
|
if (module->companion == -1) {
|
||||||
LOGI("Spawning companion for `%s`\n", module->name);
|
module->companion = spawn_companion(argv, module->name, module->lib_fd);
|
||||||
|
|
||||||
module->companion = spawn_companion(module->name, module->lib_fd);
|
if (module->companion > 0) {
|
||||||
|
LOGI(" Spawned companion for \"%s\"\n", module->name);
|
||||||
if (module->companion != -1) {
|
|
||||||
LOGI("Spawned companion for `%s`\n", module->name);
|
|
||||||
|
|
||||||
/* INFO: Reversed params, may fix issues */
|
|
||||||
if (send_fd(module->companion, client_fd) == -1) {
|
|
||||||
LOGE("Failed sending companion fd\n");
|
|
||||||
|
|
||||||
uint8_t response = 0;
|
|
||||||
ret = write(client_fd, &response, sizeof(response));
|
|
||||||
ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(response));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (module->companion == -2) {
|
if (module->companion == -2) {
|
||||||
LOGI("Could not spawn companion for `%s` as it has no entry\n", module->name);
|
LOGE(" No companion spawned for \"%s\" because it has no entry.\n", module->name);
|
||||||
} else {
|
} else {
|
||||||
LOGI("Could not spawn companion for `%s` due to failures.\n", module->name);
|
LOGE(" Failed to spawn companion for \"%s\": %s\n", module->name, strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t response = 0;
|
|
||||||
ret = write(client_fd, &response, sizeof(response));
|
|
||||||
ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(response));
|
|
||||||
|
|
||||||
LOGI("Companion fd: %d\n", module->companion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (module->companion != -1) {
|
||||||
|
if (gwrite_fd(module->companion, client_fd) == -1) {
|
||||||
|
LOGE("Failed to send companion fd socket of module \"%s\"\n", module->name);
|
||||||
|
|
||||||
|
ret = write_int(client_fd, 0);
|
||||||
|
ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(int));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = write_int(client_fd, 0);
|
||||||
|
ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("ZD++ RequestCompanionSocket\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GetModuleDir: {
|
case GetModuleDir: {
|
||||||
LOGI("Getting module directory\n");
|
LOGI("ZD-- GetModuleDir\n");
|
||||||
|
|
||||||
size_t index_buf[1];
|
size_t index = 0;
|
||||||
ssize_t ret = read(client_fd, &index_buf, sizeof(index_buf));
|
read_size_t(client_fd, &index);
|
||||||
ASSURE_SIZE_READ_BREAK("GetModuleDir", "index", ret, sizeof(index_buf));
|
|
||||||
|
|
||||||
size_t index = index_buf[0];
|
char module_dir[PATH_MAX];
|
||||||
|
snprintf(module_dir, PATH_MAX, "%s/%s", PATH_MODULES_DIR, context.modules[index].name);
|
||||||
|
|
||||||
LOGI("Index: %zu\n", index);
|
int fd = open(module_dir, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
char dir[PATH_MAX];
|
LOGE("Failed opening module directory \"%s\": %s\n", module_dir, strerror(errno));
|
||||||
snprintf(dir, PATH_MAX, "%s/%s", PATH_MODULES_DIR, context.modules[index].name);
|
|
||||||
|
|
||||||
LOGI("Module directory: %s\n", dir);
|
|
||||||
/* INFO: Maybe not read only? */
|
|
||||||
int dir_fd = open(dir, O_RDONLY);
|
|
||||||
|
|
||||||
LOGI("Module directory fd: %d\n", dir_fd);
|
|
||||||
|
|
||||||
if (send_fd(client_fd, dir_fd) == -1) {
|
|
||||||
LOGE("Failed sending module directory fd\n");
|
|
||||||
|
|
||||||
close(dir_fd);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Sent module directory fd\n");
|
struct stat st;
|
||||||
|
if (fstat(fd, &st) == -1) {
|
||||||
|
LOGE("Failed getting module directory \"%s\" stats: %s\n", module_dir, strerror(errno));
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gwrite_fd(client_fd, fd) == -1) {
|
||||||
|
LOGE("Failed sending module directory \"%s\" fd: %s\n", module_dir, strerror(errno));
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("ZD++ GetModuleDir\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(client_fd);
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#ifndef ZYGISKD_H
|
#ifndef ZYGISKD_H
|
||||||
#define ZYGISKD_H
|
#define ZYGISKD_H
|
||||||
|
|
||||||
void zygiskd_start(void);
|
void zygiskd_start(char *restrict argv[]);
|
||||||
|
|
||||||
#endif /* ZYGISKD_H */
|
#endif /* ZYGISKD_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user