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:
ThePedroo
2024-09-08 15:53:47 -03:00
parent a549f0e5ae
commit c2abef8826
12 changed files with 721 additions and 603 deletions

View File

@@ -1,221 +1,263 @@
#include <linux/un.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include "daemon.h"
#include "dl.h"
#include "socket_utils.h"
namespace zygiskd {
static std::string TMP_PATH;
void Init(const char *path) {
TMP_PATH = path;
static std::string TMP_PATH;
void Init(const char *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() {
return TMP_PATH;
close(fd);
return -1;
}
bool PingHeartbeat() {
int fd = Connect(5);
if (fd == -1) {
PLOGE("Connect to zygiskd");
return false;
}
int Connect(uint8_t retry) {
int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
struct sockaddr_un addr = {
.sun_family = AF_UNIX,
.sun_path = { 0 },
};
socket_utils::write_u8(fd, (uint8_t) SocketAction::PingHeartBeat);
auto socket_path = TMP_PATH + kCPSocketName;
strcpy(addr.sun_path, socket_path.c_str());
socklen_t socklen = sizeof(addr);
close(fd);
while (retry--) {
int r = connect(fd, reinterpret_cast<struct sockaddr*>(&addr), socklen);
if (r == 0) return fd;
if (retry) {
PLOGE("Retrying to connect to zygiskd, sleep 1s");
sleep(1);
}
}
return true;
}
int RequestLogcatFd() {
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) {
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);
return -1;
}
bool PingHeartbeat() {
UniqueFd fd = Connect(5);
if (fd == -1) {
PLOGE("Connect to zygiskd");
return false;
}
socket_utils::write_u8(fd, (uint8_t) SocketAction::PingHeartBeat);
return true;
}
return;
}
int RequestLogcatFd() {
int fd = Connect(1);
if (fd == -1) {
PLOGE("RequestLogcatFd");
return -1;
}
socket_utils::write_u8(fd, (uint8_t) SocketAction::RequestLogcatFd);
return fd;
}
info->modules->modules_count = socket_utils::read_usize(fd);
uint32_t GetProcessFlags(uid_t uid) {
UniqueFd 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);
if (info->modules->modules_count == 0) {
info->modules->modules = NULL;
return socket_utils::read_u32(fd);
}
close(fd);
std::vector<Module> ReadModules() {
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;
}
return;
}
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);
if (socket_utils::read_u8(fd) == 1) {
return fd;
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 {
close(fd);
return -1;
}
}
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);
int GetModuleDir(size_t index) {
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");
break;
}
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);
} else info->running = false;
}
fclose(module_prop);
}
}
close(fd);
} else info->running = false;
}
}

View File

@@ -5,131 +5,133 @@
#include "socket_utils.h"
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 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);
size_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 write_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) {
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 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) {
int rec = recvmsg(sockfd, msg, flags);
if (rec < 0) PLOGE("recvmsg");
return rec;
}
ssize_t xrecvmsg(int sockfd, struct msghdr* msg, int flags) {
int rec = recvmsg(sockfd, msg, flags);
if (rec < 0) PLOGE("recvmsg");
return rec;
}
template<typename T>
inline T read_exact_or(int fd, T fail) {
T res;
return sizeof(T) == xread(fd, &res, sizeof(T)) ? res : fail;
}
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
};
template<typename T>
inline bool write_exact(int fd, T val) {
return sizeof(T) == xwrite(fd, &val, sizeof(T));
}
xrecvmsg(sockfd, &msg, MSG_WAITALL);
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
uint8_t read_u8(int fd) {
return read_exact_or<uint8_t>(fd, 0);
}
if (msg.msg_controllen != bufsz ||
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;
}
uint32_t read_u32(int fd) {
return read_exact_or<uint32_t>(fd, 0);
}
return CMSG_DATA(cmsg);
}
size_t read_usize(int fd) {
return read_exact_or<size_t>(fd, 0);
}
template<typename T>
inline T read_exact_or(int fd, T fail) {
T res;
return sizeof(T) == xread(fd, &res, sizeof(T)) ? res : fail;
}
bool write_usize(int fd, size_t val) {
return write_exact<size_t>(fd, val);
}
template<typename T>
inline bool write_exact(int fd, T val) {
return sizeof(T) == xwrite(fd, &val, sizeof(T));
}
std::string read_string(int fd) {
size_t len = read_usize(fd);
uint8_t read_u8(int fd) {
return read_exact_or<uint8_t>(fd, 0);
}
char buf[len + 1];
xread(fd, buf, len);
uint32_t read_u32(int fd) {
return read_exact_or<uint32_t>(fd, 0);
}
buf[len] = '\0';
size_t read_usize(int fd) {
return read_exact_or<size_t>(fd, 0);
}
return buf;
}
bool write_usize(int fd, size_t val) {
return write_exact<size_t>(fd, val);
}
bool write_u8(int fd, uint8_t val) {
return write_exact<uint8_t>(fd, val);
}
std::string read_string(int fd) {
auto len = read_usize(fd);
char buf[len + 1];
buf[len] = '\0';
xread(fd, buf, len);
return buf;
}
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
};
bool write_u8(int fd, uint8_t val) {
return write_exact<uint8_t>(fd, val);
}
xrecvmsg(sockfd, &msg, MSG_WAITALL);
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
bool write_u32(int fd, uint32_t val) {
return write_exact<uint32_t>(fd, val);
}
if (msg.msg_controllen != bufsz ||
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 write_usize(fd, str.size()) && str.size() == xwrite(fd, str.data(), str.size());
}
return CMSG_DATA(cmsg);
}
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);
if (data == nullptr) return -1;
void* data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
if (data == nullptr) return -1;
int result;
memcpy(&result, data, sizeof(int));
return result;
}
int result;
memcpy(&result, data, sizeof(int));
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());
}
}

View File

@@ -15,7 +15,7 @@ fun getLatestNDKPath(): String {
}
// 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
}

View File

@@ -6,6 +6,7 @@
#include <sys/stat.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/limits.h>
@@ -19,6 +20,11 @@
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) {
char path[PATH_MAX];
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;
}
void *call_entry(void *restrict arg) {
int fd = *((int *)arg);
void *entry_thread(void *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;
if (fstat(fd, &st0) == -1) {
LOGE("Failed to stat client fd\n");
fstat(fd, &st0);
free(arg);
LOGI("New companion thread (inside the thread!).\n - Client fd: %d\n", fd);
exit(0);
}
entry(fd);
module_entry(fd);
// Only close client if it is the same file so we don't
// accidentally close a re-used file descriptor.
// This check is required because the module companion
// handler could've closed the file descriptor already.
/* TODO: Is this even necessary? */
struct stat st1;
if (fstat(fd, &st1) == -1) {
LOGE("Failed to stat client fd\n");
if (fstat(fd, &st1) != -1) {
if (st0.st_dev != st1.st_dev || st0.st_ino != st1.st_ino) {
close(fd);
free(arg);
exit(0);
LOGI("Client fd has been replaced. Bye!\n");
}
}
if (st0.st_dev != st1.st_dev || st0.st_ino != st1.st_ino) {
close(fd);
}
free(args);
free(arg);
pthread_exit(NULL);
return NULL;
}
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];
ssize_t ret = read_string(fd, name, sizeof(name) - 1);
if (ret == -1) return;
char name[256];
ssize_t ret = read_string(fd, name, sizeof(name));
if (ret == -1) {
LOGE("Failed to read module name\n");
name[ret] = '\0';
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;
uint8_t response = 2;
write(fd, &response, sizeof(response));
exit(0);
return;
}
LOGI("Companion process created for: %s\n", name);
LOGI(" - Module name: `%.*s`\n", (int)ret, name);
uint8_t response = 1;
write(fd, &response, sizeof(response));
int library_fd = gread_fd(fd);
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) {
if (!check_unix_socket(fd, true)) {
LOGI("Something went wrong. Bye!\n");
LOGI("Something went wrong in companion. Bye!\n");
exit(0);
break;
}
int *client_fd = malloc(sizeof(int));
recv_fd(fd, client_fd);
struct companion_module_thread_args *args = malloc(sizeof(struct companion_module_thread_args));
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("Creating new thread for companion request\n");
LOGI("New companion request.\n - Module name: %.*s\n - Client fd: %d\n", (int)ret, name, args->fd);
write_uint8_t(args->fd, 1);
pthread_t thread;
pthread_create(&thread, NULL, call_entry, (void *)client_fd);
pthread_detach(thread);
pthread_create(&thread, NULL, entry_thread, args);
}
}

View File

@@ -1,29 +1,51 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <libgen.h>
#include <string.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_DLEXT_USE_NAMESPACE 0x200
struct AndroidNamespace {
u_int8_t _unused[0];
};
typedef struct AndroidNamespace {
unsigned char _unused[0];
} AndroidNamespace;
struct AndroidDlextinfo {
u_int64_t flags;
typedef struct AndroidDlextinfo {
uint64_t flags;
void *reserved_addr;
size_t reserved_size;
int relro_fd;
int library_fd;
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);
struct AndroidDlextinfo info = {
.flags = 0,
@@ -35,24 +57,32 @@ void *android_dlopen(char *restrict path, uint32_t flags) {
.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) {
void *ns = ((void *(*)(const char *, const char *, const char *, u_int32_t, void *, void *, void *))android_create_namespace_fn)(
path,
dir,
NULL,
ANDROID_NAMESPACE_TYPE_SHARED,
NULL,
NULL,
(void *)&android_dlopen
);
AndroidNamespace *ns = android_create_namespace_fn(
path,
dir,
NULL,
ANDROID_NAMESPACE_TYPE_SHARED,
NULL,
NULL,
(const void *)&android_dlopen
);
if (ns != NULL) {
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
info.library_namespace = ns;
}
if (ns != NULL) {
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
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;
}

View File

@@ -1,6 +1,6 @@
#ifndef 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 */

View File

@@ -86,7 +86,7 @@ int main(int argc, char *argv[]) {
return 1;
}
root_impls_setup();
zygiskd_start();
zygiskd_start(argv);
return 0;
}

View File

@@ -57,7 +57,7 @@ bool _apatch_get_package_config(struct packages_config *restrict config) {
return false;
}
char line[1024];
char line[1024 * 2];
/* INFO: Skip the CSV header */
fgets(line, sizeof(line), fp);

View File

@@ -18,6 +18,10 @@
#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) {
char path[PATH_MAX];
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
@@ -192,82 +196,114 @@ int unix_listener_from_path(char *restrict path) {
return socket_fd;
}
ssize_t send_fd(int sockfd, int fd) {
char control_buf[CMSG_SPACE(sizeof(int))];
memset(control_buf, 0, sizeof(control_buf));
int cnt = 1;
ssize_t gwrite_fd(int fd, int sendfd) {
char cmsgbuf[CMSG_SPACE(sizeof(int))];
char buf[1] = { 0 };
struct iovec iov = {
.iov_base = &cnt,
.iov_len = sizeof(cnt)
.iov_base = buf,
.iov_len = 1
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = control_buf,
.msg_controllen = sizeof(control_buf)
.msg_control = cmsgbuf,
.msg_controllen = sizeof(cmsgbuf)
};
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
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);
if (sent_bytes == -1) {
LOGE("Failed to send fd: %s\n", strerror(errno));
ssize_t ret = sendmsg(fd, &msg, 0);
if (ret == -1) {
LOGE("sendmsg: %s\n", strerror(errno));
return -1;
}
return sent_bytes;
return ret;
}
ssize_t recv_fd(int sockfd, int *restrict fd) {
char control_buf[CMSG_SPACE(sizeof(int))];
memset(control_buf, 0, sizeof(control_buf));
int cnt = 1;
int gread_fd(int fd) {
char cmsgbuf[CMSG_SPACE(sizeof(int))];
char buf[1] = { 0 };
struct iovec iov = {
.iov_base = &cnt,
.iov_len = sizeof(cnt)
.iov_base = buf,
.iov_len = 1
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = control_buf,
.msg_controllen = sizeof(control_buf)
.msg_control = cmsgbuf,
.msg_controllen = sizeof(cmsgbuf)
};
ssize_t received_bytes = recvmsg(sockfd, &msg, 0);
if (received_bytes == -1) {
LOGE("Failed to read fd: %s\n", strerror(errno));
ssize_t ret = recvmsg(fd, &msg, 0);
if (ret == -1) {
LOGE("recvmsg: %s\n", strerror(errno));
return -1;
}
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
memcpy(fd, CMSG_DATA(cmsg), sizeof(int));
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));
if (cmsg == NULL) {
LOGE("CMSG_FIRSTHDR: %s\n", strerror(errno));
return -1;
}
written_bytes = write(fd, str, len);
if ((size_t)written_bytes != len) {
int sendfd;
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");
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) {
size_t str_len_buf[1];
ssize_t read_bytes = read(fd, &str_len_buf, sizeof(str_len_buf));
if (read_bytes != (ssize_t)sizeof(str_len_buf)) {
LOGE("Failed to read string length: %s\n", strerror(errno));
ssize_t read_bytes = read(fd, &str_len_buf, sizeof(size_t));
if (read_bytes != (ssize_t)sizeof(size_t)) {
LOGE("Failed to read string length: Not all bytes were read (%zd != %zu).\n", read_bytes, sizeof(size_t));
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);
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;
}
@@ -349,7 +385,7 @@ bool check_unix_socket(int fd, bool block) {
int timeout = block ? -1 : 0;
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 */

View File

@@ -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__))
#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__); \
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);
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);
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);

View File

@@ -9,6 +9,7 @@
#include <sys/sendfile.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/limits.h>
@@ -173,26 +174,10 @@ static void load_modules(enum Architecture arch, struct Context *restrict contex
char arch_str[32];
switch (arch) {
case ARM32: {
strcpy(arch_str, "armeabi-v7a");
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;
}
case ARM64: { strcpy(arch_str, "arm64-v8a"); break; }
case X86_64: { strcpy(arch_str, "x86_64"); break; }
case ARM32: { strcpy(arch_str, "armeabi-v7a"); break; }
case X86: { strcpy(arch_str, "x86"); break; }
}
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);
}
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];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
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 companion_fd = sockets[1];
LOGI("Companion fd: %d\n", companion_fd);
LOGI("Daemon fd: %d\n", daemon_fd);
pid_t pid = fork();
LOGI("Forked: %d\n", pid);
if (pid < 0) {
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) {
close(companion_fd);
LOGI("Waiting for companion to start (%d)\n", pid);
int status = 0;
waitpid(pid, &status, 0);
LOGI("Companion exited with status %d\n", status);
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
if (write_string(daemon_fd, name) == -1) {
LOGE("Failed sending module name\n");
LOGE("Failed writing module name.\n");
close(daemon_fd);
return -1;
}
if (send_fd(daemon_fd, lib_fd) == -1) {
LOGE("Failed sending lib fd\n");
if (gwrite_fd(daemon_fd, lib_fd) == -1) {
LOGE("Failed sending library fd.\n");
close(daemon_fd);
return -1;
}
LOGI("Sent module name and lib fd\n");
uint8_t response_buf[1];
ssize_t ret = read(daemon_fd, &response_buf, sizeof(response_buf));
ASSURE_SIZE_READ_WR("companion", "response", ret, sizeof(response_buf));
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]);
uint8_t response = 0;
ssize_t ret = read_uint8_t(daemon_fd, &response);
if (ret <= 0) {
LOGE("Failed reading companion response.\n");
close(daemon_fd);
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 {
LOGE("Exited with status %d\n", status);
close(daemon_fd);
return -1;
}
/* INFO: if pid == 0: */
} else {
LOGI("Companion started\n");
/* 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];
snprintf(companion_fd_str, 32, "%d", companion_fd);
snprintf(companion_fd_str, sizeof(companion_fd_str), "%d", companion_fd);
LOGI("Executing companion...\n");
char *argv[] = { ZYGISKD_FILE, "companion", companion_fd_str, NULL };
if (non_blocking_execv(ZYGISKD_PATH, argv) == -1) {
char *eargv[] = { process_name, "companion", companion_fd_str, NULL };
if (non_blocking_execv(ZYGISKD_PATH, eargv) == -1) {
LOGE("Failed executing companion: %s\n", strerror(errno));
close(companion_fd);
@@ -351,8 +351,6 @@ static int spawn_companion(char *restrict name, int lib_fd) {
exit(1);
}
LOGI("Bye bye!\n");
exit(0);
}
@@ -362,7 +360,7 @@ struct __attribute__((__packed__)) MsgHead {
char data[0];
};
void zygiskd_start(void) {
void zygiskd_start(char *restrict argv[]) {
LOGI("Welcome to ReZygisk %s!\n", ZKSU_VERSION);
enum RootImpl impl = get_impl();
@@ -517,10 +515,8 @@ void zygiskd_start(void) {
return;
}
LOGI("Accepted client: %d\n", client_fd);
uint8_t buf[1];
ssize_t len = read(client_fd, buf, sizeof(buf));
uint8_t action8 = 0;
ssize_t len = read_uint8_t(client_fd, &action8);
if (len == -1) {
LOGE("read: %s\n", strerror(errno));
@@ -531,17 +527,22 @@ void zygiskd_start(void) {
return;
}
LOGI("Action: %hhu\n", buf[0]);
enum DaemonSocketAction action = (enum DaemonSocketAction)buf[0];
enum DaemonSocketAction action = (enum DaemonSocketAction)action8;
switch (action) {
case PingHeartbeat: {
LOGI("ZD-- PingHeartbeat\n");
enum DaemonSocketAction msgr = ZYGOTE_INJECTED;
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
LOGI("ZD++ PingHeartbeat\n");
break;
}
case ZygoteRestart: {
LOGI("ZD-- ZygoteRestart\n");
for (int i = 0; i < context.len; i++) {
if (context.modules[i].companion != -1) {
close(context.modules[i].companion);
@@ -549,36 +550,40 @@ void zygiskd_start(void) {
}
}
LOGI("ZD++ ZygoteRestart\n");
break;
}
case SystemServerStarted: {
LOGI("ZD-- SystemServerStarted\n");
enum DaemonSocketAction msgr = SYSTEM_SERVER_STARTED;
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
LOGI("ZD++ SystemServerStarted\n");
break;
}
/* TODO: May need to move to another thread? :/ */
case RequestLogcatFd: {
uint8_t level_buf[1];
ssize_t ret = read(client_fd, &level_buf, sizeof(level_buf));
ASSURE_SIZE_READ_BREAK("RequestLogcatFd", "level", ret, sizeof(level_buf));
uint8_t level = level_buf[0];
uint8_t level = 0;
ssize_t ret = read_uint8_t(client_fd, &level);
ASSURE_SIZE_READ_BREAK("RequestLogcatFd", "level", ret, sizeof(level));
char tag[128 + 1];
ret = read_string(client_fd, tag, sizeof(tag) - 1);
if (ret == -1) {
LOGE("Failed reading tag\n");
LOGE("Failed reading logcat tag.\n");
break;
}
tag[ret] = '\0';
/* INFO: Non-NULL terminated */
char message[1024];
ret = read_string(client_fd, message, sizeof(message));
if (ret == -1) {
LOGE("Failed reading message\n");
LOGE("Failed reading logcat message.\n");
break;
}
@@ -588,13 +593,11 @@ void zygiskd_start(void) {
break;
}
case GetProcessFlags: {
LOGI("Getting process flags\n");
LOGI("ZD-- GetProcessFlags\n");
uint32_t uid_buf[1];
ssize_t ret = read(client_fd, &uid_buf, sizeof(uid_buf));
ASSURE_SIZE_READ_BREAK("GetProcessFlags", "uid", ret, sizeof(uid_buf));
uint32_t uid = uid_buf[0];
uint32_t uid = 0;
ssize_t ret = read_uint32_t(client_fd, &uid);
ASSURE_SIZE_READ_BREAK("GetProcessFlags", "uid", ret, sizeof(uid));
uint32_t flags = 0;
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()) {
case None: { 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));
LOGI("Sent flags\n");
LOGI("ZD++ GetProcessFlags\n");
break;
}
case GetInfo: {
uint32_t flags = 0;
LOGI("ZD-- GetInfo\n");
LOGI("Getting info\n");
uint32_t flags = 0;
switch (get_impl()) {
case None: { break; }
@@ -662,72 +663,52 @@ void zygiskd_start(void) {
}
}
LOGI("Flags: %d\n", flags);
ssize_t ret = write(client_fd, &flags, sizeof(flags));
ssize_t ret = write_size_t(client_fd, flags);
ASSURE_SIZE_WRITE_BREAK("GetInfo", "flags", ret, sizeof(flags));
uint32_t pid = getpid();
LOGI("Getting pid: %d\n", pid);
ret = write(client_fd, &pid, sizeof(pid));
uint32_t pid = getpid();
ret = write_uint32_t(client_fd, pid);
ASSURE_SIZE_WRITE_BREAK("GetInfo", "pid", ret, sizeof(pid));
LOGI("Sent pid\n");
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++) {
write_string(client_fd, context.modules[i].name);
}
LOGI("ZD++ GetInfo\n");
break;
}
case ReadModules: {
LOGI("Reading modules to stream\n");
LOGI("ZD-- ReadModules\n");
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));
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) {
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;
}
if (write_string(client_fd, context.modules[i].name) == -1) break;
if (gwrite_fd(client_fd, context.modules[i].lib_fd) == -1) break;
}
LOGI("Finished reading modules to stream\n");
LOGI("ZD++ ReadModules\n");
break;
}
case RequestCompanionSocket: {
LOGI("Requesting companion socket\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));
LOGI("ZD-- RequestCompanionSocket\n");
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];
if (module->companion != -1) {
LOGI("Companion for module `%s` already exists\n", module->name);
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);
module->companion = -1;
@@ -735,74 +716,74 @@ void zygiskd_start(void) {
}
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 != -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));
}
if (module->companion > 0) {
LOGI(" Spawned companion for \"%s\"\n", module->name);
} else {
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 {
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;
}
case GetModuleDir: {
LOGI("Getting module directory\n");
LOGI("ZD-- GetModuleDir\n");
size_t index_buf[1];
ssize_t ret = read(client_fd, &index_buf, sizeof(index_buf));
ASSURE_SIZE_READ_BREAK("GetModuleDir", "index", ret, sizeof(index_buf));
size_t index = 0;
read_size_t(client_fd, &index);
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);
char dir[PATH_MAX];
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);
int fd = open(module_dir, O_RDONLY);
if (fd == -1) {
LOGE("Failed opening module directory \"%s\": %s\n", module_dir, strerror(errno));
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;
}
}
close(client_fd);
continue;
}

View File

@@ -1,6 +1,6 @@
#ifndef ZYGISKD_H
#define ZYGISKD_H
void zygiskd_start(void);
void zygiskd_start(char *restrict argv[]);
#endif /* ZYGISKD_H */