diff --git a/native/jni/base/compat/fortify.hpp b/native/jni/base/compat/fortify.hpp index f6440a4c6..6fa6d4e81 100644 --- a/native/jni/base/compat/fortify.hpp +++ b/native/jni/base/compat/fortify.hpp @@ -6,7 +6,7 @@ #undef _FORTIFY_SOURCE -extern int __vloge(const char* fmt, va_list ap); +extern void __vloge(const char* fmt, va_list ap); static inline __noreturn __printflike(1, 2) void __fortify_fatal(const char* fmt, ...) { va_list args; diff --git a/native/jni/base/include/base.hpp b/native/jni/base/include/base.hpp index fede4dc5b..a8481f353 100644 --- a/native/jni/base/include/base.hpp +++ b/native/jni/base/include/base.hpp @@ -5,3 +5,4 @@ #include "../files.hpp" #include "../misc.hpp" #include "../logging.hpp" +#include diff --git a/native/jni/base/logging.cpp b/native/jni/base/logging.cpp index 7597404d7..1b5258d90 100644 --- a/native/jni/base/logging.cpp +++ b/native/jni/base/logging.cpp @@ -2,41 +2,52 @@ #include #include +#include -#include "logging.hpp" +// Just need to include it somewhere +#include using namespace std; -int nop_log(const char *, va_list) { return 0; } - -void nop_ex(int) {} +void nop_log(const char *, va_list) {} log_callback log_cb = { .d = nop_log, .i = nop_log, .w = nop_log, .e = nop_log, - .ex = nop_ex }; +static bool EXIT_ON_ERROR = false; -void no_logging() { - log_cb.d = nop_log; - log_cb.i = nop_log; - log_cb.w = nop_log; - log_cb.e = nop_log; - log_cb.ex = nop_ex; +static void fmt_and_log_with_rs(LogLevel level, const char *fmt, va_list ap) { + char buf[4096]; + int len = vsnprintf(buf, sizeof(buf), fmt, ap); + if (len > 0 && buf[len - 1] == '\n') { + // It's unfortunate that all logging on the C++ side always manually include + // a newline at the end due to how it was originally implemented. + // The logging infrastructure on the rust side does NOT expect a newline + // at the end, so we will have to strip it out before sending it over. + buf[len - 1] = '\0'; + } + log_with_rs(level, buf); } -static int vprintfe(const char *fmt, va_list ap) { - return vfprintf(stderr, fmt, ap); +#define rlog(prio) [](auto fmt, auto ap) { fmt_and_log_with_rs(LogLevel::prio, fmt, ap); } +static void forward_logging_to_rs() { + log_cb.d = rlog(Debug); + log_cb.i = rlog(Info); + log_cb.w = rlog(Warn); + log_cb.e = rlog(Error); } void cmdline_logging() { - log_cb.d = vprintfe; - log_cb.i = vprintf; - log_cb.w = vprintfe; - log_cb.e = vprintfe; - log_cb.ex = exit; + rs::logging::cmdline_logging(); + forward_logging_to_rs(); +} + +void exit_on_error(bool b) { + rs::logging::exit_on_error(b); + EXIT_ON_ERROR = b; } #define LOG_BODY(prio) { \ @@ -54,9 +65,9 @@ void LOGD(const char *fmt, ...) {} #endif void LOGI(const char *fmt, ...) { LOG_BODY(i) } void LOGW(const char *fmt, ...) { LOG_BODY(w) } -void LOGE(const char *fmt, ...) { LOG_BODY(e); log_cb.ex(EXIT_FAILURE); } +void LOGE(const char *fmt, ...) { LOG_BODY(e); if (EXIT_ON_ERROR) exit(EXIT_FAILURE); } // Export raw symbol to fortify compat -extern "C" int __vloge(const char* fmt, va_list ap) { - return log_cb.e(fmt, ap); +extern "C" void __vloge(const char* fmt, va_list ap) { + log_cb.e(fmt, ap); } diff --git a/native/jni/base/logging.hpp b/native/jni/base/logging.hpp index ef88b9eed..75c867803 100644 --- a/native/jni/base/logging.hpp +++ b/native/jni/base/logging.hpp @@ -4,11 +4,10 @@ #include struct log_callback { - int (*d)(const char* fmt, va_list ap); - int (*i)(const char* fmt, va_list ap); - int (*w)(const char* fmt, va_list ap); - int (*e)(const char* fmt, va_list ap); - void (*ex)(int code); + void (*d)(const char* fmt, va_list ap); + void (*i)(const char* fmt, va_list ap); + void (*w)(const char* fmt, va_list ap); + void (*e)(const char* fmt, va_list ap); }; extern log_callback log_cb; @@ -19,8 +18,7 @@ void LOGW(const char *fmt, ...) __printflike(1, 2); void LOGE(const char *fmt, ...) __printflike(1, 2); #define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s\n", ##args, errno, std::strerror(errno)) -int nop_log(const char *, va_list); -void nop_ex(int); +void nop_log(const char *, va_list); -void no_logging(); void cmdline_logging(); +void exit_on_error(bool b); diff --git a/native/jni/core/daemon.cpp b/native/jni/core/daemon.cpp index 1348baced..0b8e2a71e 100644 --- a/native/jni/core/daemon.cpp +++ b/native/jni/core/daemon.cpp @@ -11,6 +11,8 @@ #include #include +#include + #include "core.hpp" using namespace std; diff --git a/native/jni/core/logging.cpp b/native/jni/core/logging.cpp index afaa3e6b0..1a56c5df4 100644 --- a/native/jni/core/logging.cpp +++ b/native/jni/core/logging.cpp @@ -166,22 +166,22 @@ extern "C" int magisk_log_print(int prio, const char *tag, const char *fmt, ...) return ret; } -#define mlog(prio) [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_##prio, fmt, ap); } +#define mlog(prio) [](auto fmt, auto ap){ magisk_log(ANDROID_LOG_##prio, fmt, ap); } void magisk_logging() { log_cb.d = mlog(DEBUG); log_cb.i = mlog(INFO); log_cb.w = mlog(WARN); log_cb.e = mlog(ERROR); - log_cb.ex = nop_ex; + exit_on_error(false); } -#define alog(prio) [](auto fmt, auto ap){ return __android_log_vprint(ANDROID_LOG_##prio, "Magisk", fmt, ap); } +#define alog(prio) [](auto fmt, auto ap){ __android_log_vprint(ANDROID_LOG_##prio, "Magisk", fmt, ap); } void android_logging() { log_cb.d = alog(DEBUG); log_cb.i = alog(INFO); log_cb.w = alog(WARN); log_cb.e = alog(ERROR); - log_cb.ex = nop_ex; + exit_on_error(false); } void start_log_daemon() { diff --git a/native/jni/core/magisk.cpp b/native/jni/core/magisk.cpp index 7d21b90a9..c7d2c4ff8 100644 --- a/native/jni/core/magisk.cpp +++ b/native/jni/core/magisk.cpp @@ -127,6 +127,7 @@ int magisk_main(int argc, char *argv[]) { #if 0 /* Entry point for testing stuffs */ else if (argv[1] == "--test"sv) { + rust_test_entry(); return 0; } #endif diff --git a/native/jni/include/daemon.hpp b/native/jni/include/daemon.hpp index 1be5e7cd7..05d61a562 100644 --- a/native/jni/include/daemon.hpp +++ b/native/jni/include/daemon.hpp @@ -8,6 +8,7 @@ #include #include +#include #define AID_ROOT 0 #define AID_SHELL 2000 diff --git a/native/jni/init/getinfo.cpp b/native/jni/init/getinfo.cpp index 5e5533600..1b08c1769 100644 --- a/native/jni/init/getinfo.cpp +++ b/native/jni/init/getinfo.cpp @@ -119,9 +119,9 @@ static bool check_key_combo() { static FILE *kmsg; static char kmsg_buf[4096]; -static int vprintk(const char *fmt, va_list ap) { +static void vprintk(const char *fmt, va_list ap) { vsnprintf(kmsg_buf + 12, sizeof(kmsg_buf) - 12, fmt, ap); - return fprintf(kmsg, "%s", kmsg_buf); + fprintf(kmsg, "%s", kmsg_buf); } void setup_klog() { // Shut down first 3 fds @@ -150,7 +150,7 @@ void setup_klog() { kmsg = fdopen(fd, "w"); setbuf(kmsg, nullptr); log_cb.d = log_cb.i = log_cb.w = log_cb.e = vprintk; - log_cb.ex = nop_ex; + exit_on_error(false); strcpy(kmsg_buf, "magiskinit: "); // Disable kmsg rate limiting diff --git a/native/jni/resetprop/resetprop.cpp b/native/jni/resetprop/resetprop.cpp index 98b8fbf38..bc3b0e194 100644 --- a/native/jni/resetprop/resetprop.cpp +++ b/native/jni/resetprop/resetprop.cpp @@ -13,8 +13,6 @@ using namespace std; -static bool verbose = false; - #ifdef APPLET_STUB_MAIN #define system_property_set __system_property_set #define system_property_find __system_property_find @@ -297,10 +295,9 @@ void load_prop_file(const char *filename, bool prop_svc) { } int resetprop_main(int argc, char *argv[]) { - log_cb.d = [](auto fmt, auto ap) -> int { return verbose ? vfprintf(stderr, fmt, ap) : 0; }; - bool prop_svc = true; bool persist = false; + bool verbose = false; char *argv0 = argv[0]; --argc; @@ -340,6 +337,9 @@ int resetprop_main(int argc, char *argv[]) { ++argv; } + if (!verbose) + log_cb.d = nop_log; + switch (argc) { case 0: print_props(persist); diff --git a/native/jni/su/su_daemon.cpp b/native/jni/su/su_daemon.cpp index 87e31fcc4..e8c8c8f9a 100644 --- a/native/jni/su/su_daemon.cpp +++ b/native/jni/su/su_daemon.cpp @@ -311,7 +311,7 @@ void su_daemon_handler(int client, const sock_cred *cred) { LOGD("su: fork handler\n"); // Abort upon any error occurred - log_cb.ex = exit; + exit_on_error(true); // ack write_int(client, 0); diff --git a/native/jni/zygisk/entry.cpp b/native/jni/zygisk/entry.cpp index bc1d1a4f4..2fec0b40a 100644 --- a/native/jni/zygisk/entry.cpp +++ b/native/jni/zygisk/entry.cpp @@ -17,15 +17,15 @@ using namespace std; void *self_handle = nullptr; -static int zygisk_log(int prio, const char *fmt, va_list ap); +static void zygisk_log(int prio, const char *fmt, va_list ap); -#define zlog(prio) [](auto fmt, auto ap){ return zygisk_log(ANDROID_LOG_##prio, fmt, ap); } +#define zlog(prio) [](auto fmt, auto ap){ zygisk_log(ANDROID_LOG_##prio, fmt, ap); } static void zygisk_logging() { log_cb.d = zlog(DEBUG); log_cb.i = zlog(INFO); log_cb.w = zlog(WARN); log_cb.e = zlog(ERROR); - log_cb.ex = nop_ex; + exit_on_error(false); } // Make sure /proc/self/environ is sanitized @@ -114,7 +114,7 @@ static void zygisk_init() { // The following code runs in zygote/app process -static int zygisk_log(int prio, const char *fmt, va_list ap) { +static void zygisk_log(int prio, const char *fmt, va_list ap) { // If we don't have log pipe set, ask magiskd for it // This could happen multiple times in zygote because it was closed to prevent crashing if (logd_fd < 0) { @@ -139,13 +139,12 @@ static int zygisk_log(int prio, const char *fmt, va_list ap) { sigaddset(&mask, SIGPIPE); pthread_sigmask(SIG_BLOCK, &mask, &orig_mask); } - int ret = magisk_log(prio, fmt, ap); + magisk_log(prio, fmt, ap); if (sig) { timespec ts{}; sigtimedwait(&mask, nullptr, &ts); pthread_sigmask(SIG_SETMASK, &orig_mask, nullptr); } - return ret; } static inline bool should_load_modules(uint32_t flags) { diff --git a/native/rust/Cargo.lock b/native/rust/Cargo.lock index b24797e6b..1a64b59c5 100644 --- a/native/rust/Cargo.lock +++ b/native/rust/Cargo.lock @@ -5,6 +5,9 @@ version = 3 [[package]] name = "base" version = "0.1.0" +dependencies = [ + "cxx", +] [[package]] name = "cc" diff --git a/native/rust/base/Cargo.toml b/native/rust/base/Cargo.toml index d683bee11..5cc231340 100644 --- a/native/rust/base/Cargo.toml +++ b/native/rust/base/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] +cxx = "1.0.69" diff --git a/native/rust/base/src/lib.rs b/native/rust/base/src/lib.rs index e69de29bb..3a3bc778b 100644 --- a/native/rust/base/src/lib.rs +++ b/native/rust/base/src/lib.rs @@ -0,0 +1,25 @@ +pub use logging::*; + +mod logging; + +#[cxx::bridge] +pub mod ffi { + pub enum LogLevel { + Error, + Warn, + Info, + Debug, + } + + extern "Rust" { + fn log_with_rs(level: LogLevel, msg: &str); + } +} + +#[cxx::bridge(namespace = "rs::logging")] +pub mod ffi2 { + extern "Rust" { + fn cmdline_logging(); + fn exit_on_error(b: bool); + } +} diff --git a/native/rust/base/src/logging.rs b/native/rust/base/src/logging.rs new file mode 100644 index 000000000..e0587a506 --- /dev/null +++ b/native/rust/base/src/logging.rs @@ -0,0 +1,91 @@ +use std::fmt::Arguments; +use std::process::exit; + +use crate::ffi::LogLevel; + +// We don't need to care about thread safety, because all +// logger changes will only happen on the main thread. +pub static mut LOGGER: Logger = Logger { + d: nop_log, + i: nop_log, + w: nop_log, + e: nop_log, +}; +static mut EXIT_ON_ERROR: bool = false; + +#[derive(Copy, Clone)] +pub struct Logger { + pub d: fn(args: Arguments), + pub i: fn(args: Arguments), + pub w: fn(args: Arguments), + pub e: fn(args: Arguments), +} + +pub fn nop_log(_: Arguments) {} + +fn println(args: Arguments) { println!("{}", args); } + +fn eprintln(args: Arguments) { eprintln!("{}", args); } + +pub fn log_with_rs(level: LogLevel, msg: &str) { + log_impl(level, format_args!("{}", msg)); +} + +pub fn exit_on_error(b: bool) { + unsafe { EXIT_ON_ERROR = b; } +} + +pub fn cmdline_logging() { + let logger = Logger { + d: eprintln, + i: println, + w: eprintln, + e: eprintln, + }; + unsafe { + LOGGER = logger; + EXIT_ON_ERROR = true; + } +} + +pub fn log_impl(level: LogLevel, args: Arguments) { + let logger = unsafe { LOGGER }; + let aoe = unsafe { EXIT_ON_ERROR }; + match level { + LogLevel::Error => { + (logger.e)(args); + if aoe { exit(1); } + } + LogLevel::Warn => (logger.w)(args), + LogLevel::Info => (logger.i)(args), + LogLevel::Debug => (logger.d)(args), + _ => () + } +} + +#[macro_export] +macro_rules! error { + ($($arg:tt)+) => ($crate::log_impl($crate::ffi::LogLevel::Error, format_args!($($arg)+))) +} + +#[macro_export] +macro_rules! warn { + ($($arg:tt)+) => ($crate::log_impl($crate::ffi::LogLevel::Warn, format_args!($($arg)+))) +} + +#[macro_export] +macro_rules! info { + ($($arg:tt)+) => ($crate::log_impl($crate::ffi::LogLevel::Info, format_args!($($arg)+))) +} + +#[cfg(debug_assertions)] +#[macro_export] +macro_rules! debug { + ($($arg:tt)+) => ($crate::log_impl($crate::ffi::LogLevel::Debug, format_args!($($arg)+))) +} + +#[cfg(not(debug_assertions))] +#[macro_export] +macro_rules! debug { + ($($arg:tt)+) => () +} diff --git a/native/rust/boot/src/lib.rs b/native/rust/boot/src/lib.rs index e69de29bb..8411b1d59 100644 --- a/native/rust/boot/src/lib.rs +++ b/native/rust/boot/src/lib.rs @@ -0,0 +1 @@ +pub use base; diff --git a/native/rust/core/src/lib.rs b/native/rust/core/src/lib.rs index e69de29bb..ec659ef92 100644 --- a/native/rust/core/src/lib.rs +++ b/native/rust/core/src/lib.rs @@ -0,0 +1,10 @@ +pub use base; + +#[cxx::bridge] +pub mod ffi { + extern "Rust" { + fn rust_test_entry(); + } +} + +fn rust_test_entry() {} diff --git a/native/rust/init/src/lib.rs b/native/rust/init/src/lib.rs index e69de29bb..8411b1d59 100644 --- a/native/rust/init/src/lib.rs +++ b/native/rust/init/src/lib.rs @@ -0,0 +1 @@ +pub use base; diff --git a/native/rust/sepolicy/src/lib.rs b/native/rust/sepolicy/src/lib.rs index e69de29bb..8411b1d59 100644 --- a/native/rust/sepolicy/src/lib.rs +++ b/native/rust/sepolicy/src/lib.rs @@ -0,0 +1 @@ +pub use base;