3 Commits

Author SHA1 Message Date
ThePedroo
7e823319b7 improve: SoInfo hiding code complexity
This commit improves the SoInfo hiding code by reducing the complexity of it, using dlclose directly when possible to make it more future proof and simple.

Co-Authored-By: 4h9fbZ <176179231+4h9fbZ@users.noreply.github.com>
2025-08-10 18:18:26 -03:00
ThePedroo
f9fcf1c2e7 fix: remote strlen fail in dlopen path; add: GNU ifunc handling to elf_util.c
This commit fixes the remote call to "strlen" fail because ReZygisk ELF utils would not handle GNU indirect functions, making it call the in-between function instead of the actual function.
2025-08-10 17:21:34 -03:00
ThePedroo
08513b17e8 fix: memory leak, unitialized memory access, FILE pointer leak bugs
This commit fixes numerous general code bugs, improving reliability and consistency of ReZygisk.
2025-08-10 17:06:48 -03:00
19 changed files with 503 additions and 280 deletions

View File

@@ -108,43 +108,32 @@ void rezygiskd_get_info(struct rezygisk_info *info) {
read_uint32_t(fd, (uint32_t *)&info->pid);
read_size_t(fd, &info->modules->modules_count);
if (info->modules->modules_count == 0) {
info->modules->modules = NULL;
read_size_t(fd, &info->modules.modules_count);
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) {
info->modules.modules = (char **)malloc(sizeof(char *) * info->modules.modules_count);
if (!info->modules.modules) {
PLOGE("allocating modules name memory");
free(info->modules);
info->modules = NULL;
info->modules->modules_count = 0;
info->modules.modules_count = 0;
close(fd);
return;
}
for (size_t i = 0; i < info->modules->modules_count; i++) {
for (size_t i = 0; i < info->modules.modules_count; i++) {
char *module_name = read_string(fd);
if (module_name == NULL) {
PLOGE("reading module name");
info->modules->modules_count = i;
free_rezygisk_info(info);
info->modules = NULL;
info->modules->modules_count = 0;
close(fd);
return;
goto info_cleanup;
}
char module_path[PATH_MAX];
@@ -156,43 +145,49 @@ void rezygiskd_get_info(struct rezygisk_info *info) {
if (!module_prop) {
PLOGE("failed to open module prop file %s", module_path);
info->modules->modules_count = i;
free_rezygisk_info(info);
info->modules = NULL;
info->modules->modules_count = 0;
close(fd);
return;
goto info_cleanup;
}
info->modules.modules[i] = NULL;
char line[1024];
while (fgets(line, sizeof(line), module_prop) != NULL) {
if (strncmp(line, "name=", strlen("name=")) != 0) continue;
info->modules->modules[i] = strndup(line + 5, strlen(line) - 6);
info->modules.modules[i] = strndup(line + 5, strlen(line) - 6);
break;
}
if (info->modules.modules[i] == NULL) {
PLOGE("failed to read module name from %s", module_path);
fclose(module_prop);
goto info_cleanup;
}
fclose(module_prop);
continue;
info_cleanup:
info->modules.modules_count = i;
free_rezygisk_info(info);
break;
}
close(fd);
}
void free_rezygisk_info(struct rezygisk_info *info) {
if (info->modules->modules) {
for (size_t i = 0; i < info->modules->modules_count; i++) {
free(info->modules->modules[i]);
}
free(info->modules->modules);
for (size_t i = 0; i < info->modules.modules_count; i++) {
free(info->modules.modules[i]);
}
free(info->modules);
free(info->modules.modules);
info->modules.modules = NULL;
}
bool rezygiskd_read_modules(struct zygisk_modules *modules) {
@@ -237,13 +232,11 @@ bool rezygiskd_read_modules(struct zygisk_modules *modules) {
}
void free_modules(struct zygisk_modules *modules) {
if (modules->modules) {
for (size_t i = 0; i < modules->modules_count; i++) {
free(modules->modules[i]);
}
free(modules->modules);
for (size_t i = 0; i < modules->modules_count; i++) {
free(modules->modules[i]);
}
free(modules->modules);
}
int rezygiskd_connect_companion(size_t index) {

View File

@@ -5,6 +5,7 @@
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/auxv.h>
#include <unistd.h>
@@ -159,14 +160,14 @@ ElfImg *ElfImg_create(const char *elf, void *base) {
}
if (base) {
/* LOGI: Due to the use in zygisk-ptracer, we need to allow pre-
/* INFO: Due to the use in zygisk-ptracer, we need to allow pre-
fetched bases to be passed, as the linker (Android 7.1
and below) is not loaded from dlopen, which makes it not
be visible with dl_iterate_phdr.
*/
img->base = base;
LOGI("Using provided base address 0x%p for %s", base, elf);
LOGD("Using provided base address 0x%p for %s", base, elf);
} else {
if (!_find_module_base(img)) {
LOGE("Failed to find module base for %s using dl_iterate_phdr", elf);
@@ -387,7 +388,7 @@ ElfImg *ElfImg_create(const char *elf, void *base) {
img->symstr_offset_for_symtab = 0;
}
} else {
LOGI("No .symtab section found or section headers missing");
LOGD("No .symtab section found or section headers missing");
img->symtab_start = NULL;
img->symtab_count = 0;
@@ -403,43 +404,22 @@ ElfImg *ElfImg_create(const char *elf, void *base) {
img->bias = phdr[i].p_vaddr - phdr[i].p_offset;
bias_calculated = true;
LOGI("Calculated bias %ld from PT_LOAD segment %d (vaddr %lx)", (long)img->bias, i, (unsigned long)phdr[i].p_vaddr);
LOGD("Calculated bias %ld from PT_LOAD segment %d (vaddr %lx)", (long)img->bias, i, (unsigned long)phdr[i].p_vaddr);
break;
}
}
if (!bias_calculated) {
for (int i = 0; i < img->header->e_phnum; ++i) {
if (phdr[i].p_type == PT_LOAD) {
img->bias = phdr[i].p_vaddr - phdr[i].p_offset;
bias_calculated = true;
if (!bias_calculated) for (int i = 0; i < img->header->e_phnum; ++i) {
if (phdr[i].p_type != PT_LOAD) continue;
LOGI("Calculated bias %ld from first PT_LOAD segment %d (vaddr %lx, offset %lx)",
(long)img->bias, i, (unsigned long)phdr[i].p_vaddr, (unsigned long)phdr[i].p_offset);
img->bias = phdr[i].p_vaddr - phdr[i].p_offset;
bias_calculated = true;
break;
}
}
}
}
LOGD("Calculated bias %ld from first PT_LOAD segment %d (vaddr %lx, offset %lx)",
(long)img->bias, i, (unsigned long)phdr[i].p_vaddr, (unsigned long)phdr[i].p_offset);
if (!bias_calculated && shdr_base) {
LOGW("Could not calculate bias from program headers, falling back to section method.");
uintptr_t shoff_for_bias = (uintptr_t)shdr_base;
for (int i = 0; i < img->header->e_shnum; i++, shoff_for_bias += img->header->e_shentsize) {
ElfW(Shdr) *section_h = (ElfW(Shdr *))shoff_for_bias;
if ((section_h->sh_flags & SHF_ALLOC) && section_h->sh_addr != 0) {
img->bias = (off_t)section_h->sh_addr - (off_t)section_h->sh_offset;
bias_calculated = true;
char *sname = section_str ? (section_h->sh_name + section_str) : "<?>";
LOGI("Calculated bias %ld from first allocated section %s (addr %lx, offset %lx)",
(long)img->bias, sname, (unsigned long)section_h->sh_addr, (unsigned long)section_h->sh_offset);
break;
}
break;
}
}
@@ -523,7 +503,7 @@ bool _load_symtabs(ElfImg *img) {
return true;
}
ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash, unsigned char *sym_type) {
if (img->gnu_nbucket_ == 0 || img->gnu_bloom_size_ == 0 || !img->gnu_bloom_filter_ || !img->gnu_bucket_ || !img->gnu_chain_ || !img->dynsym_start || !img->strtab_start)
return 0;
@@ -545,7 +525,7 @@ ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
uint32_t sym_index = img->gnu_bucket_[hash % img->gnu_nbucket_];
if (sym_index < img->gnu_symndx_) {
LOGI("Symbol %s hash %u maps to bucket %u index %u (below gnu_symndx %u), not exported?", name, hash, hash % img->gnu_nbucket_, sym_index, img->gnu_symndx_);
LOGW("Symbol %s hash %u maps to bucket %u index %u (below gnu_symndx %u), not exported?", name, hash, hash % img->gnu_nbucket_, sym_index, img->gnu_symndx_);
return 0;
}
@@ -568,8 +548,12 @@ ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
return 0;
}
if ((((chain_val ^ hash) >> 1) == 0 && strcmp(name, strings + sym->st_name) == 0) && sym->st_shndx != SHN_UNDEF)
if ((((chain_val ^ hash) >> 1) == 0 && strcmp(name, strings + sym->st_name) == 0) && sym->st_shndx != SHN_UNDEF) {
unsigned int type = ELF_ST_TYPE(sym->st_info);
if (sym_type) *sym_type = type;
return sym->st_value;
}
while ((chain_val & 1) == 0) {
sym_index++;
@@ -589,14 +573,18 @@ ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
break;
}
if ((((chain_val ^ hash) >> 1) == 0 && strcmp(name, strings + sym->st_name) == 0) && sym->st_shndx != SHN_UNDEF)
if ((((chain_val ^ hash) >> 1) == 0 && strcmp(name, strings + sym->st_name) == 0) && sym->st_shndx != SHN_UNDEF) {
unsigned int type = ELF_ST_TYPE(sym->st_info);
if (sym_type) *sym_type = type;
return sym->st_value;
}
}
return 0;
}
ElfW(Addr) ElfLookup(ElfImg *restrict img, const char *restrict name, uint32_t hash) {
ElfW(Addr) ElfLookup(ElfImg *restrict img, const char *restrict name, uint32_t hash, unsigned char *sym_type) {
if (img->nbucket_ == 0 || !img->bucket_ || !img->chain_ || !img->dynsym_start || !img->strtab_start)
return 0;
@@ -605,14 +593,18 @@ ElfW(Addr) ElfLookup(ElfImg *restrict img, const char *restrict name, uint32_t h
for (size_t n = img->bucket_[hash % img->nbucket_]; n != STN_UNDEF; n = img->chain_[n]) {
ElfW(Sym) *sym = img->dynsym_start + n;
if (strcmp(name, strings + sym->st_name) == 0 && sym->st_shndx != SHN_UNDEF)
if (strcmp(name, strings + sym->st_name) == 0 && sym->st_shndx != SHN_UNDEF) {
unsigned int type = ELF_ST_TYPE(sym->st_info);
if (sym_type) *sym_type = type;
return sym->st_value;
}
}
return 0;
}
ElfW(Addr) LinearLookup(ElfImg *img, const char *restrict name) {
ElfW(Addr) LinearLookup(ElfImg *img, const char *restrict name, unsigned char *sym_type) {
if (!_load_symtabs(img)) {
LOGE("Failed to load symtabs for linear lookup of %s", name);
@@ -623,7 +615,7 @@ ElfW(Addr) LinearLookup(ElfImg *img, const char *restrict name) {
if (valid_symtabs_amount == 0) {
LOGW("No valid symbols (FUNC/OBJECT with size > 0) found in .symtab for %s", img->elf);
return false;
return 0;
}
for (size_t i = 0; i < valid_symtabs_amount; i++) {
@@ -633,13 +625,16 @@ ElfW(Addr) LinearLookup(ElfImg *img, const char *restrict name) {
if (img->symtabs_[i].sym->st_shndx == SHN_UNDEF)
continue;
unsigned int type = ELF_ST_TYPE(img->symtabs_[i].sym->st_info);
if (sym_type) *sym_type = type;
return img->symtabs_[i].sym->st_value;
}
return 0;
}
ElfW(Addr) LinearLookupByPrefix(ElfImg *img, const char *prefix) {
ElfW(Addr) LinearLookupByPrefix(ElfImg *img, const char *prefix, unsigned char *sym_type) {
if (!_load_symtabs(img)) {
LOGE("Failed to load symtabs for linear lookup by prefix of %s", prefix);
@@ -650,7 +645,7 @@ ElfW(Addr) LinearLookupByPrefix(ElfImg *img, const char *prefix) {
if (valid_symtabs_amount == 0) {
LOGW("No valid symbols (FUNC/OBJECT with size > 0) found in .symtab for %s", img->elf);
return false;
return 0;
}
size_t prefix_len = strlen(prefix);
@@ -666,45 +661,161 @@ ElfW(Addr) LinearLookupByPrefix(ElfImg *img, const char *prefix) {
if (img->symtabs_[i].sym->st_shndx == SHN_UNDEF)
continue;
unsigned int type = ELF_ST_TYPE(img->symtabs_[i].sym->st_info);
if (sym_type) *sym_type = type;
return img->symtabs_[i].sym->st_value;
}
return 0;
}
ElfW(Addr) getSymbOffset(ElfImg *img, const char *name) {
ElfW(Addr) getSymbOffset(ElfImg *img, const char *name, unsigned char *sym_type) {
ElfW(Addr) offset = 0;
offset = GnuLookup(img, name, GnuHash(name));
offset = GnuLookup(img, name, GnuHash(name), sym_type);
if (offset != 0) return offset;
offset = ElfLookup(img, name, ElfHash(name));
offset = ElfLookup(img, name, ElfHash(name), sym_type);
if (offset != 0) return offset;
offset = LinearLookup(img, name);
offset = LinearLookup(img, name, sym_type);
if (offset != 0) return offset;
return 0;
}
#ifdef __aarch64__
/* INFO: Struct containing information about hardware capabilities used in resolver. This
struct information is pulled directly from the AOSP code.
SOURCES:
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/libc/include/sys/ifunc.h#53
*/
struct __ifunc_arg_t {
unsigned long _size;
unsigned long _hwcap;
unsigned long _hwcap2;
};
/* INFO: This is a constant used in the AOSP code to indicate that the struct __ifunc_arg_t
contains hardware capabilities.
SOURCES:
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/libc/include/sys/ifunc.h#74
*/
#define _IFUNC_ARG_HWCAP (1ULL << 62)
#elif defined(__riscv)
/* INFO: Struct used in Linux RISC-V architecture to probe hardware capabilities.
SOURCES:
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/libc/kernel/uapi/asm-riscv/asm/hwprobe.h#10
*/
struct riscv_hwprobe {
int64_t key;
uint64_t value;
};
/* INFO: This function is used in the AOSP code to probe hardware capabilities on RISC-V architecture
by calling the syscall __NR_riscv_hwprobe and passing the parameters that will filled with
the device hardware capabilities.
SOURCES:
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/libc/bionic/vdso.cpp#86
*/
int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, size_t cpu_count, unsigned long *cpus, unsigned flags) {
register long a0 __asm__("a0") = (long)pairs;
register long a1 __asm__("a1") = pair_count;
register long a2 __asm__("a2") = cpu_count;
register long a3 __asm__("a3") = (long)cpus;
register long a4 __asm__("a4") = flags;
register long a7 __asm__("a7") = __NR_riscv_hwprobe;
__asm__ volatile(
"ecall"
: "=r"(a0)
: "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a7)
);
return -a0;
}
/* INFO: This is a function pointer type that points how the signature of the __riscv_hwprobe
function is.
SOURCES:
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/libc/include/sys/hwprobe.h#62
*/
typedef int (*__riscv_hwprobe_t)(struct riscv_hwprobe *__pairs, size_t __pair_count, size_t __cpu_count, unsigned long *__cpus, unsigned __flags);
#endif
/* INFO: GNU ifuncs (indirect functions) are functions that does not execute the code by itself,
but instead lead to other functions that may very according to hardware capabilities,
or other reasons, depending of the architecture.
This function is based on AOSP's (Android Open Source Project) code, and resolves the
indirect symbol, leading to the correct, most appropriate for the hardware, symbol.
SOURCES:
- https://android.googlesource.com/platform/bionic/+/refs/tags/android-16.0.0_r1/linker/linker.cpp#2594
- https://android.googlesource.com/platform/bionic/+/tags/android-16.0.0_r1/libc/bionic/bionic_call_ifunc_resolver.cpp#41
*/
static ElfW(Addr) handle_indirect_symbol(ElfImg *img, ElfW(Off) offset) {
ElfW(Addr) resolver_addr = (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
#ifdef __aarch64__
typedef ElfW(Addr) (*ifunc_resolver_t)(uint64_t, struct __ifunc_arg_t *);
struct __ifunc_arg_t args = {
._size = sizeof(struct __ifunc_arg_t),
._hwcap = getauxval(AT_HWCAP),
._hwcap2 = getauxval(AT_HWCAP2)
};
return ((ifunc_resolver_t)resolver_addr)(args._hwcap | _IFUNC_ARG_HWCAP, &args);
#elif defined(__arm__)
typedef ElfW(Addr) (*ifunc_resolver_t)(unsigned long);
return ((ifunc_resolver_t)resolver_addr)(getauxval(AT_HWCAP));
#elif defined(__riscv)
typedef ElfW(Addr) (*ifunc_resolver_t)(uint64_t, __riscv_hwprobe_t, void *);
return ((ifunc_resolver_t)resolver_addr)(getauxval(AT_HWCAP), __riscv_hwprobe, NULL);
#else
typedef ElfW(Addr) (*ifunc_resolver_t)(void);
return ((ifunc_resolver_t)resolver_addr)();
#endif
}
ElfW(Addr) getSymbAddress(ElfImg *img, const char *name) {
ElfW(Addr) offset = getSymbOffset(img, name);
unsigned char sym_type = 0;
ElfW(Addr) offset = getSymbOffset(img, name, &sym_type);
if (offset == 0 || !img->base) return 0;
ElfW(Addr) address = (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
if (sym_type == STT_GNU_IFUNC) {
LOGD("Resolving STT_GNU_IFUNC symbol %s", name);
return address;
return handle_indirect_symbol(img, offset);
}
return (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
}
ElfW(Addr) getSymbAddressByPrefix(ElfImg *img, const char *prefix) {
ElfW(Addr) offset = LinearLookupByPrefix(img, prefix);
unsigned char sym_type = 0;
ElfW(Addr) offset = LinearLookupByPrefix(img, prefix, &sym_type);
if (offset == 0 || !img->base) return 0;
ElfW(Addr) address = (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
if (sym_type == STT_GNU_IFUNC) {
LOGD("Resolving STT_GNU_IFUNC symbol by prefix %s", prefix);
return address;
return handle_indirect_symbol(img, offset);
}
return (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
}
void *getSymbValueByPrefix(ElfImg *img, const char *prefix) {

View File

@@ -25,7 +25,7 @@ int read_fd(int fd) {
.msg_controllen = sizeof(cmsgbuf)
};
ssize_t ret = recvmsg(fd, &msg, MSG_WAITALL);
ssize_t ret = TEMP_FAILURE_RETRY(recvmsg(fd, &msg, MSG_WAITALL));
if (ret == -1) {
PLOGE("recvmsg");
@@ -47,14 +47,14 @@ int read_fd(int fd) {
ssize_t write_string(int fd, const char *str) {
size_t str_len = strlen(str);
ssize_t write_bytes = write(fd, &str_len, sizeof(size_t));
ssize_t write_bytes = TEMP_FAILURE_RETRY(write(fd, &str_len, sizeof(size_t)));
if (write_bytes != (ssize_t)sizeof(size_t)) {
LOGE("Failed to write string length: Not all bytes were written (%zd != %zu).\n", write_bytes, sizeof(size_t));
return -1;
}
write_bytes = write(fd, str, str_len);
write_bytes = TEMP_FAILURE_RETRY(write(fd, str, str_len));
if (write_bytes != (ssize_t)str_len) {
LOGE("Failed to write string: Promised bytes doesn't exist (%zd != %zu).\n", write_bytes, str_len);
@@ -66,7 +66,7 @@ ssize_t write_string(int fd, const char *str) {
char *read_string(int fd) {
size_t str_len = 0;
ssize_t read_bytes = read(fd, &str_len, sizeof(size_t));
ssize_t read_bytes = TEMP_FAILURE_RETRY(read(fd, &str_len, 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));
@@ -80,7 +80,7 @@ char *read_string(int fd) {
return NULL;
}
read_bytes = read(fd, buf, str_len);
read_bytes = TEMP_FAILURE_RETRY(read(fd, buf, str_len));
if (read_bytes != (ssize_t)str_len) {
LOGE("Failed to read string: Promised bytes doesn't exist (%zd != %zu).\n", read_bytes, str_len);
@@ -94,14 +94,14 @@ char *read_string(int fd) {
return buf;
}
#define write_func(type) \
ssize_t write_## type(int fd, type val) { \
return write(fd, &val, sizeof(type)); \
#define write_func(type) \
ssize_t write_## type(int fd, type val) { \
return TEMP_FAILURE_RETRY(write(fd, &val, sizeof(type))); \
}
#define read_func(type) \
ssize_t read_## type(int fd, type *val) { \
return read(fd, val, sizeof(type)); \
#define read_func(type) \
ssize_t read_## type(int fd, type *val) { \
return TEMP_FAILURE_RETRY(read(fd, val, sizeof(type))); \
}
write_func(uint8_t)

View File

@@ -42,7 +42,7 @@ enum root_impl {
};
struct rezygisk_info {
struct zygisk_modules *modules;
struct zygisk_modules modules;
enum root_impl root_impl;
pid_t pid;
bool running;

View File

@@ -1,13 +1,20 @@
#ifndef ELF_UTIL_H
#define ELF_UTIL_H
#include <stdbool.h>
#include <string.h>
#include <link.h>
#include <linux/elf.h>
#include <sys/types.h>
#include <pthread.h> // Added for threading primitives
#define SHT_GNU_HASH 0x6ffffff6
// Function pointer types for constructors and destructors
typedef void (*linker_simple_func_t)(void);
typedef void (*linker_ctor_function_t)(int, char**, char**);
typedef void (*linker_dtor_function_t)(void);
struct symtabs {
char *name;
ElfW(Sym) *sym;
@@ -54,17 +61,7 @@ void ElfImg_destroy(ElfImg *img);
ElfImg *ElfImg_create(const char *elf, void *base);
ElfW(Addr) ElfLookup(ElfImg *restrict img, const char *restrict name, uint32_t hash);
ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *restrict name, uint32_t hash);
ElfW(Addr) LinearLookup(ElfImg *restrict img, const char *restrict name);
ElfW(Addr) LinearLookupByPrefix(ElfImg *restrict img, const char *name);
int dl_cb(struct dl_phdr_info *info, size_t size, void *data);
ElfW(Addr) getSymbOffset(ElfImg *img, const char *name);
ElfW(Addr) getSymbOffset(ElfImg *img, const char *name, unsigned char *sym_type);
ElfW(Addr) getSymbAddress(ElfImg *img, const char *name);

View File

@@ -1,5 +1,6 @@
#include "daemon.h"
#include "logging.h"
#include "solist.h"
#include "zygisk.hpp"
using namespace std;
@@ -8,7 +9,7 @@ void *start_addr = nullptr;
size_t block_size = 0;
extern "C" [[gnu::visibility("default")]]
void entry(void* addr, size_t size, const char* path) {
void entry(void *addr, size_t size) {
LOGD("Zygisk library injected, version %s", ZKSU_VERSION);
start_addr = addr;
@@ -23,7 +24,10 @@ void entry(void* addr, size_t size, const char* path) {
LOGD("start plt hooking");
hook_functions();
void *module_addrs[1] = { addr };
clean_trace(path, module_addrs, 1, 1, 0);
solist_drop_so_path(addr, true);
solist_reset_counters(1, 1);
send_seccomp_event();
LOGD("Zygisk library execution done, addr: %p, size: %zu", addr, size);
}

View File

@@ -734,24 +734,23 @@ void ZygiskContext::run_modules_post() {
if (flags[APP_SPECIALIZE]) m.postAppSpecialize(args.app);
else if (flags[SERVER_FORK_AND_SPECIALIZE]) m.postServerSpecialize(args.server);
/* INFO: If module is unloaded by dlclose, there's no need to
hide it from soinfo manually. */
if (m.tryUnload()) modules_unloaded++;
else {
bool has_dropped = solist_drop_so_path(m.getEntry(), false);
if (!has_dropped) continue;
LOGD("Dropped solist record for %p", m.getEntry());
}
}
if (modules.size() > 0) {
LOGD("modules unloaded: %zu/%zu", modules_unloaded, modules.size());
LOGD("Modules unloaded: %zu/%zu", modules_unloaded, modules.size());
/* INFO: While Variable Length Arrays (VLAs) aren't usually
recommended due to the ease of using too much of the
stack, this should be fine since it should not be
possible to exhaust the stack with only a few addresses. */
void *module_addrs[modules.size() * sizeof(void *)];
solist_reset_counters(modules.size(), modules_unloaded);
size_t i = 0;
for (const auto &m : modules) {
module_addrs[i++] = m.getEntry();
}
clean_trace("/data/adb", module_addrs, modules.size(), modules.size(), modules_unloaded);
LOGD("Returned global counters to their original values");
}
}
@@ -1006,22 +1005,6 @@ static void hook_register(dev_t dev, ino_t inode, const char *symbol, void *new_
#define PLT_HOOK_REGISTER(DEV, INODE, NAME) \
PLT_HOOK_REGISTER_SYM(DEV, INODE, #NAME, NAME)
/* INFO: module_addrs_length is always the same as "load" */
void clean_trace(const char *path, void **module_addrs, size_t module_addrs_length, size_t load, size_t unload) {
LOGD("cleaning trace for path %s", path);
if (load > 0 || unload > 0) solist_reset_counters(load, unload);
LOGD("Dropping solist record for %s", path);
for (size_t i = 0; i < module_addrs_length; i++) {
bool has_dropped = solist_drop_so_path(module_addrs[i]);
if (!has_dropped) continue;
LOGD("Dropped solist record for %p", module_addrs[i]);
}
}
void hook_functions() {
plt_hook_list = new vector<tuple<dev_t, ino_t, const char *, void **>>();
jni_hook_list = new map<string, vector<JNINativeMethod>>();

View File

@@ -1,8 +1,7 @@
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <android/dlext.h>
#include <dlfcn.h>
#include <linux/limits.h>
@@ -24,6 +23,7 @@
static const char *(*get_realpath_sym)(SoInfo *) = NULL;
static void (*soinfo_free)(SoInfo *) = NULL;
static SoInfo *(*find_containing_library)(const void *p) = NULL;
static void (*purge_unused_memory)(void) = NULL;
static inline const char *get_path(SoInfo *self) {
if (get_realpath_sym)
@@ -104,6 +104,8 @@ static bool solist_init() {
ElfImg_destroy(linker);
somain = NULL;
return false;
}
@@ -115,6 +117,8 @@ static bool solist_init() {
ElfImg_destroy(linker);
somain = NULL;
return false;
}
@@ -126,9 +130,26 @@ static bool solist_init() {
ElfImg_destroy(linker);
somain = NULL;
return false;
}
LOGD("%p is find_containing_library", (void *)find_containing_library);
purge_unused_memory = (void (*)())getSymbAddress(linker, "__dl__Z19purge_unused_memoryv");
if (purge_unused_memory == NULL) {
LOGE("Failed to find purge_unused_memory __dl__Z19purge_unused_memoryv");
ElfImg_destroy(linker);
somain = NULL;
return false;
}
LOGD("%p is purge_unused_memory", (void *)purge_unused_memory);
g_module_load_counter = (size_t *)getSymbAddress(linker, "__dl__ZL21g_module_load_counter");
if (g_module_load_counter != NULL) LOGD("found symbol g_module_load_counter");
@@ -154,7 +175,7 @@ static bool solist_init() {
/* INFO: find_containing_library returns the SoInfo for the library that contains
that memory inside its limits, hence why named "lib_memory" in ReZygisk. */
bool solist_drop_so_path(void *lib_memory) {
bool solist_drop_so_path(void *lib_memory, bool unload) {
if (somain == NULL && !solist_init()) {
LOGE("Failed to initialize solist");
@@ -165,6 +186,8 @@ bool solist_drop_so_path(void *lib_memory) {
if (found == NULL) {
LOGD("Could not find containing library for %p", lib_memory);
purge_unused_memory();
return false;
}
@@ -176,16 +199,44 @@ bool solist_drop_so_path(void *lib_memory) {
return false;
}
strcpy(path, get_path(found));
strncpy(path, get_path(found), sizeof(path) - 1);
/* INFO: This area is guarded. Must unprotect first. */
pdg_unprotect();
set_size(found, 0);
soinfo_free(found);
if (unload) pdg_protect();
pdg_protect();
LOGD("Set size of %p to 0", (void *)found);
LOGD("Successfully dropped so path for: %s", path);
/* INFO: We know that as libzygisk.so our limits, but modules are arbitrary, so
calling deconstructors might break them. To avoid that, we manually call
the separated structures, that however won't clean all traces in soinfo,
not for now, at least. */
if (unload && dlclose((void *)found) == -1) {
LOGE("Failed to dlclose so path for %s: %s", path, dlerror());
return false;
} else if (!unload) {
LOGD("Not unloading so path for %s, only dropping it", path);
/* TODO: call notify_gdb_of_unload(found); (it is static) to avoid leaving traces in
r_debug_tail.
SOURCES:
- https://android.googlesource.com/platform/bionic/+/refs/heads/main/linker/linker_gdb_support.cpp#94
*/
/* INFO: unregister_soinfo_tls cannot be used since module might use JNI which may
require TLS, so we cannot remove it. */
soinfo_free(found);
pdg_protect();
}
LOGD("Successfully hidden soinfo traces for %s", path);
/* INFO: Avoid leaks by ensuring the freed places are munmapped */
purge_unused_memory();
LOGD("Purged unused memory successfully");
/* INFO: Let's avoid trouble regarding detections */
memset(path, strlen(path), 0);

View File

@@ -5,11 +5,7 @@
extern "C" {
#endif /* __cplusplus */
typedef struct SoInfo SoInfo;
struct SoInfo {
char data[0];
};
typedef void SoInfo;
#define FuncType(name) void (*name)
@@ -28,14 +24,20 @@ struct pdg {
libzygisk.so, so that it doesn't create gaps between current module info
and the next (soinfo).
To do that, we use 2 functions: soinfo_free, and set_size, which will
zero the region size, and then remove all traces of that library (libzygisk.so)
which was previously loaded.
To do that, we use 2 functions: set_size and dlclose, which will first zero
zero the size that the linker believes the shared library is, and then dlclose.
Because the size is 0, it won't munmap the library, allowing us to keep loaded while
having all other traces removed.
For the case of modules, which are arbitrary, we won't call dlclose, as it could break
the module. Instead of using dlclose, we separately call soinfo_free, which will free
the soinfo structure. That will allow to keep the data initialized by constructors
mmaped, hence properly dropping most traces without breaking the module.
SOURCES:
- https://android.googlesource.com/platform/bionic/+/refs/heads/android15-release/linker/linker.cpp#1712
*/
bool solist_drop_so_path(void *lib_memory);
bool solist_drop_so_path(void *lib_memory, bool unload);
/*
INFO: When dlopen'ing a library, the system will increment 1 to a global

View File

@@ -7,6 +7,4 @@ extern size_t block_size;
void hook_functions();
void clean_trace(const char *path, void **module_addrs, size_t module_addrs_length, size_t load, size_t unload);
extern "C" void send_seccomp_event();

View File

@@ -77,11 +77,11 @@ int main(int argc, char **argv) {
}
}
if (info.modules->modules_count != 0) {
printf("Modules: %zu\n", info.modules->modules_count);
if (info.modules.modules_count != 0) {
printf("Modules: %zu\n", info.modules.modules_count);
for (size_t i = 0; i < info.modules->modules_count; i++) {
printf(" - %s\n", info.modules->modules[i]);
for (size_t i = 0; i < info.modules.modules_count; i++) {
printf(" - %s\n", info.modules.modules[i]);
}
} else {
printf("Modules: N/A\n");

View File

@@ -66,6 +66,7 @@ struct rezygiskd_status status32 = {
int monitor_epoll_fd;
bool monitor_events_running = true;
typedef void (*monitor_event_callback_t)();
bool monitor_events_init() {
monitor_epoll_fd = epoll_create(1);
@@ -78,14 +79,9 @@ bool monitor_events_init() {
return true;
}
struct monitor_event_cbs {
void (*callback)();
void (*stop_callback)();
};
bool monitor_events_register_event(struct monitor_event_cbs *event_cbs, int fd, uint32_t events) {
bool monitor_events_register_event(monitor_event_callback_t event_cb, int fd, uint32_t events) {
struct epoll_event ev = {
.data.ptr = event_cbs,
.data.ptr = (void *)event_cb,
.events = events
};
@@ -116,15 +112,16 @@ void monitor_events_loop() {
struct epoll_event events[2];
while (monitor_events_running) {
int nfds = epoll_wait(monitor_epoll_fd, events, 2, -1);
if (nfds == -1) {
if (errno != EINTR) PLOGE("epoll_wait");
if (nfds == -1 && errno != EINTR) {
PLOGE("epoll_wait");
continue;
monitor_events_running = false;
break;
}
for (int i = 0; i < nfds; i++) {
struct monitor_event_cbs *event_cbs = (struct monitor_event_cbs *)events[i].data.ptr;
event_cbs->callback();
for (int i = 0; i < nfds; i++) {
((monitor_event_callback_t)events[i].data.ptr)();
if (!monitor_events_running) break;
}
@@ -132,11 +129,6 @@ void monitor_events_loop() {
if (monitor_epoll_fd >= 0) close(monitor_epoll_fd);
monitor_epoll_fd = -1;
for (int i = 0; i < (int)(sizeof(events) / sizeof(events[0])); i++) {
struct monitor_event_cbs *event_cbs = (struct monitor_event_cbs *)events[i].data.ptr;
event_cbs->stop_callback();
}
}
int monitor_sock_fd;
@@ -272,15 +264,13 @@ void rezygiskd_listener_callback() {
status64.daemon_info = NULL;
}
status64.daemon_info = (char *)malloc(msg.length);
status64.daemon_info = strdup(msg_data);
if (!status64.daemon_info) {
PLOGE("malloc daemon64 info");
break;
}
strcpy(status64.daemon_info, msg_data);
update_status(NULL);
break;
@@ -293,15 +283,13 @@ void rezygiskd_listener_callback() {
status32.daemon_info = NULL;
}
status32.daemon_info = (char *)malloc(msg.length);
status32.daemon_info = strdup(msg_data);
if (!status32.daemon_info) {
PLOGE("malloc daemon32 info");
break;
}
strcpy(status32.daemon_info, msg_data);
update_status(NULL);
break;
@@ -316,15 +304,13 @@ void rezygiskd_listener_callback() {
status64.daemon_error_info = NULL;
}
status64.daemon_error_info = (char *)malloc(msg.length);
status64.daemon_error_info = strdup(msg_data);
if (!status64.daemon_error_info) {
PLOGE("malloc daemon64 error info");
break;
}
strcpy(status64.daemon_error_info, msg_data);
update_status(NULL);
break;
@@ -339,15 +325,13 @@ void rezygiskd_listener_callback() {
status32.daemon_error_info = NULL;
}
status32.daemon_error_info = (char *)malloc(msg.length);
status32.daemon_error_info = strdup(msg_data);
if (!status32.daemon_error_info) {
PLOGE("malloc daemon32 error info");
break;
}
strcpy(status32.daemon_error_info, msg_data);
update_status(NULL);
break;
@@ -847,10 +831,6 @@ void init_monitor() {
monitor_events_init();
struct monitor_event_cbs listener_cbs = {
.callback = rezygiskd_listener_callback,
.stop_callback = rezygiskd_listener_stop
};
if (!rezygiskd_listener_init()) {
LOGE("failed to create socket");
@@ -859,12 +839,8 @@ void init_monitor() {
exit(1);
}
monitor_events_register_event(&listener_cbs, monitor_sock_fd, EPOLLIN | EPOLLET);
monitor_events_register_event(rezygiskd_listener_callback, monitor_sock_fd, EPOLLIN | EPOLLET);
struct monitor_event_cbs sigchld_cbs = {
.callback = sigchld_listener_callback,
.stop_callback = sigchld_listener_stop
};
if (sigchld_listener_init() == false) {
LOGE("failed to create signalfd");
@@ -874,10 +850,15 @@ void init_monitor() {
exit(1);
}
monitor_events_register_event(&sigchld_cbs, sigchld_signal_fd, EPOLLIN | EPOLLET);
monitor_events_register_event(sigchld_listener_callback, sigchld_signal_fd, EPOLLIN | EPOLLET);
monitor_events_loop();
/* INFO: Once it stops the loop, we cannot access the epool data, so we
either manually call the stops or save to a structure. */
rezygiskd_listener_stop();
sigchld_listener_stop();
if (status64.daemon_info) free(status64.daemon_info);
if (status64.daemon_error_info) free(status64.daemon_error_info);
if (status32.daemon_info) free(status32.daemon_info);

View File

@@ -161,13 +161,15 @@ bool inject_on_main(int pid, const char *lib_path) {
const char *libdl_path = NULL;
const char *libc_path = NULL;
for (size_t i = 0; i < local_map->size; i++) {
if (local_map->maps[i].path == NULL) continue;
for (size_t i = 0; i < map->size; i++) {
if (map->maps[i].path == NULL) continue;
const char *filename = position_after(local_map->maps[i].path, '/');
const char *filename = position_after(map->maps[i].path, '/');
if (strcmp(filename, "libdl.so") == 0) {
libdl_path = local_map->maps[i].path;
if (!libdl_path && strcmp(filename, "libdl.so") == 0) {
libdl_path = map->maps[i].path;
LOGD("found libdl.so at %s", libdl_path);
/* INFO: If we had found libc.so too, no need to continue searching */
if (libc_path) break;
@@ -175,8 +177,10 @@ bool inject_on_main(int pid, const char *lib_path) {
continue;
}
if (strcmp(filename, "libc.so") == 0) {
libc_path = local_map->maps[i].path;
if (!libc_path && strcmp(filename, "libc.so") == 0) {
libc_path = map->maps[i].path;
LOGD("found libc.so at %s", libc_path);
/* INFO: If we had found libdl.so too, no need to continue searching */
if (libdl_path) break;
@@ -364,10 +368,8 @@ bool inject_on_main(int pid, const char *lib_path) {
/* call injector entry(start_addr, block_size, path) */
args[0] = (uintptr_t)start_addr;
args[1] = block_size;
str = push_string(pid, &regs, rezygiskd_get_path());
args[2] = (uintptr_t)str;
remote_call(pid, &regs, injector_entry, (uintptr_t)libc_return_addr, args, 3);
remote_call(pid, &regs, injector_entry, (uintptr_t)libc_return_addr, args, 2);
free(args);

View File

@@ -119,8 +119,8 @@ struct maps *parse_maps(const char *filename) {
path_offset++;
}
maps->maps = (struct map *)realloc(maps->maps, (i + 1) * sizeof(struct map));
if (!maps->maps) {
struct map *tmp_maps = (struct map *)realloc(maps->maps, (i + 1) * sizeof(struct map));
if (!tmp_maps) {
LOGE("Failed to allocate memory for maps->maps");
maps->size = i;
@@ -130,6 +130,7 @@ struct maps *parse_maps(const char *filename) {
return NULL;
}
maps->maps = tmp_maps;
maps->maps[i].start = addr_start;
maps->maps[i].end = addr_end;

View File

@@ -153,7 +153,14 @@ void companion_entry(int fd) {
LOGI("New companion request.\n - Module name: %s\n - Client fd: %d\n", name, client_fd);
ret = write_uint8_t(client_fd, 1);
ASSURE_SIZE_WRITE("ZygiskdCompanion", "client_fd", ret, sizeof(uint8_t));
if (ret != sizeof(uint8_t)) {
LOGE("Failed to sent client_fd in ZygiskdCompanion: Expected %zu, got %zd\n", sizeof(uint8_t), ret);
free(args);
close(client_fd);
break;
}
pthread_t thread;
if (pthread_create(&thread, NULL, entry_thread, (void *)args) == 0)

View File

@@ -73,6 +73,14 @@ struct packages_config {
size_t size;
};
void _apatch_free_package_config(struct packages_config *restrict config) {
for (size_t i = 0; i < config->size; i++) {
free(config->configs[i].process);
}
free(config->configs);
}
/* WARNING: Dynamic memory based */
bool _apatch_get_package_config(struct packages_config *restrict config) {
config->configs = NULL;
@@ -96,14 +104,16 @@ bool _apatch_get_package_config(struct packages_config *restrict config) {
}
while (fgets(line, sizeof(line), fp) != NULL) {
config->configs = realloc(config->configs, (config->size + 1) * sizeof(struct package_config));
if (config->configs == NULL) {
struct package_config *tmp_configs = realloc(config->configs, (config->size + 1) * sizeof(struct package_config));
if (tmp_configs == NULL) {
LOGE("Failed to realloc APatch config struct: %s\n", strerror(errno));
_apatch_free_package_config(config);
fclose(fp);
return false;
}
config->configs = tmp_configs;
config->configs[config->size].process = strdup(strtok(line, ","));
@@ -128,21 +138,9 @@ bool _apatch_get_package_config(struct packages_config *restrict config) {
return true;
}
void _apatch_free_package_config(struct packages_config *restrict config) {
for (size_t i = 0; i < config->size; i++) {
free(config->configs[i].process);
}
free(config->configs);
}
bool apatch_uid_granted_root(uid_t uid) {
struct packages_config config;
if (!_apatch_get_package_config(&config)) {
_apatch_free_package_config(&config);
return false;
}
if (!_apatch_get_package_config(&config)) return false;
for (size_t i = 0; i < config.size; i++) {
if (config.configs[i].uid != uid) continue;
@@ -162,11 +160,7 @@ bool apatch_uid_granted_root(uid_t uid) {
bool apatch_uid_should_umount(uid_t uid, const char *const process) {
struct packages_config config;
if (!_apatch_get_package_config(&config)) {
_apatch_free_package_config(&config);
return false;
}
if (!_apatch_get_package_config(&config)) return false;
for (size_t i = 0; i < config.size; i++) {
if (config.configs[i].uid != uid) continue;

View File

@@ -74,8 +74,7 @@ void root_impls_setup(void) {
}
void get_impl(struct root_impl *uimpl) {
uimpl->impl = impl.impl;
uimpl->variant = impl.variant;
*uimpl = impl;
}
bool uid_granted_root(uid_t uid) {

View File

@@ -109,12 +109,9 @@ static void get_current_attr(char *restrict output, size_t size) {
return;
}
if (fread(output, 1, size, current) == 0) {
if (fread(output, 1, size, current) == 0)
LOGE("fread: %s\n", strerror(errno));
return;
}
fclose(current);
}
@@ -543,15 +540,13 @@ bool parse_mountinfo(const char *restrict pid, struct mountinfos *restrict mount
&optional_start, &optional_end, &type_start, &type_end,
&source_start, &source_end, &fs_option_start, &fs_option_end);
mounts->mounts = (struct mountinfo *)realloc(mounts->mounts, (i + 1) * sizeof(struct mountinfo));
if (!mounts->mounts) {
struct mountinfo *tmp_mounts = (struct mountinfo *)realloc(mounts->mounts, (i + 1) * sizeof(struct mountinfo));
if (!tmp_mounts) {
LOGE("Failed to allocate memory for mounts->mounts");
fclose(mountinfo);
free_mounts(mounts);
return false;
goto cleanup_mount_allocs;
}
mounts->mounts = tmp_mounts;
unsigned int shared = 0;
unsigned int master = 0;
@@ -572,16 +567,64 @@ bool parse_mountinfo(const char *restrict pid, struct mountinfos *restrict mount
mounts->mounts[i].parent = parent;
mounts->mounts[i].device = (dev_t)(makedev(maj, min));
mounts->mounts[i].root = strndup(line + root_start, (size_t)(root_end - root_start));
if (mounts->mounts[i].root == NULL) {
LOGE("Failed to allocate memory for root\n");
goto cleanup_mount_allocs;
}
mounts->mounts[i].target = strndup(line + target_start, (size_t)(target_end - target_start));
if (mounts->mounts[i].target == NULL) {
LOGE("Failed to allocate memory for target\n");
goto cleanup_root;
}
mounts->mounts[i].vfs_option = strndup(line + vfs_option_start, (size_t)(vfs_option_end - vfs_option_start));
if (mounts->mounts[i].vfs_option == NULL) {
LOGE("Failed to allocate memory for vfs_option\n");
goto cleanup_target;
}
mounts->mounts[i].optional.shared = shared;
mounts->mounts[i].optional.master = master;
mounts->mounts[i].optional.propagate_from = propagate_from;
mounts->mounts[i].type = strndup(line + type_start, (size_t)(type_end - type_start));
if (mounts->mounts[i].type == NULL) {
LOGE("Failed to allocate memory for type\n");
goto cleanup_vfs_option;
}
mounts->mounts[i].source = strndup(line + source_start, (size_t)(source_end - source_start));
if (mounts->mounts[i].source == NULL) {
LOGE("Failed to allocate memory for source\n");
goto cleanup_type;
}
mounts->mounts[i].fs_option = strndup(line + fs_option_start, (size_t)(fs_option_end - fs_option_start));
if (mounts->mounts[i].fs_option == NULL) {
LOGE("Failed to allocate memory for fs_option\n");
goto cleanup_source;
}
i++;
continue;
cleanup_source:
free((void *)mounts->mounts[i].source);
cleanup_type:
free((void *)mounts->mounts[i].type);
cleanup_vfs_option:
free((void *)mounts->mounts[i].vfs_option);
cleanup_target:
free((void *)mounts->mounts[i].target);
cleanup_root:
free((void *)mounts->mounts[i].root);
cleanup_mount_allocs:
fclose(mountinfo);
free_mounts(mounts);
return false;
}
fclose(mountinfo);

View File

@@ -123,7 +123,6 @@ static void load_modules(enum Architecture arch, struct Context *restrict contex
continue;
}
context->modules = realloc(context->modules, (size_t)((context->len + 1) * sizeof(struct Module)));
if (context->modules == NULL) {
LOGE("Failed reallocating memory for modules.\n");
@@ -143,8 +142,10 @@ static void load_modules(enum Architecture arch, struct Context *restrict contex
static void free_modules(struct Context *restrict context) {
for (size_t i = 0; i < context->len; i++) {
free(context->modules[i].name);
if (context->modules[i].companion != -1) close(context->modules[i].companion);
if (context->modules[i].companion >= 0) close(context->modules[i].companion);
}
free(context->modules);
}
static int create_daemon_socket(void) {
@@ -288,7 +289,7 @@ void zygiskd_start(char *restrict argv[]) {
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead));
unix_datagram_sendto(CONTROLLER_SOCKET, msg_data, (size_t)msg.length);
free(msg_data);
exit(EXIT_FAILURE);
} else {
enum Architecture arch = get_arch();
load_modules(arch, &context);
@@ -301,12 +302,24 @@ void zygiskd_start(char *restrict argv[]) {
} else {
for (size_t i = 0; i < context.len; i++) {
if (i != context.len - 1) {
module_list = realloc(module_list, module_list_len + strlen(context.modules[i].name) + strlen(", ") + 1);
if (module_list == NULL) {
char *tmp_module_list = realloc(module_list, module_list_len + strlen(context.modules[i].name) + strlen(", ") + 1);
if (tmp_module_list == NULL) {
LOGE("Failed reallocating memory for module list.\n");
return;
char *kmsg_failure = "Failed reallocating memory for module list";
struct MsgHead msg = {
.cmd = DAEMON_SET_ERROR_INFO,
.length = (int)strlen(kmsg_failure) + 1
};
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead));
unix_datagram_sendto(CONTROLLER_SOCKET, kmsg_failure, (size_t)msg.length);
free(module_list);
free_modules(&context);
exit(EXIT_FAILURE);
}
module_list = tmp_module_list;
strcpy(module_list + module_list_len, context.modules[i].name);
@@ -316,12 +329,24 @@ void zygiskd_start(char *restrict argv[]) {
module_list_len += strlen(", ");
} else {
module_list = realloc(module_list, module_list_len + strlen(context.modules[i].name) + 1);
if (module_list == NULL) {
char *tmp_module_list = realloc(module_list, module_list_len + strlen(context.modules[i].name) + 1);
if (tmp_module_list == NULL) {
LOGE("Failed reallocating memory for module list.\n");
return;
char *kmsg_failure = "Failed reallocating memory for module list";
struct MsgHead msg = {
.cmd = DAEMON_SET_ERROR_INFO,
.length = (int)strlen(kmsg_failure) + 1
};
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead));
unix_datagram_sendto(CONTROLLER_SOCKET, kmsg_failure, (size_t)msg.length);
free(module_list);
free_modules(&context);
exit(EXIT_FAILURE);
}
module_list = tmp_module_list;
strcpy(module_list + module_list_len, context.modules[i].name);
@@ -344,7 +369,16 @@ void zygiskd_start(char *restrict argv[]) {
if (msg_data == NULL) {
LOGE("Failed allocating memory for message data.\n");
return;
char *kmsg_failure = "Failed allocating memory for message data";
msg.cmd = DAEMON_SET_ERROR_INFO;
msg.length = (int)strlen(kmsg_failure) + 1;
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead));
unix_datagram_sendto(CONTROLLER_SOCKET, kmsg_failure, (size_t)msg.length);
free(module_list);
free_modules(&context);
exit(EXIT_FAILURE);
}
snprintf(msg_data, msg_length, "Root: %s, Modules: %s", impl_name, module_list);
@@ -360,6 +394,8 @@ void zygiskd_start(char *restrict argv[]) {
if (socket_fd == -1) {
LOGE("Failed creating daemon socket\n");
free_modules(&context);
return;
}
@@ -372,7 +408,7 @@ void zygiskd_start(char *restrict argv[]) {
if (client_fd == -1) {
LOGE("accept: %s\n", strerror(errno));
return;
break;
}
uint8_t action8 = 0;
@@ -380,11 +416,11 @@ void zygiskd_start(char *restrict argv[]) {
if (len == -1) {
LOGE("read: %s\n", strerror(errno));
return;
break;
} else if (len == 0) {
LOGI("Client disconnected\n");
return;
break;
}
enum DaemonSocketAction action = (enum DaemonSocketAction)action8;
@@ -402,10 +438,10 @@ void zygiskd_start(char *restrict argv[]) {
}
case ZygoteRestart: {
for (size_t i = 0; i < context.len; i++) {
if (context.modules[i].companion != -1) {
close(context.modules[i].companion);
context.modules[i].companion = -1;
}
if (context.modules[i].companion <= -1) continue;
close(context.modules[i].companion);
context.modules[i].companion = -1;
}
break;
@@ -566,9 +602,19 @@ void zygiskd_start(char *restrict argv[]) {
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 (index >= context.len) {
LOGE("Invalid module index: %zu\n", index);
if (module->companion != -1) {
ret = write_uint8_t(client_fd, 0);
ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(int));
close(client_fd);
break;
}
struct Module *module = &context.modules[index];
if (module->companion >= 0) {
if (!check_unix_socket(module->companion, false)) {
LOGE(" - Companion for module \"%s\" crashed\n", module->name);
@@ -577,10 +623,10 @@ void zygiskd_start(char *restrict argv[]) {
}
}
if (module->companion == -1) {
if (module->companion <= -1) {
module->companion = spawn_companion(argv, module->name, module->lib_fd);
if (module->companion > 0) {
if (module->companion >= 0) {
LOGI(" - Spawned companion for \"%s\": %d\n", module->name, module->companion);
} else {
if (module->companion == -2) {
@@ -597,7 +643,7 @@ void zygiskd_start(char *restrict argv[]) {
so just sending the file descriptor of the client is
safe.
*/
if (module->companion != -1) {
if (module->companion >= 0) {
LOGI(" - Sending companion fd socket of module \"%s\"\n", module->name);
if (write_fd(module->companion, client_fd) == -1) {
@@ -629,6 +675,17 @@ void zygiskd_start(char *restrict argv[]) {
ssize_t ret = read_size_t(client_fd, &index);
ASSURE_SIZE_READ_BREAK("GetModuleDir", "index", ret, sizeof(index));
if (index >= context.len) {
LOGE("Invalid module index: %zu\n", index);
ret = write_uint8_t(client_fd, 0);
ASSURE_SIZE_WRITE_BREAK("GetModuleDir", "response", ret, sizeof(int));
close(client_fd);
break;
}
char module_dir[PATH_MAX];
snprintf(module_dir, PATH_MAX, "%s/%s", PATH_MODULES_DIR, context.modules[index].name);