11 Commits

Author SHA1 Message Date
Nullptr
698e6e6624 Bump to 0.9.1.1 2024-01-05 17:50:37 +08:00
Nullptr
fbb792ef13 Minor changes 2024-01-05 17:11:50 +08:00
Nullptr
381abc99d5 Bump to 0.9.1 2024-01-05 16:48:10 +08:00
Nullptr
fd603982e8 Refine uid_is_manager 2024-01-05 16:43:04 +08:00
Nullptr
2d384685e7 No hardcode ksu tmp path 2024-01-05 14:30:07 +08:00
5ec1cff
675febfd14 refine code 2024-01-05 13:57:18 +08:00
5ec1cff
ad32c4efb0 reformat code 2024-01-05 13:10:10 +08:00
5ec1cff
331b01b0f4 recognize magisk variants correctly 2024-01-05 13:00:01 +08:00
5ec1cff
8079123e43 Refine gradle 2024-01-05 11:11:42 +08:00
5ec1cff
9a95377d7b fix injector cannot get tmp path 2024-01-05 10:37:48 +08:00
Nullptr
043cfd93d6 No hardcode temp dir 2024-01-04 03:44:57 +08:00
26 changed files with 339 additions and 264 deletions

View File

@@ -11,7 +11,7 @@ Standalone implementation of Zygisk, providing Zygisk API support for KernelSU a
### KernelSU
+ Minimal KernelSU version: 10940
+ Minimal ksud version: 11412
+ Minimal ksud version: 11424
+ Kernel has full SELinux patch support
### Magisk

View File

@@ -20,11 +20,11 @@ val gitCommitHash = "git rev-parse --verify --short HEAD".execute()
val moduleId by extra("zygisksu")
val moduleName by extra("Zygisk Next")
val verName by extra("v4-0.9.0")
val verName by extra("v4-0.9.1.1")
val verCode by extra(gitCommitCount)
val commitHash by extra(gitCommitHash)
val minKsuVersion by extra(10940)
val minKsudVersion by extra(11412)
val minKsudVersion by extra(11425)
val maxKsuVersion by extra(20000)
val minMagiskVersion by extra(26402)

View File

@@ -1,23 +1 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.useAndroidX=false

View File

@@ -1,6 +1,6 @@
[versions]
agp = "8.1.2"
kotlin = "1.9.10"
agp = "8.2.0"
kotlin = "1.9.22"
[plugins]
agp-lib = { id = "com.android.library", version.ref = "agp" }

View File

@@ -7,10 +7,13 @@
#include "socket_utils.h"
namespace zygiskd {
static std::string zygisk_path;
static std::string TMP_PATH;
void Init(const char *path) {
LOGI("zygisk path set to %s", path);
zygisk_path = path;
TMP_PATH = path;
}
std::string GetTmpPath() {
return TMP_PATH;
}
int Connect(uint8_t retry) {
@@ -19,7 +22,7 @@ namespace zygiskd {
.sun_family = AF_UNIX,
.sun_path={0},
};
auto socket_path = zygisk_path + kCPSocketName;
auto socket_path = TMP_PATH + kCPSocketName;
strcpy(addr.sun_path, socket_path.c_str());
socklen_t socklen = sizeof(addr);

View File

@@ -12,7 +12,6 @@
#endif
constexpr auto kCPSocketName = "/" LP_SELECT("cp32", "cp64") ".sock";
#define TMP_PATH "/debug_ramdisk/zygisksu"
class UniqueFd {
using Fd = int;
@@ -63,7 +62,9 @@ namespace zygiskd {
SystemServerStarted,
};
void Init(const char *path = TMP_PATH);
void Init(const char *path);
std::string GetTmpPath();
bool PingHeartbeat();

View File

@@ -8,11 +8,11 @@ using namespace std;
void *self_handle = nullptr;
extern "C" [[gnu::visibility("default")]]
void entry(void* handle) {
void entry(void* handle, const char* path) {
LOGI("Zygisk library injected, version %s", ZKSU_VERSION);
self_handle = handle;
zygiskd::Init(path);
zygiskd::Init();
if (!zygiskd::PingHeartbeat()) {
LOGE("Zygisk daemon is not running");
return;

View File

@@ -46,7 +46,7 @@ void revert_unmount_ksu() {
&& std::find(KSU_PARTITIONS.begin(), KSU_PARTITIONS.end(), info.target) != KSU_PARTITIONS.end()) {
targets.emplace_back(info.target);
}
// Unmount /debug_ramdisk
// Unmount temp dir
if (info.type == "tmpfs" && info.source == KSU_OVERLAY_SOURCE) {
targets.emplace_back(info.target);
}

View File

@@ -14,12 +14,12 @@
using namespace std::string_view_literals;
int main(int argc, char **argv) {
zygiskd::Init(getenv("TMP_PATH"));
if (argc >= 2 && argv[1] == "monitor"sv) {
init_monitor();
return 0;
} else if (argc >= 3 && argv[1] == "trace"sv) {
if (argc >= 4 && argv[3] == "--restart"sv) {
zygiskd::Init();
zygiskd::ZygoteRestart();
}
auto pid = strtol(argv[2], 0, 0);

View File

@@ -37,7 +37,7 @@ enum TracingState {
std::string monitor_stop_reason;
constexpr char SOCKET_NAME[] = TMP_PATH "/init_monitor";
constexpr char SOCKET_NAME[] = "init_monitor";
struct EventLoop;
@@ -94,7 +94,7 @@ public:
return true;
}
bool UnregisterHandler(EventHandler &handler) {
[[maybe_unused]] bool UnregisterHandler(EventHandler &handler) {
if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, handler.GetFd(), nullptr) == -1) {
PLOGE("failed to del event handler");
return false;
@@ -136,7 +136,7 @@ struct SocketHandler : public EventHandler {
.sun_family = AF_UNIX,
.sun_path={0},
};
strcpy(addr.sun_path, SOCKET_NAME);
sprintf(addr.sun_path, "%s/%s", zygiskd::GetTmpPath().c_str(), SOCKET_NAME);
socklen_t socklen = sizeof(sa_family_t) + strlen(addr.sun_path);
if (bind(sock_fd_, (struct sockaddr *) &addr, socklen) == -1) {
PLOGE("bind socket");
@@ -149,7 +149,7 @@ struct SocketHandler : public EventHandler {
return sock_fd_;
}
void HandleEvent(EventLoop &loop, uint32_t event) override {
void HandleEvent(EventLoop &loop, uint32_t) override {
struct [[gnu::packed]] MsgHead {
Command cmd;
int length;
@@ -346,7 +346,7 @@ public:
return signal_fd_;
}
void HandleEvent(EventLoop &loop, uint32_t event) override {
void HandleEvent(EventLoop &, uint32_t) override {
for (;;) {
ssize_t s = read(signal_fd_, &fdsi, sizeof(fdsi));
if (s == -1) {
@@ -472,7 +472,7 @@ public:
} while (false);
updateStatus();
} else {
LOGE("process %d received unknown status %s", pid,
LOGW("process %d received unknown status %s", pid,
parse_status(status).c_str());
}
process.erase(state);
@@ -544,7 +544,7 @@ static void updateStatus() {
}
static bool prepare_environment() {
prop_path = TMP_PATH "/module.prop";
prop_path = zygiskd::GetTmpPath() + "/module.prop";
close(open(prop_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644));
auto orig_prop = xopen_file("./module.prop", "r");
if (orig_prop == nullptr) {
@@ -595,13 +595,13 @@ void send_control_command(Command cmd) {
.sun_family = AF_UNIX,
.sun_path={0},
};
strcpy(addr.sun_path, SOCKET_NAME);
sprintf(addr.sun_path, "%s/%s", zygiskd::GetTmpPath().c_str(), SOCKET_NAME);
socklen_t socklen = sizeof(sa_family_t) + strlen(addr.sun_path);
auto nsend = sendto(sockfd, (void *) &cmd, sizeof(cmd), 0, (sockaddr *) &addr, socklen);
if (nsend == -1) {
err(EXIT_FAILURE, "send");
} else if (nsend != sizeof(cmd)) {
printf("send %ld != %ld\n", nsend, sizeof(cmd));
printf("send %zu != %zu\n", nsend, sizeof(cmd));
exit(1);
}
printf("command sent\n");

View File

@@ -14,6 +14,8 @@
#include <signal.h>
#include <sys/system_properties.h>
#include <string>
#include <cinttypes>
#include "utils.hpp"
bool inject_on_main(int pid, const char *lib_path) {
@@ -23,42 +25,42 @@ bool inject_on_main(int pid, const char *lib_path) {
struct user_regs_struct regs{}, backup{};
auto map = MapInfo::Scan(std::to_string(pid));
if (!get_regs(pid, regs)) return false;
auto arg = reinterpret_cast<uintptr_t *>(regs.REG_SP);
LOGD("kernel argument %p %s", arg, get_addr_mem_region(map, arg).c_str());
auto arg = static_cast<uintptr_t>(regs.REG_SP);
LOGV("kernel argument %" PRIxPTR " %s", arg, get_addr_mem_region(map, arg).c_str());
int argc;
auto argv = reinterpret_cast<char **>(reinterpret_cast<uintptr_t *>(arg) + 1);
LOGD("argv %p", argv);
LOGV("argv %p", argv);
read_proc(pid, arg, &argc, sizeof(argc));
LOGD("argc %d", argc);
LOGV("argc %d", argc);
auto envp = argv + argc + 1;
LOGD("envp %p", envp);
LOGV("envp %p", envp);
auto p = envp;
while (true) {
uintptr_t *buf;
read_proc(pid, (uintptr_t *) p, &buf, sizeof(buf));
read_proc(pid, (uintptr_t) p, &buf, sizeof(buf));
if (buf != nullptr) ++p;
else break;
}
++p;
auto auxv = reinterpret_cast<ElfW(auxv_t) *>(p);
LOGD("auxv %p %s", auxv, get_addr_mem_region(map, auxv).c_str());
LOGV("auxv %p %s", auxv, get_addr_mem_region(map, (uintptr_t) auxv).c_str());
auto v = auxv;
void *entry_addr = nullptr;
void *addr_of_entry_addr = nullptr;
uintptr_t entry_addr = 0;
uintptr_t addr_of_entry_addr = 0;
while (true) {
ElfW(auxv_t) buf;
read_proc(pid, (uintptr_t *) v, &buf, sizeof(buf));
read_proc(pid, (uintptr_t) v, &buf, sizeof(buf));
if (buf.a_type == AT_ENTRY) {
entry_addr = reinterpret_cast<void *>(buf.a_un.a_val);
addr_of_entry_addr = reinterpret_cast<char *>(v) + offsetof(ElfW(auxv_t), a_un);
LOGD("entry address %p %s (v=%p, entry_addr=%p)", entry_addr,
get_addr_mem_region(map, entry_addr).c_str(), v, addr_of_entry_addr);
entry_addr = (uintptr_t) buf.a_un.a_val;
addr_of_entry_addr = (uintptr_t) v + offsetof(ElfW(auxv_t), a_un);
LOGV("entry address %" PRIxPTR " %s (entry=%" PRIxPTR ", entry_addr=%" PRIxPTR ")", entry_addr,
get_addr_mem_region(map, entry_addr).c_str(), (uintptr_t) v, addr_of_entry_addr);
break;
}
if (buf.a_type == AT_NULL) break;
v++;
}
if (entry_addr == nullptr) {
if (entry_addr == 0) {
LOGE("failed to get entry");
return false;
}
@@ -66,13 +68,13 @@ bool inject_on_main(int pid, const char *lib_path) {
// Replace the program entry with an invalid address
// For arm32 compatibility, we set the last bit to the same as the entry address
uintptr_t break_addr = (-0x05ec1cff & ~1) | ((uintptr_t) entry_addr & 1);
if (!write_proc(pid, (uintptr_t *) addr_of_entry_addr, &break_addr, sizeof(break_addr))) return false;
if (!write_proc(pid, (uintptr_t) addr_of_entry_addr, &break_addr, sizeof(break_addr))) return false;
ptrace(PTRACE_CONT, pid, 0, 0);
int status;
wait_for_trace(pid, &status, __WALL);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSEGV) {
if (!get_regs(pid, regs)) return false;
if ((regs.REG_IP & ~1) != (break_addr & ~1)) {
if (static_cast<uintptr_t>(regs.REG_IP & ~1) != (break_addr & ~1)) {
LOGE("stopped at unknown addr %p", (void *) regs.REG_IP);
return false;
}
@@ -80,7 +82,7 @@ bool inject_on_main(int pid, const char *lib_path) {
LOGD("stopped at entry");
// restore entry address
if (!write_proc(pid, (uintptr_t *) addr_of_entry_addr, &entry_addr, sizeof(entry_addr))) return false;
if (!write_proc(pid, (uintptr_t) addr_of_entry_addr, &entry_addr, sizeof(entry_addr))) return false;
// backup registers
memcpy(&backup, &regs, sizeof(regs));
@@ -119,11 +121,13 @@ bool inject_on_main(int pid, const char *lib_path) {
args.clear();
args.push_back(dlerror_str_addr);
auto dlerror_len = remote_call(pid, regs, (uintptr_t) strlen_addr, (uintptr_t) libc_return_addr, args);
LOGD("dlerror len %ld", dlerror_len);
if (dlerror_len <= 0) return false;
if (dlerror_len <= 0) {
LOGE("dlerror len <= 0");
return false;
}
std::string err;
err.resize(dlerror_len + 1, 0);
read_proc(pid, (uintptr_t*) dlerror_str_addr, err.data(), dlerror_len);
read_proc(pid, (uintptr_t) dlerror_str_addr, err.data(), dlerror_len);
LOGE("dlerror info %s", err.c_str());
return false;
}
@@ -142,9 +146,11 @@ bool inject_on_main(int pid, const char *lib_path) {
return false;
}
// call injector entry(handle, magic)
// call injector entry(handle, path)
args.clear();
args.push_back(remote_handle);
str = push_string(pid, regs, zygiskd::GetTmpPath().c_str());
args.push_back((long) str);
remote_call(pid, regs, injector_entry, (uintptr_t) libc_return_addr, args);
// reset pc to entry
@@ -178,7 +184,7 @@ bool trace_zygote(int pid) {
}
WAIT_OR_DIE
if (STOPPED_WITH(SIGSTOP, PTRACE_EVENT_STOP)) {
std::string lib_path = TMP_PATH;
std::string lib_path = zygiskd::GetTmpPath();
lib_path += "/lib" LP_SELECT("", "64") "/libzygisk.so";
if (!inject_on_main(pid, lib_path.c_str())) {
LOGE("failed to inject");

View File

@@ -102,8 +102,8 @@ std::vector<MapInfo> MapInfo::Scan(const std::string& pid) {
return info;
}
ssize_t write_proc(int pid, uintptr_t *remote_addr, const void *buf, size_t len) {
LOGD("write to remote addr %p size %zu", remote_addr, len);
ssize_t write_proc(int pid, uintptr_t remote_addr, const void *buf, size_t len) {
LOGV("write to remote addr %" PRIxPTR " size %zu", remote_addr, len);
struct iovec local{
.iov_base = (void *) buf,
.iov_len = len
@@ -115,13 +115,13 @@ ssize_t write_proc(int pid, uintptr_t *remote_addr, const void *buf, size_t len)
auto l = process_vm_writev(pid, &local, 1, &remote, 1, 0);
if (l == -1) {
PLOGE("process_vm_writev");
} else if (l != len) {
} else if (static_cast<size_t>(l) != len) {
LOGW("not fully written: %zu, excepted %zu", l, len);
}
return l;
}
ssize_t read_proc(int pid, uintptr_t *remote_addr, void *buf, size_t len) {
ssize_t read_proc(int pid, uintptr_t remote_addr, void *buf, size_t len) {
struct iovec local{
.iov_base = (void *) buf,
.iov_len = len
@@ -133,7 +133,7 @@ ssize_t read_proc(int pid, uintptr_t *remote_addr, void *buf, size_t len) {
auto l = process_vm_readv(pid, &local, 1, &remote, 1, 0);
if (l == -1) {
PLOGE("process_vm_readv");
} else if (l != len) {
} else if (static_cast<size_t>(l) != len) {
LOGW("not fully read: %zu, excepted %zu", l, len);
}
return l;
@@ -177,9 +177,9 @@ bool set_regs(int pid, struct user_regs_struct &regs) {
return true;
}
std::string get_addr_mem_region(std::vector<MapInfo> &info, void *addr) {
std::string get_addr_mem_region(std::vector<MapInfo> &info, uintptr_t addr) {
for (auto &map: info) {
if (map.start <= (uintptr_t) addr && map.end > (uintptr_t) addr) {
if (map.start <= addr && map.end > addr) {
auto s = std::string(map.path);
s += ' ';
s += map.perms & PROT_READ ? 'r' : '-';
@@ -248,24 +248,24 @@ void align_stack(struct user_regs_struct &regs, long preserve) {
regs.REG_SP = (regs.REG_SP - preserve) & ~0xf;
}
void *push_string(int pid, struct user_regs_struct &regs, const char *str) {
uintptr_t push_string(int pid, struct user_regs_struct &regs, const char *str) {
auto len = strlen(str) + 1;
regs.REG_SP -= len;
align_stack(regs);
auto addr = reinterpret_cast<uintptr_t *>(regs.REG_SP);
auto addr = static_cast<uintptr_t>(regs.REG_SP);
if (!write_proc(pid, addr, str, len)) {
LOGE("failed to write string %s", str);
}
LOGD("pushed string %p", addr);
LOGD("pushed string %" PRIxPTR, addr);
return addr;
}
uintptr_t remote_call(int pid, struct user_regs_struct &regs, uintptr_t func_addr, uintptr_t return_addr,
std::vector<long> &args) {
align_stack(regs);
LOGD("call %d args", args.size());
LOGV("calling remote function %" PRIxPTR " args %zu", func_addr, args.size());
for (auto &a: args) {
LOGD("arg %p", (void *) a);
LOGV("arg %p", (void *) a);
}
#if defined(__x86_64__)
if (args.size() >= 1) {
@@ -289,12 +289,12 @@ uintptr_t remote_call(int pid, struct user_regs_struct &regs, uintptr_t func_add
if (args.size() > 6) {
auto remain = (args.size() - 6) * sizeof(long);
align_stack(regs, remain);
if (!write_proc(pid, (uintptr_t *) regs.REG_SP, args.data(), remain)) {
if (!write_proc(pid, (uintptr_t) regs.REG_SP, args.data(), remain)) {
LOGE("failed to push arguments");
}
}
regs.REG_SP -= sizeof(long);
if (!write_proc(pid, (uintptr_t *) regs.REG_SP, &return_addr, sizeof(return_addr))) {
if (!write_proc(pid, (uintptr_t) regs.REG_SP, &return_addr, sizeof(return_addr))) {
LOGE("failed to write return addr");
}
regs.REG_IP = func_addr;
@@ -302,34 +302,34 @@ uintptr_t remote_call(int pid, struct user_regs_struct &regs, uintptr_t func_add
if (args.size() > 0) {
auto remain = (args.size()) * sizeof(long);
align_stack(regs, remain);
if (!write_proc(pid, (uintptr_t *)regs.REG_SP, args.data(), remain)) {
if (!write_proc(pid, (uintptr_t) regs.REG_SP, args.data(), remain)) {
LOGE("failed to push arguments");
}
}
regs.REG_SP -= sizeof(long);
if (!write_proc(pid, (uintptr_t*) regs.REG_SP, &return_addr, sizeof(return_addr))) {
if (!write_proc(pid, (uintptr_t) regs.REG_SP, &return_addr, sizeof(return_addr))) {
LOGE("failed to write return addr");
}
regs.REG_IP = func_addr;
#elif defined(__aarch64__)
for (int i = 0; i < args.size() && i < 8; i++) {
for (size_t i = 0; i < args.size() && i < 8; i++) {
regs.regs[i] = args[i];
}
if (args.size() > 8) {
auto remain = (args.size() - 8) * sizeof(long);
align_stack(regs, remain);
write_proc(pid, (uintptr_t *)regs.REG_SP, args.data(), remain);
write_proc(pid, (uintptr_t)regs.REG_SP, args.data(), remain);
}
regs.regs[30] = return_addr;
regs.REG_IP = func_addr;
#elif defined(__arm__)
for (int i = 0; i < args.size() && i < 4; i++) {
for (size_t i = 0; i < args.size() && i < 4; i++) {
regs.uregs[i] = args[i];
}
if (args.size() > 4) {
auto remain = (args.size() - 4) * sizeof(long);
align_stack(regs, remain);
write_proc(pid, (uintptr_t *)regs.REG_SP, args.data(), remain);
write_proc(pid, (uintptr_t)regs.REG_SP, args.data(), remain);
}
regs.uregs[14] = return_addr;
regs.REG_IP = func_addr;
@@ -353,7 +353,7 @@ uintptr_t remote_call(int pid, struct user_regs_struct &regs, uintptr_t func_add
return 0;
}
if (WSTOPSIG(status) == SIGSEGV) {
if (regs.REG_IP != return_addr) {
if (static_cast<uintptr_t>(regs.REG_IP) != return_addr) {
LOGE("wrong return addr %p", (void *) regs.REG_IP);
return 0;
}

View File

@@ -60,15 +60,15 @@ struct MapInfo {
#define user_regs_struct user_regs
#endif
ssize_t write_proc(int pid, uintptr_t *remote_addr, const void *buf, size_t len);
ssize_t write_proc(int pid, uintptr_t remote_addr, const void *buf, size_t len);
ssize_t read_proc(int pid, uintptr_t *remote_addr, void *buf, size_t len);
ssize_t read_proc(int pid, uintptr_t remote_addr, void *buf, size_t len);
bool get_regs(int pid, struct user_regs_struct &regs);
bool set_regs(int pid, struct user_regs_struct &regs);
std::string get_addr_mem_region(std::vector<MapInfo> &info, void *addr);
std::string get_addr_mem_region(std::vector<MapInfo> &info, uintptr_t addr);
void *find_module_base(std::vector<MapInfo> &info, std::string_view suffix);
@@ -80,7 +80,7 @@ void *find_func_addr(
void align_stack(struct user_regs_struct &regs, long preserve = 0);
void *push_string(int pid, struct user_regs_struct &regs, const char *str);
uintptr_t push_string(int pid, struct user_regs_struct &regs, const char *str);
uintptr_t remote_call(int pid, struct user_regs_struct &regs, uintptr_t func_addr, uintptr_t return_addr,
std::vector<long> &args);

View File

@@ -1,3 +1,4 @@
import android.databinding.tool.ext.capitalizeUS
import java.security.MessageDigest
import org.apache.tools.ant.filters.ReplaceTokens
@@ -35,9 +36,9 @@ android.buildFeatures {
}
androidComponents.onVariants { variant ->
val variantLowered = variant.name.toLowerCase()
val variantCapped = variant.name.capitalize()
val buildTypeLowered = variant.buildType?.toLowerCase()
val variantLowered = variant.name.lowercase()
val variantCapped = variant.name.capitalizeUS()
val buildTypeLowered = variant.buildType?.lowercase()
val moduleDir = layout.buildDirectory.dir("outputs/module/$variantLowered")
val zipFileName = "$moduleName-$verName-$verCode-$commitHash-$buildTypeLowered.zip".replace(' ', '-')
@@ -77,11 +78,11 @@ androidComponents.onVariants { variant ->
filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
}
into("bin") {
from(project(":zygiskd").buildDir.path + "/rustJniLibs/android")
from(project(":zygiskd").layout.buildDirectory.file("rustJniLibs/android"))
include("**/zygiskd")
}
into("lib") {
from("${project(":loader").buildDir}/intermediates/stripped_native_libs/$variantLowered/out/lib")
from(project(":loader").layout.buildDirectory.file("intermediates/stripped_native_libs/$variantLowered/out/lib"))
}
val root = moduleDir.get()
@@ -106,16 +107,16 @@ androidComponents.onVariants { variant ->
.putLong(real.length())
.array()
sig.update(buffer)
println("sha $path ${real.length()}")
real.forEachBlock { bytes, size ->
sig.update(bytes, 0, size)
}
}
fun getSign(name: String, abi32: String, abi64: String) {
println("getSign for $name $abi32 $abi64")
val set =
TreeSet<Pair<File, File?>> { o1, o2 -> o1.first.path.replace("\\", "/").compareTo(o2.first.path.replace("\\", "/")) }
val set = TreeSet<Pair<File, File?>> { o1, o2 ->
o1.first.path.replace("\\", "/")
.compareTo(o2.first.path.replace("\\", "/"))
}
set.add(Pair(root.file("module.prop").asFile, null))
set.add(Pair(root.file("sepolicy.rule").asFile, null))
set.add(Pair(root.file("post-fs-data.sh").asFile, null))
@@ -173,6 +174,7 @@ androidComponents.onVariants { variant ->
getSign("machikado.arm", "armeabi-v7a", "arm64-v8a")
getSign("machikado.x86", "x86", "x86_64")
} else {
println("no private_key found, this build will not be signed")
root.file("machikado.arm").asFile.createNewFile()
root.file("machikado.x86").asFile.createNewFile()
}
@@ -192,7 +194,7 @@ androidComponents.onVariants { variant ->
group = "module"
dependsOn(prepareModuleFilesTask)
archiveFileName.set(zipFileName)
destinationDirectory.set(file("$buildDir/outputs/release"))
destinationDirectory.set(layout.buildDirectory.file("outputs/release").get().asFile)
from(moduleDir)
}

View File

@@ -26,7 +26,8 @@ create_sys_perm() {
chcon u:object_r:system_file:s0 $1
}
TMP_PATH="/debug_ramdisk/zygisksu"
export TMP_PATH=/sbin
[ -d /sbin ] || export TMP_PATH=/debug_ramdisk
create_sys_perm $TMP_PATH

View File

@@ -1,2 +1,6 @@
MODDIR=${0%/*}/..
export TMP_PATH=/sbin
[ -d /sbin ] || export TMP_PATH=/debug_ramdisk
exec $MODDIR/bin/zygisk-ptrace64 ctl $*

View File

@@ -64,4 +64,4 @@ afterEvaluate {
}
}
}
}
}

View File

@@ -1,13 +1,12 @@
use crate::dl;
use crate::utils::{check_unix_socket, UnixStreamExt};
use anyhow::Result;
use passfd::FdPassingExt;
use rustix::fs::fstat;
use std::ffi::c_void;
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
use std::os::unix::net::UnixStream;
use std::thread;
use anyhow::Result;
use passfd::FdPassingExt;
use rustix::fs::fstat;
use tokio::io::AsyncWriteExt;
use crate::utils::{check_unix_socket, UnixStreamExt};
use crate::dl;
type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32);
@@ -28,7 +27,7 @@ pub fn entry(fd: i32) {
None => {
log::debug!("No companion entry for `{name}`");
stream.write_u8(0).expect("reply 0");
return ();
std::process::exit(0);
}
};
@@ -43,7 +42,9 @@ pub fn entry(fd: i32) {
stream.write_u8(1).expect("reply success");
thread::spawn(move || {
let st0 = fstat(&stream).expect("failed to stat stream");
unsafe { entry(stream.as_raw_fd()); }
unsafe {
entry(stream.as_raw_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

View File

@@ -1,34 +1,25 @@
use crate::lp_select;
use bitflags::bitflags;
use const_format::concatcp;
use konst::primitive::parse_i32;
use konst::unwrap_ctx;
use log::LevelFilter;
use num_enum::TryFromPrimitive;
use crate::lp_select;
pub const MIN_KSU_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MIN_KSU_VERSION")));
pub const MAX_KSU_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MAX_KSU_VERSION")));
pub const MIN_MAGISK_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MIN_MAGISK_VERSION")));
pub const ZKSU_VERSION: &'static str = env!("ZKSU_VERSION");
pub const ZKSU_VERSION: &str = env!("ZKSU_VERSION");
#[cfg(debug_assertions)]
pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Trace;
#[cfg(not(debug_assertions))]
pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Info;
pub const PATH_MODULES_DIR: &str = "..";
pub const PATH_MODULE_PROP: &str = "module.prop";
pub const ZYGOTE_INJECTED: i32 = lp_select!(5, 4);
pub const DAEMON_SET_INFO: i32 = lp_select!(7, 6);
pub const DAEMON_SET_ERROR_INFO: i32 = lp_select!(9, 8);
pub const SYSTEM_SERVER_STARTED: i32 = 10;
pub const TMP_DIR: &str = "/debug_ramdisk/zygisksu";
pub const CONTROLLER_SOCKET: &str = concatcp!(TMP_DIR, "/init_monitor");
pub const PATH_CP_NAME: &str = concatcp!(TMP_DIR, lp_select!("/cp32.sock", "/cp64.sock"));
pub const MAX_RESTART_COUNT: i32 = 5;
#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
#[repr(u8)]

View File

@@ -30,13 +30,13 @@ extern "C" {
}
type AndroidCreateNamespaceFn = unsafe extern "C" fn(
*const c_char, // name
*const c_char, // ld_library_path
*const c_char, // default_library_path
u64, // type
*const c_char, // permitted_when_isolated_path
*mut AndroidNamespace, // parent
*const c_void, // caller_addr
*const c_char, // name
*const c_char, // ld_library_path
*const c_char, // default_library_path
u64, // type
*const c_char, // permitted_when_isolated_path
*mut AndroidNamespace, // parent
*const c_void, // caller_addr
) -> *mut AndroidNamespace;
pub unsafe fn dlopen(path: &str, flags: i32) -> Result<*mut c_void> {
@@ -57,11 +57,15 @@ pub unsafe fn dlopen(path: &str, flags: i32) -> Result<*mut c_void> {
libc::RTLD_DEFAULT,
std::ffi::CString::new("__loader_android_create_namespace")?.as_ptr(),
);
let android_create_namespace_fn: AndroidCreateNamespaceFn = std::mem::transmute(android_create_namespace_fn);
let android_create_namespace_fn: AndroidCreateNamespaceFn =
std::mem::transmute(android_create_namespace_fn);
let ns = android_create_namespace_fn(
filename, dir, std::ptr::null(),
filename,
dir,
std::ptr::null(),
ANDROID_NAMESPACE_TYPE_SHARED,
std::ptr::null(), std::ptr::null_mut(),
std::ptr::null(),
std::ptr::null_mut(),
&dlopen as *const _ as *const c_void,
);
if ns != std::ptr::null_mut() {

View File

@@ -1,11 +1,10 @@
mod companion;
mod constants;
mod dl;
mod root_impl;
mod utils;
mod zygiskd;
mod companion;
use std::future::Future;
use crate::constants::ZKSU_VERSION;
fn init_android_logger(tag: &str) {

View File

@@ -71,7 +71,7 @@ pub fn uid_should_umount(uid: i32) -> bool {
// TODO: signature
pub fn uid_is_manager(uid: i32) -> bool {
if let Ok(s) = rustix::fs::stat("/data/user_de/0/me.weishu.kernelsu") {
return s.st_uid == uid as u32
return s.st_uid == uid as u32;
}
false
}

View File

@@ -1,44 +1,78 @@
use std::process::{Command, Stdio};
use std::fs;
use std::os::android::fs::MetadataExt;
use crate::constants::MIN_MAGISK_VERSION;
use std::process::{Command, Stdio};
use log::info;
use crate::utils::LateInit;
const MAGISK_OFFICIAL: &str = "com.topjohnwu.magisk";
const MAGISK_THIRD_PARTIES: &[(&str, &str)] = &[
("alpha", "io.github.vvb2060.magisk"),
("kitsune", "io.github.huskydg.magisk"),
];
pub enum Version {
Supported,
TooOld,
}
static VARIANT: LateInit<&str> = LateInit::new();
pub fn get_magisk() -> Option<Version> {
let version: Option<i32> = Command::new("magisk")
if !VARIANT.initiated() {
Command::new("magisk")
.arg("-v")
.stdout(Stdio::piped())
.spawn()
.ok()
.and_then(|child| child.wait_with_output().ok())
.and_then(|output| String::from_utf8(output.stdout).ok())
.map(|version| {
let third_party = MAGISK_THIRD_PARTIES.iter().find_map(|v| {
version.contains(v.0).then_some(v.1)
});
VARIANT.init(third_party.unwrap_or(MAGISK_OFFICIAL));
info!("Magisk variant: {}", *VARIANT);
});
}
Command::new("magisk")
.arg("-V")
.stdout(Stdio::piped())
.spawn().ok()
.spawn()
.ok()
.and_then(|child| child.wait_with_output().ok())
.and_then(|output| String::from_utf8(output.stdout).ok())
.and_then(|output| output.trim().parse().ok());
version.map(|version| {
if version >= MIN_MAGISK_VERSION {
Version::Supported
} else {
Version::TooOld
}
})
.and_then(|output| output.trim().parse::<i32>().ok())
.map(|version| {
if version >= MIN_MAGISK_VERSION {
Version::Supported
} else {
Version::TooOld
}
})
}
pub fn uid_granted_root(uid: i32) -> bool {
Command::new("magisk")
.arg("--sqlite")
.arg(format!("select 1 from policies where uid={uid} and policy=2 limit 1"))
.arg(format!(
"select 1 from policies where uid={uid} and policy=2 limit 1"
))
.stdout(Stdio::piped())
.spawn().ok()
.spawn()
.ok()
.and_then(|child| child.wait_with_output().ok())
.and_then(|output| String::from_utf8(output.stdout).ok())
.map(|output| output.is_empty()) == Some(false)
.map(|output| output.is_empty())
== Some(false)
}
pub fn uid_should_umount(uid: i32) -> bool {
let output = Command::new("pm")
.args(["list", "packages", "--uid", &uid.to_string()])
.stdout(Stdio::piped())
.spawn().ok()
.spawn()
.ok()
.and_then(|child| child.wait_with_output().ok())
.and_then(|output| String::from_utf8(output.stdout).ok());
let line = match output {
@@ -54,43 +88,37 @@ pub fn uid_should_umount(uid: i32) -> bool {
};
Command::new("magisk")
.arg("--sqlite")
.arg(format!("select 1 from denylist where package_name=\"{pkg}\" limit 1"))
.arg(format!(
"select 1 from denylist where package_name=\"{pkg}\" limit 1"
))
.stdout(Stdio::piped())
.spawn().ok()
.spawn()
.ok()
.and_then(|child| child.wait_with_output().ok())
.and_then(|output| String::from_utf8(output.stdout).ok())
.map(|output| output.is_empty()) == Some(false)
.map(|output| output.is_empty())
== Some(false)
}
// TODO: signature
// TODO: magisk random package name
pub fn uid_is_manager(uid: i32) -> bool {
let output = Command::new("magisk")
.arg("--sqlite")
.arg(format!("select value from strings where key=\"requester\" limit 1"))
.stdout(Stdio::piped())
.spawn().ok()
.spawn()
.ok()
.and_then(|child| child.wait_with_output().ok())
.and_then(|output| String::from_utf8(output.stdout).ok())
.map(|output| output.trim().to_string());
if let Some(output) = output {
if let Some(manager) = output.strip_prefix("value=") {
if let Ok(s) = rustix::fs::stat(format!("/data/user_de/0/{}", manager)) {
return s.st_uid == uid as u32;
} else {
return false;
}
return fs::metadata(format!("/data/user_de/0/{}", manager))
.map(|s| s.st_uid() == uid as u32)
.unwrap_or(false);
}
}
if let Ok(s) = rustix::fs::stat("/data/user_de/0/com.topjohnwu.magisk") {
if s.st_uid == uid as u32 {
return true;
}
}
if let Ok(s) = rustix::fs::stat("/data/user_de/0/io.github.vvb2060.magisk") {
if s.st_uid == uid as u32 {
return true;
}
}
false
fs::metadata(format!("/data/user_de/0/{}", *VARIANT))
.map(|s| s.st_uid() == uid as u32)
.unwrap_or(false)
}

View File

@@ -20,21 +20,19 @@ pub fn setup() {
let impl_ = match (ksu_version, magisk_version) {
(None, None) => RootImpl::None,
(Some(_), Some(_)) => RootImpl::Multiple,
(Some(ksu_version), None) => {
match ksu_version {
kernelsu::Version::Supported => RootImpl::KernelSU,
kernelsu::Version::TooOld => RootImpl::TooOld,
kernelsu::Version::Abnormal => RootImpl::Abnormal,
}
}
(None, Some(magisk_version)) => {
match magisk_version {
magisk::Version::Supported => RootImpl::Magisk,
magisk::Version::TooOld => RootImpl::TooOld,
}
}
(Some(ksu_version), None) => match ksu_version {
kernelsu::Version::Supported => RootImpl::KernelSU,
kernelsu::Version::TooOld => RootImpl::TooOld,
kernelsu::Version::Abnormal => RootImpl::Abnormal,
},
(None, Some(magisk_version)) => match magisk_version {
magisk::Version::Supported => RootImpl::Magisk,
magisk::Version::TooOld => RootImpl::TooOld,
},
};
unsafe { ROOT_IMPL = impl_; }
unsafe {
ROOT_IMPL = impl_;
}
}
pub fn get_impl() -> &'static RootImpl {

View File

@@ -1,35 +1,49 @@
use anyhow::Result;
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream};
use std::ffi::{c_char, c_void, CStr, CString};
use std::os::fd::{AsFd, AsRawFd};
use std::os::unix::net::{UnixDatagram, UnixListener};
use std::process::Command;
use std::sync::OnceLock;
use bitflags::Flags;
use rustix::net::{AddressFamily, bind_unix, connect_unix, listen, SendFlags, sendto_unix, socket, SocketAddrUnix, SocketType};
use rustix::net::{
bind_unix, connect_unix, listen, sendto_unix, socket, AddressFamily, SendFlags, SocketAddrUnix,
SocketType,
};
use rustix::path::Arg;
use rustix::thread::gettid;
use std::ffi::{c_char, c_void, CStr, CString};
use std::os::fd::{AsFd, AsRawFd};
use std::os::unix::net::{UnixListener};
use std::process::Command;
use std::sync::OnceLock;
use std::{
fs,
io::{Read, Write},
os::unix::net::UnixStream,
};
#[cfg(target_pointer_width = "64")]
#[macro_export]
macro_rules! lp_select {
($lp32:expr, $lp64:expr) => { $lp64 };
($lp32:expr, $lp64:expr) => {
$lp64
};
}
#[cfg(target_pointer_width = "32")]
#[macro_export]
macro_rules! lp_select {
($lp32:expr, $lp64:expr) => { $lp32 };
($lp32:expr, $lp64:expr) => {
$lp32
};
}
#[cfg(debug_assertions)]
#[macro_export]
macro_rules! debug_select {
($debug:expr, $release:expr) => { $debug };
($debug:expr, $release:expr) => {
$debug
};
}
#[cfg(not(debug_assertions))]
#[macro_export]
macro_rules! debug_select {
($debug:expr, $release:expr) => { $release };
($debug:expr, $release:expr) => {
$release
};
}
pub struct LateInit<T> {
@@ -38,12 +52,18 @@ pub struct LateInit<T> {
impl<T> LateInit<T> {
pub const fn new() -> Self {
LateInit { cell: OnceLock::new() }
LateInit {
cell: OnceLock::new(),
}
}
pub fn init(&self, value: T) {
assert!(self.cell.set(value).is_ok())
}
pub fn initiated(&self) -> bool {
self.cell.get().is_some()
}
}
impl<T> std::ops::Deref for LateInit<T> {
@@ -58,7 +78,10 @@ pub fn set_socket_create_context(context: &str) -> Result<()> {
match fs::write(path, context) {
Ok(_) => Ok(()),
Err(_) => {
let path = format!("/proc/self/task/{}/attr/sockcreate", gettid().as_raw_nonzero());
let path = format!(
"/proc/self/task/{}/attr/sockcreate",
gettid().as_raw_nonzero()
);
fs::write(path, context)?;
Ok(())
}
@@ -94,6 +117,7 @@ pub fn get_property(name: &str) -> Result<String> {
Ok(prop.to_string_lossy().to_string())
}
#[allow(dead_code)]
pub fn set_property(name: &str, value: &str) -> Result<()> {
let name = CString::new(name)?;
let value = CString::new(value)?;
@@ -103,11 +127,10 @@ pub fn set_property(name: &str, value: &str) -> Result<()> {
Ok(())
}
#[allow(dead_code)]
pub fn wait_property(name: &str, serial: u32) -> Result<u32> {
let name = CString::new(name)?;
let info = unsafe {
__system_property_find(name.as_ptr())
};
let info = unsafe { __system_property_find(name.as_ptr()) };
let mut serial = serial;
unsafe {
__system_property_wait(info, serial, &mut serial, std::ptr::null());
@@ -115,14 +138,11 @@ pub fn wait_property(name: &str, serial: u32) -> Result<u32> {
Ok(serial)
}
#[allow(dead_code)]
pub fn get_property_serial(name: &str) -> Result<u32> {
let name = CString::new(name)?;
let info = unsafe {
__system_property_find(name.as_ptr())
};
Ok(unsafe {
__system_property_serial(info)
})
let info = unsafe { __system_property_find(name.as_ptr()) };
Ok(unsafe { __system_property_serial(info) })
}
pub fn switch_mount_namespace(pid: i32) -> Result<()> {
@@ -234,6 +254,11 @@ extern "C" {
fn __system_property_get(name: *const c_char, value: *mut c_char) -> u32;
fn __system_property_set(name: *const c_char, value: *const c_char) -> u32;
fn __system_property_find(name: *const c_char) -> *const c_void;
fn __system_property_wait(info: *const c_void, old_serial: u32, new_serial: *mut u32, timeout: *const libc::timespec) -> bool;
fn __system_property_wait(
info: *const c_void,
old_serial: u32,
new_serial: *mut u32,
timeout: *const libc::timespec,
) -> bool;
fn __system_property_serial(info: *const c_void) -> u32;
}

View File

@@ -1,24 +1,23 @@
use crate::constants::{DaemonSocketAction, ProcessFlags};
use crate::utils::{check_unix_socket, UnixStreamExt};
use crate::{constants, dl, lp_select, root_impl, utils};
use crate::utils::{check_unix_socket, LateInit, UnixStreamExt};
use crate::{constants, lp_select, root_impl, utils};
use anyhow::{bail, Result};
use log::{debug, error, info, trace, warn};
use passfd::FdPassingExt;
use std::sync::{Arc, Mutex};
use std::thread;
use rustix::fs::{fcntl_setfd, FdFlags};
use std::fs;
use std::io::Error;
use std::os::fd::{OwnedFd, RawFd};
use std::ops::Deref;
use std::os::fd::{AsFd, OwnedFd, RawFd};
use std::os::unix::process::CommandExt;
use std::os::unix::{
net::{UnixListener, UnixStream},
prelude::AsRawFd,
};
use std::path::PathBuf;
use std::process::{Command, exit};
use log::info;
use std::os::unix::process::CommandExt;
use bitflags::Flags;
type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32);
use std::process::{exit, Command};
use std::sync::{Arc, Mutex};
use std::thread;
struct Module {
name: String,
@@ -30,11 +29,23 @@ struct Context {
modules: Vec<Module>,
}
static TMP_PATH: LateInit<String> = LateInit::new();
static CONTROLLER_SOCKET: LateInit<String> = LateInit::new();
static PATH_CP_NAME: LateInit<String> = LateInit::new();
pub fn main() -> Result<()> {
log::info!("Welcome to Zygisk Next ({}) !", constants::ZKSU_VERSION);
info!("Welcome to Zygisk Next ({}) !", constants::ZKSU_VERSION);
TMP_PATH.init(std::env::var("TMP_PATH")?);
CONTROLLER_SOCKET.init(format!("{}/init_monitor", TMP_PATH.deref()));
PATH_CP_NAME.init(format!(
"{}/{}",
TMP_PATH.deref(),
lp_select!("/cp32.sock", "/cp64.sock")
));
let arch = get_arch()?;
log::debug!("Daemon architecture: {arch}");
debug!("Daemon architecture: {arch}");
let modules = load_modules(arch)?;
{
@@ -42,9 +53,13 @@ pub fn main() -> Result<()> {
let info = match root_impl::get_impl() {
root_impl::RootImpl::KernelSU | root_impl::RootImpl::Magisk => {
msg.extend_from_slice(&constants::DAEMON_SET_INFO.to_le_bytes());
let module_names: Vec<_> = modules.iter()
.map(|m| m.name.as_str()).collect();
format!("Root: {:?},module({}): {}", root_impl::get_impl(), modules.len(), module_names.join(","))
let module_names: Vec<_> = modules.iter().map(|m| m.name.as_str()).collect();
format!(
"Root: {:?},module({}): {}",
root_impl::get_impl(),
modules.len(),
module_names.join(",")
)
}
_ => {
msg.extend_from_slice(&constants::DAEMON_SET_ERROR_INFO.to_le_bytes());
@@ -54,12 +69,11 @@ pub fn main() -> Result<()> {
msg.extend_from_slice(&(info.len() as u32 + 1).to_le_bytes());
msg.extend_from_slice(info.as_bytes());
msg.extend_from_slice(&[0u8]);
utils::unix_datagram_sendto(constants::CONTROLLER_SOCKET, msg.as_slice()).expect("failed to send info");
utils::unix_datagram_sendto(&CONTROLLER_SOCKET, msg.as_slice())
.expect("failed to send info");
}
let context = Context {
modules,
};
let context = Context { modules };
let context = Arc::new(context);
let listener = create_daemon_socket()?;
for stream in listener.incoming() {
@@ -67,11 +81,11 @@ pub fn main() -> Result<()> {
let context = Arc::clone(&context);
let action = stream.read_u8()?;
let action = DaemonSocketAction::try_from(action)?;
log::trace!("New daemon action {:?}", action);
trace!("New daemon action {:?}", action);
match action {
DaemonSocketAction::PingHeartbeat => {
let value = constants::ZYGOTE_INJECTED;
utils::unix_datagram_sendto(constants::CONTROLLER_SOCKET, &value.to_le_bytes())?;
utils::unix_datagram_sendto(&CONTROLLER_SOCKET, &value.to_le_bytes())?;
}
DaemonSocketAction::ZygoteRestart => {
info!("Zygote restarted, clean up companions");
@@ -82,12 +96,12 @@ pub fn main() -> Result<()> {
}
DaemonSocketAction::SystemServerStarted => {
let value = constants::SYSTEM_SERVER_STARTED;
utils::unix_datagram_sendto(constants::CONTROLLER_SOCKET, &value.to_le_bytes())?;
utils::unix_datagram_sendto(&CONTROLLER_SOCKET, &value.to_le_bytes())?;
}
_ => {
thread::spawn(move || {
if let Err(e) = handle_daemon_action(action, stream, &context) {
log::warn!("Error handling daemon action: {}\n{}", e, e.backtrace());
warn!("Error handling daemon action: {}\n{}", e, e.backtrace());
}
});
}
@@ -113,7 +127,7 @@ fn load_modules(arch: &str) -> Result<Vec<Module>> {
let dir = match fs::read_dir(constants::PATH_MODULES_DIR) {
Ok(dir) => dir,
Err(e) => {
log::warn!("Failed reading modules directory: {}", e);
warn!("Failed reading modules directory: {}", e);
return Ok(modules);
}
};
@@ -125,16 +139,20 @@ fn load_modules(arch: &str) -> Result<Vec<Module>> {
if !so_path.exists() || disabled.exists() {
continue;
}
log::info!(" Loading module `{name}`...");
info!(" Loading module `{name}`...");
let lib_fd = match create_library_fd(&so_path) {
Ok(fd) => fd,
Err(e) => {
log::warn!(" Failed to create memfd for `{name}`: {e}");
warn!(" Failed to create memfd for `{name}`: {e}");
continue;
}
};
let companion = Mutex::new(None);
let module = Module { name, lib_fd, companion };
let module = Module {
name,
lib_fd,
companion,
};
modules.push(module);
}
@@ -161,7 +179,7 @@ fn create_library_fd(so_path: &PathBuf) -> Result<OwnedFd> {
fn create_daemon_socket() -> Result<UnixListener> {
utils::set_socket_create_context("u:r:zygote:s0")?;
let listener = utils::unix_listener_from_path(constants::PATH_CP_NAME)?;
let listener = utils::unix_listener_from_path(&PATH_CP_NAME)?;
Ok(listener)
}
@@ -187,13 +205,13 @@ fn spawn_companion(name: &str, lib_fd: RawFd) -> Result<Option<UnixStream>> {
0 => Ok(None),
1 => Ok(Some(daemon)),
_ => bail!("Invalid companion response"),
}
};
} else {
bail!("exited with status {}", status);
}
} else {
// Remove FD_CLOEXEC flag
unsafe { libc::fcntl(companion.as_raw_fd() as libc::c_int, libc::F_SETFD, 0i32); };
fcntl_setfd(companion.as_fd(), FdFlags::empty())?;
}
}
@@ -205,19 +223,21 @@ fn spawn_companion(name: &str, lib_fd: RawFd) -> Result<Option<UnixStream>> {
exit(0)
}
fn handle_daemon_action(action: DaemonSocketAction, mut stream: UnixStream, context: &Context) -> Result<()> {
fn handle_daemon_action(
action: DaemonSocketAction,
mut stream: UnixStream,
context: &Context,
) -> Result<()> {
match action {
DaemonSocketAction::RequestLogcatFd => {
loop {
let level = match stream.read_u8() {
Ok(level) => level,
Err(_) => break,
};
let tag = stream.read_string()?;
let message = stream.read_string()?;
utils::log_raw(level as i32, &tag, &message)?;
}
}
DaemonSocketAction::RequestLogcatFd => loop {
let level = match stream.read_u8() {
Ok(level) => level,
Err(_) => break,
};
let tag = stream.read_string()?;
let message = stream.read_string()?;
utils::log_raw(level as i32, &tag, &message)?;
},
DaemonSocketAction::GetProcessFlags => {
let uid = stream.read_u32()? as i32;
let mut flags = ProcessFlags::empty();
@@ -236,8 +256,16 @@ fn handle_daemon_action(action: DaemonSocketAction, mut stream: UnixStream, cont
root_impl::RootImpl::Magisk => flags |= ProcessFlags::PROCESS_ROOT_IS_MAGISK,
_ => panic!("wrong root impl: {:?}", root_impl::get_impl()),
}
log::trace!("Uid {} granted root: {}", uid, flags.contains(ProcessFlags::PROCESS_GRANTED_ROOT));
log::trace!("Uid {} on denylist: {}", uid, flags.contains(ProcessFlags::PROCESS_ON_DENYLIST));
trace!(
"Uid {} granted root: {}",
uid,
flags.contains(ProcessFlags::PROCESS_GRANTED_ROOT)
);
trace!(
"Uid {} on denylist: {}",
uid,
flags.contains(ProcessFlags::PROCESS_ON_DENYLIST)
);
stream.write_u32(flags.bits())?;
}
DaemonSocketAction::ReadModules => {
@@ -253,7 +281,7 @@ fn handle_daemon_action(action: DaemonSocketAction, mut stream: UnixStream, cont
let mut companion = module.companion.lock().unwrap();
if let Some(Some(sock)) = companion.as_ref() {
if !check_unix_socket(sock, false) {
log::error!("Poll companion for module `{}` crashed", module.name);
error!("Poll companion for module `{}` crashed", module.name);
companion.take();
}
}
@@ -261,21 +289,27 @@ fn handle_daemon_action(action: DaemonSocketAction, mut stream: UnixStream, cont
match spawn_companion(&module.name, module.lib_fd.as_raw_fd()) {
Ok(c) => {
if c.is_some() {
log::trace!(" Spawned companion for `{}`", module.name);
trace!(" Spawned companion for `{}`", module.name);
} else {
log::trace!(" No companion spawned for `{}` because it has not entry", module.name);
trace!(
" No companion spawned for `{}` because it has not entry",
module.name
);
}
*companion = Some(c);
},
}
Err(e) => {
log::warn!(" Failed to spawn companion for `{}`: {}", module.name, e);
warn!(" Failed to spawn companion for `{}`: {}", module.name, e);
}
};
}
match companion.as_ref() {
Some(Some(sock)) => {
if let Err(e) = sock.send_fd(stream.as_raw_fd()) {
log::error!("Failed to send companion fd socket of module `{}`: {}", module.name, e);
error!(
"Failed to send companion fd socket of module `{}`: {}",
module.name, e
);
stream.write_u8(0)?;
}
// Ok: Send by companion