From b136aba1e29e174c0921cec6700f3a196abf9674 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 2 May 2023 16:49:43 -0700 Subject: [PATCH] Implement magiskinit logging in Rust --- native/src/Cargo.lock | 12 +++---- native/src/base/files.rs | 8 ++--- native/src/base/misc.rs | 21 +++++++---- native/src/init/getinfo.cpp | 51 +-------------------------- native/src/init/init.cpp | 1 + native/src/init/init.hpp | 2 -- native/src/init/logging.rs | 70 +++++++++++++++++++++++++++++-------- native/src/init/rootdir.cpp | 2 +- 8 files changed, 84 insertions(+), 83 deletions(-) diff --git a/native/src/Cargo.lock b/native/src/Cargo.lock index ec159b779..41ecdb474 100644 --- a/native/src/Cargo.lock +++ b/native/src/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.73" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.127" +version = "0.2.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" [[package]] name = "magisk" @@ -112,6 +112,6 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.2" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" diff --git a/native/src/base/files.rs b/native/src/base/files.rs index e748b84ba..257336ea3 100644 --- a/native/src/base/files.rs +++ b/native/src/base/files.rs @@ -53,20 +53,20 @@ pub fn __xopen_fd_impl(path: &CStr, flags: i32, mode: mode_t) -> Option #[macro_export] macro_rules! open_fd { ($path:expr, $flags:expr) => { - crate::__open_fd_impl($path, $flags, 0) + $crate::__open_fd_impl($path, $flags, 0) }; ($path:expr, $flags:expr, $mode:expr) => { - crate::__open_fd_impl($path, $flags, $mode) + $crate::__open_fd_impl($path, $flags, $mode) }; } #[macro_export] macro_rules! xopen_fd { ($path:expr, $flags:expr) => { - crate::__xopen_fd_impl($path, $flags, 0) + $crate::__xopen_fd_impl($path, $flags, 0) }; ($path:expr, $flags:expr, $mode:expr) => { - crate::__xopen_fd_impl($path, $flags, $mode) + $crate::__xopen_fd_impl($path, $flags, $mode) }; } diff --git a/native/src/base/misc.rs b/native/src/base/misc.rs index 521acb651..f835dd032 100644 --- a/native/src/base/misc.rs +++ b/native/src/base/misc.rs @@ -3,6 +3,13 @@ use std::ffi::CStr; use std::fmt::Arguments; use std::{fmt, slice}; +pub fn copy_str(dest: &mut [u8], src: &[u8]) -> usize { + let len = min(src.len(), dest.len() - 1); + dest[..len].copy_from_slice(&src[..len]); + dest[len] = b'\0'; + len +} + struct BufFmtWriter<'a> { buf: &'a mut [u8], used: usize, @@ -21,12 +28,7 @@ impl<'a> fmt::Write for BufFmtWriter<'a> { // Silent truncate return Ok(()); } - let remain = &mut self.buf[self.used..]; - let s_bytes = s.as_bytes(); - let copied = min(s_bytes.len(), remain.len() - 1); - remain[..copied].copy_from_slice(&s_bytes[..copied]); - self.used += copied; - self.buf[self.used] = b'\0'; + self.used += copy_str(&mut self.buf[self.used..], s.as_bytes()); // Silent truncate Ok(()) } @@ -107,6 +109,13 @@ macro_rules! cstr { }}; } +#[macro_export] +macro_rules! str_ptr { + ($s:literal) => {{ + cstr!($s).as_ptr() + }}; +} + pub fn ptr_to_str<'a, T>(ptr: *const T) -> &'a str { if ptr.is_null() { "(null)" diff --git a/native/src/init/getinfo.cpp b/native/src/init/getinfo.cpp index 9795fe9d2..b3625e39a 100644 --- a/native/src/init/getinfo.cpp +++ b/native/src/init/getinfo.cpp @@ -117,55 +117,6 @@ static bool check_key_combo() { return false; } -static FILE *kmsg; -extern "C" void klog_write(const char *msg, int len) { - fprintf(kmsg, "%.*s", len, msg); -} - -static int klog_with_rs(LogLevel level, const char *fmt, va_list ap) { - char buf[4096]; - strscpy(buf, "magiskinit: ", sizeof(buf)); - int len = vssprintf(buf + 12, sizeof(buf) - 12, fmt, ap) + 12; - log_with_rs(level, rust::Str(buf, len)); - return len; -} - -void setup_klog() { - // Shut down first 3 fds - int fd; - if (access("/dev/null", W_OK) == 0) { - fd = xopen("/dev/null", O_RDWR | O_CLOEXEC); - } else { - mknod("/null", S_IFCHR | 0666, makedev(1, 3)); - fd = xopen("/null", O_RDWR | O_CLOEXEC); - unlink("/null"); - } - xdup3(fd, STDIN_FILENO, O_CLOEXEC); - xdup3(fd, STDOUT_FILENO, O_CLOEXEC); - xdup3(fd, STDERR_FILENO, O_CLOEXEC); - if (fd > STDERR_FILENO) - close(fd); - - if (access("/dev/kmsg", W_OK) == 0) { - fd = xopen("/dev/kmsg", O_WRONLY | O_CLOEXEC); - } else { - mknod("/kmsg", S_IFCHR | 0666, makedev(1, 11)); - fd = xopen("/kmsg", O_WRONLY | O_CLOEXEC); - unlink("/kmsg"); - } - - kmsg = fdopen(fd, "w"); - setbuf(kmsg, nullptr); - rust::setup_klog(); - cpp_logger = klog_with_rs; - - // Disable kmsg rate limiting - if (FILE *rate = fopen("/proc/sys/kernel/printk_devkmsg", "w")) { - fprintf(rate, "on\n"); - fclose(rate); - } -} - void BootConfig::set(const kv_pairs &kv) { for (const auto &[key, value] : kv) { if (key == "androidboot.slot_suffix") { @@ -231,7 +182,7 @@ void load_kernel_info(BootConfig *config) { mount_list.emplace_back("/sys"); // Log to kernel - setup_klog(); + rust::setup_klog(); config->set(parse_cmdline(full_read("/proc/cmdline"))); config->set(parse_bootconfig(full_read("/proc/bootconfig"))); diff --git a/native/src/init/init.cpp b/native/src/init/init.cpp index 8417bd67e..fc9652061 100644 --- a/native/src/init/init.cpp +++ b/native/src/init/init.cpp @@ -90,6 +90,7 @@ int main(int argc, char *argv[]) { BootConfig config{}; if (argc > 1 && argv[1] == "selinux_setup"sv) { + rust::setup_klog(); init = new SecondStageInit(argv); } else { // This will also mount /sys and /proc diff --git a/native/src/init/init.hpp b/native/src/init/init.hpp index f8d737360..6a9aaf422 100644 --- a/native/src/init/init.hpp +++ b/native/src/init/init.hpp @@ -28,7 +28,6 @@ int magisk_proxy_main(int argc, char *argv[]); bool unxz(int fd, const uint8_t *buf, size_t size); void load_kernel_info(BootConfig *config); bool check_two_stage(); -void setup_klog(); const char *backup_init(); void restore_ramdisk_init(); int dump_preload(const char *path, mode_t mode); @@ -87,7 +86,6 @@ private: bool prepare(); public: SecondStageInit(char *argv[]) : MagiskInit(argv) { - setup_klog(); LOGD("%s\n", __FUNCTION__); }; diff --git a/native/src/init/logging.rs b/native/src/init/logging.rs index b2add8e29..68fe96f71 100644 --- a/native/src/init/logging.rs +++ b/native/src/init/logging.rs @@ -1,27 +1,69 @@ -use base::ffi::LogLevel; -use base::*; use std::fmt::Arguments; +use std::fs; +use std::fs::File; +use std::io::Write; +use std::sync::OnceLock; -extern "C" { - fn klog_write(msg: *const u8, len: i32); -} +use base::ffi::LogLevel; +use base::libc::{ + close, makedev, mknod, open, syscall, unlink, SYS_dup3, O_CLOEXEC, O_RDWR, STDERR_FILENO, + STDIN_FILENO, STDOUT_FILENO, S_IFCHR, +}; +use base::*; + +static KMSG: OnceLock = OnceLock::new(); pub fn setup_klog() { - const PREFIX: &[u8; 12] = b"magiskinit: "; - const PFX_LEN: usize = PREFIX.len(); + // Shut down first 3 fds + unsafe { + let mut fd = open(str_ptr!("/dev/null"), O_RDWR | O_CLOEXEC); + if fd < 0 { + mknod(str_ptr!("/null"), S_IFCHR | 0666, makedev(1, 3)); + fd = open(str_ptr!("/null"), O_RDWR | O_CLOEXEC); + fs::remove_file("/null").ok(); + } + + syscall(SYS_dup3, fd, STDIN_FILENO, O_CLOEXEC); + syscall(SYS_dup3, fd, STDOUT_FILENO, O_CLOEXEC); + syscall(SYS_dup3, fd, STDERR_FILENO, O_CLOEXEC); + if fd > STDERR_FILENO { + close(fd); + } + } + + if let Ok(kmsg) = File::options().write(true).open("/dev/kmsg") { + KMSG.set(kmsg).ok(); + } else { + unsafe { + mknod(str_ptr!("/kmsg"), S_IFCHR | 0666, makedev(1, 11)); + KMSG.set(File::options().write(true).open("/kmsg").unwrap()) + .ok(); + unlink(str_ptr!("/kmsg")); + } + } + + // Disable kmsg rate limiting + if let Ok(mut rate) = File::options() + .write(true) + .open("/proc/sys/kernel/printk_devkmsg") + { + writeln!(rate, "on").ok(); + } fn klog_fmt(_: LogLevel, args: Arguments) { - let mut buf: [u8; 4096] = [0; 4096]; - buf[..PFX_LEN].copy_from_slice(PREFIX); - let len = fmt_to_buf(&mut buf[PFX_LEN..], args) + PFX_LEN; - unsafe { - klog_write(buf.as_ptr(), len as i32); + if let Some(kmsg) = KMSG.get().as_mut() { + let mut buf: [u8; 4096] = [0; 4096]; + let len = fmt_to_buf(&mut buf, format_args!("magiskinit: {}", args)); + kmsg.write_all(&buf[..len]).ok(); } } fn klog_write_impl(_: LogLevel, msg: &[u8]) { - unsafe { - klog_write(msg.as_ptr(), msg.len() as i32); + if let Some(kmsg) = KMSG.get().as_mut() { + let mut buf: [u8; 4096] = [0; 4096]; + let mut len = copy_str(&mut buf, b"magiskinit: "); + len += copy_str(&mut buf[len..], msg); + kmsg.write_all(&buf[..len]).ok(); } } diff --git a/native/src/init/rootdir.cpp b/native/src/init/rootdir.cpp index ccde27cad..2b69f41a5 100644 --- a/native/src/init/rootdir.cpp +++ b/native/src/init/rootdir.cpp @@ -349,7 +349,7 @@ void MagiskInit::patch_rw_root() { } int magisk_proxy_main(int argc, char *argv[]) { - setup_klog(); + rust::setup_klog(); LOGD("%s\n", __FUNCTION__); // Mount rootfs as rw to do post-init rootfs patches