Move all xwrap to Rust

This commit is contained in:
topjohnwu 2022-09-15 01:17:05 -07:00
parent 66a7ef5615
commit c6646efe68
18 changed files with 356 additions and 198 deletions

7
native/src/Cargo.lock generated
View File

@ -6,6 +6,7 @@ version = 3
name = "base" name = "base"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"cfg-if",
"cxx", "cxx",
"libc", "libc",
] ]
@ -16,6 +17,12 @@ version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "cxx" name = "cxx"
version = "1.0.72" version = "1.0.72"

View File

@ -14,7 +14,6 @@ LOCAL_SRC_FILES := \
misc.cpp \ misc.cpp \
selinux.cpp \ selinux.cpp \
logging.cpp \ logging.cpp \
xwrap.cpp \
stream.cpp \ stream.cpp \
../external/cxx-rs/src/cxx.cc ../external/cxx-rs/src/cxx.cc
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)

View File

@ -9,3 +9,4 @@ path = "lib.rs"
[dependencies] [dependencies]
cxx = { path = "../external/cxx-rs" } cxx = { path = "../external/cxx-rs" }
libc = "0.2" libc = "0.2"
cfg-if = "1.0"

View File

@ -9,38 +9,12 @@
using namespace std; using namespace std;
ssize_t fd_path(int fd, char *path, size_t size) {
ssprintf(path, size, "/proc/self/fd/%d", fd);
return xreadlink(path, path, size);
}
int fd_pathat(int dirfd, const char *name, char *path, size_t size) { int fd_pathat(int dirfd, const char *name, char *path, size_t size) {
if (fd_path(dirfd, path, size) < 0) if (fd_path(dirfd, byte_slice(path, size)) < 0)
return -1; return -1;
auto len = strlen(path); auto len = strlen(path);
path[len] = '/'; path[len] = '/';
strlcpy(path + len + 1, name, size - len - 1); strscpy(path + len + 1, name, size - len - 1);
return 0;
}
int mkdirs(const char *path, mode_t mode) {
char buf[4096];
strlcpy(buf, path, sizeof(buf));
errno = 0;
for (char *p = &buf[1]; *p; ++p) {
if (*p == '/') {
*p = '\0';
if (mkdir(buf, mode) == -1) {
if (errno != EEXIST)
return -1;
}
*p = '/';
}
}
if (mkdir(buf, mode) == -1) {
if (errno != EEXIST)
return -1;
}
return 0; return 0;
} }
@ -410,14 +384,14 @@ void parse_mnt(const char *file, const function<bool(mntent*)> &fn) {
void backup_folder(const char *dir, vector<raw_file> &files) { void backup_folder(const char *dir, vector<raw_file> &files) {
char path[PATH_MAX]; char path[PATH_MAX];
xrealpath(dir, path); xcanonical_path(dir, path, sizeof(path));
int len = strlen(path); int len = strlen(path);
pre_order_walk(xopen(dir, O_RDONLY), [&](int dfd, dirent *entry) -> walk_result { pre_order_walk(xopen(dir, O_RDONLY), [&](int dfd, dirent *entry) -> walk_result {
int fd = xopenat(dfd, entry->d_name, O_RDONLY); int fd = xopenat(dfd, entry->d_name, O_RDONLY);
if (fd < 0) if (fd < 0)
return SKIP; return SKIP;
run_finally f([&]{ close(fd); }); run_finally f([&]{ close(fd); });
if (fd_path(fd, path, sizeof(path)) < 0) if (fd_path(fd, byte_slice(path, sizeof(path))) < 0)
return SKIP; return SKIP;
raw_file file; raw_file file;
file.path = path + len + 1; file.path = path + len + 1;

View File

@ -58,9 +58,16 @@ struct mmap_data : public byte_data {
mmap_data& operator=(mmap_data &&other) { swap(other); return *this; } mmap_data& operator=(mmap_data &&other) { swap(other); return *this; }
}; };
ssize_t fd_path(int fd, char *path, size_t size); extern "C" {
int fd_pathat(int dirfd, const char *name, char *path, size_t size);
int mkdirs(const char *path, mode_t mode); int mkdirs(const char *path, mode_t mode);
ssize_t canonical_path(const char *path, char *buf, size_t bufsiz);
ssize_t read_link(const char *pathname, char *buf, size_t bufsiz);
} // extern "C"
using rust::fd_path;
int fd_pathat(int dirfd, const char *name, char *path, size_t size);
void rm_rf(const char *path); void rm_rf(const char *path);
void mv_path(const char *src, const char *dest); void mv_path(const char *src, const char *dest);
void mv_dir(int src, int dest); void mv_dir(int src, int dest);

112
native/src/base/files.rs Normal file
View File

@ -0,0 +1,112 @@
use std::ffi::CStr;
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd};
use libc::{c_char, mode_t, EEXIST, ENOENT, O_CLOEXEC, O_PATH};
use crate::{bfmt_cstr, errno, xopen};
mod unsafe_impl {
use std::ffi::CStr;
use std::slice;
use libc::c_char;
#[no_mangle]
pub unsafe extern "C" fn read_link(path: *const c_char, buf: *mut u8, bufsz: usize) -> isize {
let r = libc::readlink(path, buf.cast(), bufsz - 1);
if r >= 0 {
*buf.offset(r) = b'\0';
}
return r;
}
#[no_mangle]
unsafe extern "C" fn canonical_path(path: *const c_char, buf: *mut u8, bufsz: usize) -> isize {
super::canonical_path(CStr::from_ptr(path), slice::from_raw_parts_mut(buf, bufsz))
}
}
pub fn __open_fd_impl(path: &CStr, flags: i32, mode: mode_t) -> Option<OwnedFd> {
let fd = xopen(path.as_ptr(), flags, mode);
if fd >= 0 {
unsafe { Some(OwnedFd::from_raw_fd(fd)) }
} else {
None
}
}
#[macro_export]
macro_rules! open_fd {
($path:expr, $flags:expr) => {
crate::__open_fd_impl($path, $flags, 0)
};
($path:expr, $flags:expr, $mode:expr) => {
crate::__open_fd_impl($path, $flags, $mode)
};
}
pub fn readlink(path: &CStr, data: &mut [u8]) -> isize {
unsafe { unsafe_impl::read_link(path.as_ptr(), data.as_mut_ptr(), data.len()) }
}
pub fn fd_path(fd: RawFd, buf: &mut [u8]) -> isize {
let mut fd_buf: [u8; 40] = [0; 40];
let fd_path = bfmt_cstr!(&mut fd_buf, "/proc/self/fd/{}", fd);
readlink(fd_path, buf)
}
// Inspired by https://android.googlesource.com/platform/bionic/+/master/libc/bionic/realpath.cpp
pub fn canonical_path(path: &CStr, buf: &mut [u8]) -> isize {
if let Some(fd) = open_fd!(path, O_PATH | O_CLOEXEC) {
let mut st1: libc::stat;
let mut st2: libc::stat;
unsafe {
st1 = std::mem::zeroed();
if libc::fstat(fd.as_raw_fd(), &mut st1) < 0 {
*errno() = ENOENT;
return -1;
}
}
let len = fd_path(fd.as_raw_fd(), buf);
unsafe {
st2 = std::mem::zeroed();
if libc::stat(buf.as_ptr().cast(), &mut st2) < 0
|| st2.st_dev != st1.st_dev
|| st2.st_ino != st1.st_ino
{
*errno() = ENOENT;
return -1;
}
}
return len;
} else {
*errno() = ENOENT;
-1
}
}
extern "C" {
fn strscpy(dst: *mut c_char, src: *const c_char, size: usize) -> usize;
}
#[no_mangle]
pub extern "C" fn mkdirs(path: *const c_char, mode: mode_t) -> i32 {
unsafe {
let mut buf = [0 as u8; 4096];
let ptr: *mut c_char = buf.as_mut_ptr().cast();
let len = strscpy(ptr, path, buf.len());
let mut curr = &mut buf[1..len];
while let Some(p) = curr.iter().position(|c| *c == b'/') {
curr[p] = b'\0';
if libc::mkdir(ptr, mode) < 0 && *errno() != EEXIST {
return -1;
}
curr[p] = b'/';
curr = &mut curr[(p + 1)..];
}
if libc::mkdir(ptr, mode) < 0 && *errno() != EEXIST {
return -1;
}
0
}
}

View File

@ -2,10 +2,12 @@
pub use libc; pub use libc;
pub use files::*;
pub use logging::*; pub use logging::*;
pub use misc::*; pub use misc::*;
pub use xwrap::*; pub use xwrap::*;
mod files;
mod logging; mod logging;
mod misc; mod misc;
mod xwrap; mod xwrap;
@ -31,9 +33,7 @@ pub mod ffi {
#[cxx::bridge(namespace = "rust")] #[cxx::bridge(namespace = "rust")]
pub mod ffi2 { pub mod ffi2 {
extern "Rust" { extern "Rust" {
fn xwrite(fd: i32, data: &[u8]) -> isize;
fn xread(fd: i32, data: &mut [u8]) -> isize;
fn xxread(fd: i32, data: &mut [u8]) -> isize;
fn xpipe2(fds: &mut [i32; 2], flags: i32) -> i32; fn xpipe2(fds: &mut [i32; 2], flags: i32) -> i32;
fn fd_path(fd: i32, buf: &mut [u8]) -> isize;
} }
} }

View File

@ -41,7 +41,7 @@ extern "C" int magisk_log_print(int prio, const char *tag, const char *fmt, ...)
} }
char fmt_buf[4096]; char fmt_buf[4096];
auto len = strlcpy(fmt_buf, tag, sizeof(fmt_buf) - 1); auto len = strscpy(fmt_buf, tag, sizeof(fmt_buf) - 1);
// Prevent format specifications in the tag // Prevent format specifications in the tag
std::replace(fmt_buf, fmt_buf + len, '%', '_'); std::replace(fmt_buf, fmt_buf + len, '%', '_');
len = ssprintf(fmt_buf + len, sizeof(fmt_buf) - len - 1, ": %s", fmt) + len; len = ssprintf(fmt_buf + len, sizeof(fmt_buf) - len - 1, ": %s", fmt) + len;

View File

@ -130,7 +130,7 @@ void init_argv0(int argc, char **argv) {
void set_nice_name(const char *name) { void set_nice_name(const char *name) {
memset(argv0, 0, name_len); memset(argv0, 0, name_len);
strlcpy(argv0, name, name_len); strscpy(argv0, name, name_len);
prctl(PR_SET_NAME, name); prctl(PR_SET_NAME, name);
} }
@ -224,3 +224,8 @@ int ssprintf(char *dest, size_t size, const char *fmt, ...) {
va_end(va); va_end(va);
return r; return r;
} }
#undef strlcpy
size_t strscpy(char *dest, const char *src, size_t size) {
return std::min(strlcpy(dest, src, size), size - 1);
}

View File

@ -6,6 +6,8 @@
#include <string_view> #include <string_view>
#include <bitset> #include <bitset>
#include <base-rs.hpp>
#define DISALLOW_COPY_AND_MOVE(clazz) \ #define DISALLOW_COPY_AND_MOVE(clazz) \
clazz(const clazz &) = delete; \ clazz(const clazz &) = delete; \
clazz(clazz &&) = delete; clazz(clazz &&) = delete;
@ -118,6 +120,11 @@ struct StringCmp {
bool operator()(std::string_view a, std::string_view b) const { return a < b; } bool operator()(std::string_view a, std::string_view b) const { return a < b; }
}; };
template<typename T>
rust::Slice<uint8_t> byte_slice(T *buf, size_t sz) {
return rust::Slice(reinterpret_cast<uint8_t *>(buf), sz);
}
int parse_int(std::string_view s); int parse_int(std::string_view s);
using thread_entry = void *(*)(void *); using thread_entry = void *(*)(void *);
@ -160,10 +167,14 @@ std::vector<std::string_view> split_ro(std::string_view, std::string_view delims
int vssprintf(char *dest, size_t size, const char *fmt, va_list ap); int vssprintf(char *dest, size_t size, const char *fmt, va_list ap);
// Similar to snprintf, but the return value is the written number of bytes // Similar to snprintf, but the return value is the written number of bytes
int ssprintf(char *dest, size_t size, const char *fmt, ...); int ssprintf(char *dest, size_t size, const char *fmt, ...);
// This is not actually the strscpy from the Linux kernel.
// Silently truncates, and returns the number of bytes written.
extern "C" size_t strscpy(char *dest, const char *src, size_t size);
// Ban usage of unsafe cstring functions // Ban usage of unsafe cstring functions
#define vsnprintf __use_vssprintf_instead__ #define vsnprintf __use_vssprintf_instead__
#define snprintf __use_ssprintf_instead__ #define snprintf __use_ssprintf_instead__
#define strlcpy __use_strscpy_instead__
struct exec_t { struct exec_t {
bool err = false; bool err = false;

View File

@ -41,6 +41,21 @@ pub fn fmt_to_buf(buf: &mut [u8], args: Arguments) -> usize {
} }
} }
#[macro_export]
macro_rules! bfmt {
($buf:expr, $($args:tt)*) => {
$crate::fmt_to_buf($buf, format_args!($($args)*));
};
}
#[macro_export]
macro_rules! bfmt_cstr {
($buf:expr, $($args:tt)*) => {{
let len = $crate::fmt_to_buf($buf, format_args!($($args)*));
unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(&$buf[..(len + 1)]) }
}};
}
// The cstr! macro is inspired by https://github.com/Nugine/const-str // The cstr! macro is inspired by https://github.com/Nugine/const-str
macro_rules! const_assert { macro_rules! const_assert {
@ -88,19 +103,12 @@ macro_rules! cstr {
($s:literal) => {{ ($s:literal) => {{
const LEN: usize = $crate::ToCStr($s).eval_len(); const LEN: usize = $crate::ToCStr($s).eval_len();
const BUF: [u8; LEN] = $crate::ToCStr($s).eval_bytes(); const BUF: [u8; LEN] = $crate::ToCStr($s).eval_bytes();
unsafe { CStr::from_bytes_with_nul_unchecked(&BUF) } unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(&BUF) }
}}; }};
} }
#[macro_export] pub fn ptr_to_str<'a, T>(ptr: *const T) -> &'a str {
macro_rules! r_cstr { unsafe { CStr::from_ptr(ptr.cast()) }.to_str().unwrap_or("")
($s:literal) => {
cstr!($s).as_ptr()
};
}
pub unsafe fn ptr_to_str<'a, T>(ptr: *const T) -> &'a str {
CStr::from_ptr(ptr.cast()).to_str().unwrap_or("")
} }
pub fn errno() -> &'static mut i32 { pub fn errno() -> &'static mut i32 {

View File

@ -1,119 +0,0 @@
#include <sched.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/mman.h>
#include <sys/sendfile.h>
#include <sys/ptrace.h>
#include <sys/inotify.h>
#include <base.hpp>
using namespace std;
ssize_t xwrite(int fd, const void *buf, size_t count) {
return rust::xwrite(fd, rust::Slice(static_cast<const uint8_t *>(buf), count));
}
ssize_t xread(int fd, void *buf, size_t count) {
return rust::xread(fd, rust::Slice(static_cast<uint8_t *>(buf), count));
}
ssize_t xxread(int fd, void *buf, size_t count) {
return rust::xxread(fd, rust::Slice(static_cast<uint8_t *>(buf), count));
}
dirent *xreaddir(DIR *dirp) {
errno = 0;
for (dirent *e;;) {
e = readdir(dirp);
if (e == nullptr) {
if (errno)
PLOGE("readdir");
return nullptr;
} else if (e->d_name == "."sv || e->d_name == ".."sv) {
// Filter . and .. for users
continue;
}
return e;
}
}
ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz) {
ssize_t ret = readlink(pathname, buf, bufsiz);
if (ret < 0) {
PLOGE("readlink %s", pathname);
} else {
buf[ret] = '\0';
}
return ret;
}
ssize_t xreadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) {
// readlinkat() may fail on x86 platform, returning random value
// instead of number of bytes placed in buf (length of link)
#if defined(__i386__) || defined(__x86_64__)
memset(buf, 0, bufsiz);
ssize_t ret = readlinkat(dirfd, pathname, buf, bufsiz);
if (ret < 0) {
PLOGE("readlinkat %s", pathname);
}
return ret;
#else
ssize_t ret = readlinkat(dirfd, pathname, buf, bufsiz);
if (ret < 0) {
PLOGE("readlinkat %s", pathname);
} else {
buf[ret] = '\0';
}
return ret;
#endif
}
int xmkdirs(const char *pathname, mode_t mode) {
int ret = mkdirs(pathname, mode);
if (ret < 0) {
PLOGE("mkdirs %s", pathname);
}
return ret;
}
void *xmmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset) {
void *ret = mmap(addr, length, prot, flags, fd, offset);
if (ret == MAP_FAILED) {
PLOGE("mmap");
return nullptr;
}
return ret;
}
ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count) {
ssize_t ret = sendfile(out_fd, in_fd, offset, count);
if (ret < 0) {
PLOGE("sendfile");
}
return ret;
}
int xpoll(struct pollfd *fds, nfds_t nfds, int timeout) {
int ret = poll(fds, nfds, timeout);
if (ret < 0) {
PLOGE("poll");
}
return ret;
}
char *xrealpath(const char *path, char *resolved_path) {
char buf[PATH_MAX];
char *ret = realpath(path, buf);
if (ret == nullptr) {
PLOGE("xrealpath");
} else {
strcpy(resolved_path, buf);
}
return ret;
}

View File

@ -57,8 +57,8 @@ int xmkdirat(int dirfd, const char *pathname, mode_t mode);
void *xmmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); void *xmmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count); ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count);
pid_t xfork(); pid_t xfork();
int xpoll(struct pollfd *fds, nfds_t nfds, int timeout); int xpoll(pollfd *fds, nfds_t nfds, int timeout);
char *xrealpath(const char *path, char *resolved_path); ssize_t xcanonical_path(const char *path, char *buf, size_t bufsiz);
int xmknod(const char *pathname, mode_t mode, dev_t dev); int xmknod(const char *pathname, mode_t mode, dev_t dev);
} // extern "C" } // extern "C"

View File

@ -1,11 +1,100 @@
use std::ffi::CStr; use std::ffi::CStr;
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::ptr;
use libc::{ use libc::{
c_char, c_uint, c_ulong, c_void, dev_t, mode_t, sockaddr, socklen_t, ssize_t, SYS_dup3, c_char, c_uint, c_ulong, c_void, dev_t, mode_t, nfds_t, off_t, pollfd, sockaddr, socklen_t,
ssize_t, SYS_dup3,
}; };
use crate::{errno, error, perror, ptr_to_str}; use crate::{canonical_path, cstr, errno, error, mkdirs, perror, ptr_to_str, readlink};
mod unsafe_impl {
use std::ffi::CStr;
use std::os::unix::io::RawFd;
use std::slice;
use cfg_if::cfg_if;
use libc::{c_char, nfds_t, off_t, pollfd};
use crate::{perror, ptr_to_str};
#[no_mangle]
unsafe extern "C" fn xwrite(fd: RawFd, buf: *const u8, bufsz: usize) -> isize {
super::xwrite(fd, slice::from_raw_parts(buf, bufsz))
}
#[no_mangle]
unsafe extern "C" fn xread(fd: RawFd, buf: *mut u8, bufsz: usize) -> isize {
super::xread(fd, slice::from_raw_parts_mut(buf, bufsz))
}
#[no_mangle]
unsafe extern "C" fn xxread(fd: RawFd, buf: *mut u8, bufsz: usize) -> isize {
super::xxread(fd, slice::from_raw_parts_mut(buf, bufsz))
}
#[no_mangle]
unsafe extern "C" fn xcanonical_path(path: *const c_char, buf: *mut u8, bufsz: usize) -> isize {
super::xcanonical_path(CStr::from_ptr(path), slice::from_raw_parts_mut(buf, bufsz))
}
#[no_mangle]
unsafe extern "C" fn xreadlink(path: *const c_char, buf: *mut u8, bufsz: usize) -> isize {
super::xreadlink(CStr::from_ptr(path), slice::from_raw_parts_mut(buf, bufsz))
}
#[no_mangle]
pub unsafe extern "C" fn xreadlinkat(
dirfd: RawFd,
path: *const c_char,
buf: *mut u8,
bufsz: usize,
) -> isize {
// readlinkat() may fail on x86 platform, returning random value
// instead of number of bytes placed in buf (length of link)
cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
libc::memset(buf.cast(), 0, bufsz);
let r = libc::readlinkat(dirfd, path, buf.cast(), bufsz - 1);
if r < 0 {
perror!("readlinkat {}", ptr_to_str(path))
}
} else {
let r = libc::readlinkat(dirfd, path, buf.cast(), bufsz - 1);
if r < 0 {
perror!("readlinkat {}", ptr_to_str(path))
} else {
*buf.offset(r) = b'\0';
}
}
}
return r;
}
#[no_mangle]
pub unsafe extern "C" fn xpoll(fds: *mut pollfd, nfds: nfds_t, timeout: i32) -> i32 {
let r = libc::poll(fds, nfds, timeout);
if r < 0 {
perror!("poll");
}
return r;
}
#[no_mangle]
pub unsafe extern "C" fn xsendfile(
out_fd: RawFd,
in_fd: RawFd,
offset: *mut off_t,
count: usize,
) -> isize {
let r = libc::sendfile(out_fd, in_fd, offset, count);
if r < 0 {
perror!("sendfile");
}
return r;
}
}
#[no_mangle] #[no_mangle]
pub extern "C" fn xfopen(path: *const c_char, mode: *const c_char) -> *mut libc::FILE { pub extern "C" fn xfopen(path: *const c_char, mode: *const c_char) -> *mut libc::FILE {
@ -194,6 +283,29 @@ pub extern "C" fn xfdopendir(fd: RawFd) -> *mut libc::DIR {
} }
} }
#[no_mangle]
pub extern "C" fn xreaddir(dirp: *mut libc::DIR) -> *mut libc::dirent {
#[allow(unused_unsafe)]
unsafe {
*errno() = 0;
loop {
let e = libc::readdir(dirp);
if e.is_null() {
if *errno() != 0 {
perror!("readdir")
}
} else {
// Filter out . and ..
let s = CStr::from_ptr((*e).d_name.as_ptr());
if s == cstr!(".") || s == cstr!("..") {
continue;
}
};
return e;
}
}
}
#[no_mangle] #[no_mangle]
pub extern "C" fn xsetsid() -> i32 { pub extern "C" fn xsetsid() -> i32 {
unsafe { unsafe {
@ -386,21 +498,15 @@ pub extern "C" fn xdup3(oldfd: RawFd, newfd: RawFd, flags: i32) -> RawFd {
} }
pub fn xreadlink(path: &CStr, data: &mut [u8]) -> isize { pub fn xreadlink(path: &CStr, data: &mut [u8]) -> isize {
mod e { let r = readlink(path, data);
extern "C" { if r < 0 {
pub fn xreadlink(path: *const u8, buf: *mut u8, bufsz: usize) -> isize; perror!("readlink {}", path.to_str().unwrap_or(""))
} }
} return r;
unsafe { e::xreadlink(path.as_ptr().cast(), data.as_mut_ptr(), data.len()) }
} }
pub fn xreadlinkat(dirfd: RawFd, path: &CStr, data: &mut [u8]) -> isize { pub fn xreadlinkat(dirfd: RawFd, path: &CStr, data: &mut [u8]) -> isize {
mod e { unsafe { unsafe_impl::xreadlinkat(dirfd, path.as_ptr(), data.as_mut_ptr(), data.len()) }
extern "C" {
pub fn xreadlinkat(dirfd: i32, path: *const u8, buf: *mut u8, bufsz: usize) -> isize;
}
}
unsafe { e::xreadlinkat(dirfd, path.as_ptr().cast(), data.as_mut_ptr(), data.len()) }
} }
#[no_mangle] #[no_mangle]
@ -507,6 +613,15 @@ pub extern "C" fn xmkdir(path: *const c_char, mode: mode_t) -> i32 {
} }
} }
#[no_mangle]
pub extern "C" fn xmkdirs(path: *const c_char, mode: mode_t) -> i32 {
let r = mkdirs(path, mode);
if r < 0 {
perror!("mkdirs {}", ptr_to_str(path));
}
return r;
}
#[no_mangle] #[no_mangle]
pub extern "C" fn xmkdirat(dirfd: RawFd, path: *const c_char, mode: mode_t) -> i32 { pub extern "C" fn xmkdirat(dirfd: RawFd, path: *const c_char, mode: mode_t) -> i32 {
unsafe { unsafe {
@ -518,6 +633,32 @@ pub extern "C" fn xmkdirat(dirfd: RawFd, path: *const c_char, mode: mode_t) -> i
} }
} }
pub fn xsendfile(out_fd: RawFd, in_fd: RawFd, offset: Option<&mut off_t>, count: usize) -> isize {
unsafe {
let p = offset.map_or(ptr::null_mut(), |it| it);
unsafe_impl::xsendfile(out_fd, in_fd, p, count)
}
}
#[no_mangle]
pub extern "C" fn xmmap(
addr: *mut c_void,
len: usize,
prot: i32,
flags: i32,
fd: RawFd,
offset: off_t,
) -> *mut c_void {
unsafe {
let r = libc::mmap(addr, len, prot, flags, fd, offset);
if r == libc::MAP_FAILED {
perror!("mmap");
return ptr::null_mut();
}
return r;
}
}
#[no_mangle] #[no_mangle]
pub extern "C" fn xfork() -> i32 { pub extern "C" fn xfork() -> i32 {
unsafe { unsafe {
@ -529,6 +670,18 @@ pub extern "C" fn xfork() -> i32 {
} }
} }
pub fn xpoll(fds: &mut [pollfd], timeout: i32) -> i32 {
unsafe { unsafe_impl::xpoll(fds.as_mut_ptr(), fds.len() as nfds_t, timeout) }
}
pub fn xcanonical_path(path: &CStr, buf: &mut [u8]) -> isize {
let r = canonical_path(path, buf);
if r < 0 {
perror!("canonical_path {}", path.to_str().unwrap_or(""))
}
return r;
}
#[no_mangle] #[no_mangle]
pub extern "C" fn xmknod(pathname: *const c_char, mode: mode_t, dev: dev_t) -> i32 { pub extern "C" fn xmknod(pathname: *const c_char, mode: mode_t, dev: dev_t) -> i32 {
unsafe { unsafe {

View File

@ -124,7 +124,7 @@ extern "C" void klog_write(const char *msg, int len) {
static int klog_with_rs(LogLevel level, const char *fmt, va_list ap) { static int klog_with_rs(LogLevel level, const char *fmt, va_list ap) {
char buf[4096]; char buf[4096];
strlcpy(buf, "magiskinit: ", sizeof(buf)); strscpy(buf, "magiskinit: ", sizeof(buf));
int len = vssprintf(buf + 12, sizeof(buf) - 12, fmt, ap) + 12; int len = vssprintf(buf + 12, sizeof(buf) - 12, fmt, ap) + 12;
log_with_rs(level, rust::Str(buf, len)); log_with_rs(level, rust::Str(buf, len));
return len; return len;
@ -174,10 +174,10 @@ void BootConfig::set(const kv_pairs &kv) {
LOGW("Skip invalid androidboot.slot_suffix=[normal]\n"); LOGW("Skip invalid androidboot.slot_suffix=[normal]\n");
continue; continue;
} }
strlcpy(slot, value.data(), sizeof(slot)); strscpy(slot, value.data(), sizeof(slot));
} else if (key == "androidboot.slot") { } else if (key == "androidboot.slot") {
slot[0] = '_'; slot[0] = '_';
strlcpy(slot + 1, value.data(), sizeof(slot) - 1); strscpy(slot + 1, value.data(), sizeof(slot) - 1);
} else if (key == "skip_initramfs") { } else if (key == "skip_initramfs") {
skip_initramfs = true; skip_initramfs = true;
} else if (key == "androidboot.force_normal_boot") { } else if (key == "androidboot.force_normal_boot") {
@ -185,13 +185,13 @@ void BootConfig::set(const kv_pairs &kv) {
} else if (key == "rootwait") { } else if (key == "rootwait") {
rootwait = true; rootwait = true;
} else if (key == "androidboot.android_dt_dir") { } else if (key == "androidboot.android_dt_dir") {
strlcpy(dt_dir, value.data(), sizeof(dt_dir)); strscpy(dt_dir, value.data(), sizeof(dt_dir));
} else if (key == "androidboot.hardware") { } else if (key == "androidboot.hardware") {
strlcpy(hardware, value.data(), sizeof(hardware)); strscpy(hardware, value.data(), sizeof(hardware));
} else if (key == "androidboot.hardware.platform") { } else if (key == "androidboot.hardware.platform") {
strlcpy(hardware_plat, value.data(), sizeof(hardware_plat)); strscpy(hardware_plat, value.data(), sizeof(hardware_plat));
} else if (key == "androidboot.fstab_suffix") { } else if (key == "androidboot.fstab_suffix") {
strlcpy(fstab_suffix, value.data(), sizeof(fstab_suffix)); strscpy(fstab_suffix, value.data(), sizeof(fstab_suffix));
} else if (key == "qemu") { } else if (key == "qemu") {
emulator = true; emulator = true;
} }
@ -216,7 +216,7 @@ if (access(file_name, R_OK) == 0) { \
string data = full_read(file_name); \ string data = full_read(file_name); \
if (!data.empty()) { \ if (!data.empty()) { \
data.pop_back(); \ data.pop_back(); \
strlcpy(config->key, data.data(), sizeof(config->key)); \ strscpy(config->key, data.data(), sizeof(config->key)); \
} \ } \
} }
@ -245,7 +245,7 @@ void load_kernel_info(BootConfig *config) {
}); });
if (config->dt_dir[0] == '\0') if (config->dt_dir[0] == '\0')
strlcpy(config->dt_dir, DEFAULT_DT_DIR, sizeof(config->dt_dir)); strscpy(config->dt_dir, DEFAULT_DT_DIR, sizeof(config->dt_dir));
char file_name[128]; char file_name[128];
read_dt("fstab_suffix", fstab_suffix) read_dt("fstab_suffix", fstab_suffix)

View File

@ -118,8 +118,8 @@ static void switch_root(const string &path) {
void MagiskInit::mount_rules_dir() { void MagiskInit::mount_rules_dir() {
char path[128]; char path[128];
xrealpath(BLOCKDIR, blk_info.block_dev); xcanonical_path(BLOCKDIR, blk_info.block_dev, sizeof(blk_info.block_dev));
xrealpath(MIRRDIR, path); xcanonical_path(MIRRDIR, path, sizeof(path));
char *b = blk_info.block_dev + strlen(blk_info.block_dev); char *b = blk_info.block_dev + strlen(blk_info.block_dev);
char *p = path + strlen(path); char *p = path + strlen(path);
@ -206,7 +206,7 @@ success:
// Create symlink with relative path // Create symlink with relative path
char s[128]; char s[128];
s[0] = '.'; s[0] = '.';
strlcpy(s + 1, rel + sizeof(MIRRDIR) - 1, sizeof(s) - 1); strscpy(s + 1, rel + sizeof(MIRRDIR) - 1, sizeof(s) - 1);
xsymlink(s, path); xsymlink(s, path);
} else { } else {
xsymlink(custom_rules_dir.data(), path); xsymlink(custom_rules_dir.data(), path);

View File

@ -123,7 +123,7 @@ static void exec_cmd(const char *action, vector<Extra> &data,
ssprintf(exe, sizeof(exe), "/proc/self/fd/%d", app_process_32); ssprintf(exe, sizeof(exe), "/proc/self/fd/%d", app_process_32);
#endif #endif
} else { } else {
strlcpy(exe, "/system/bin/app_process", sizeof(exe)); strscpy(exe, "/system/bin/app_process", sizeof(exe));
} }
// First try content provider call method // First try content provider call method
@ -158,7 +158,7 @@ static void exec_cmd(const char *action, vector<Extra> &data,
}; };
// Then try start activity without package name // Then try start activity without package name
strlcpy(target, info->mgr_pkg.data(), sizeof(target)); strscpy(target, info->mgr_pkg.data(), sizeof(target));
exec_command_sync(exec); exec_command_sync(exec);
if (check_no_error(exec.fd)) if (check_no_error(exec.fd))
return; return;

View File

@ -142,7 +142,7 @@ void prune_su_access() {
vector<bool> app_no_list = get_app_no_list(); vector<bool> app_no_list = get_app_no_list();
vector<int> rm_uids; vector<int> rm_uids;
char query[256], *err; char query[256], *err;
strlcpy(query, "SELECT uid FROM policies", sizeof(query)); strscpy(query, "SELECT uid FROM policies", sizeof(query));
err = db_exec(query, [&](db_row &row) -> bool { err = db_exec(query, [&](db_row &row) -> bool {
int uid = parse_int(row["uid"]); int uid = parse_int(row["uid"]);
int app_id = to_app_id(uid); int app_id = to_app_id(uid);
@ -412,7 +412,7 @@ void su_daemon_handler(int client, const sock_cred *cred) {
char path[32]; char path[32];
ssprintf(path, sizeof(path), "/proc/%d/cwd", ctx.pid); ssprintf(path, sizeof(path), "/proc/%d/cwd", ctx.pid);
char cwd[PATH_MAX]; char cwd[PATH_MAX];
if (realpath(path, cwd)) if (canonical_path(path, cwd, sizeof(cwd)))
chdir(cwd); chdir(cwd);
ssprintf(path, sizeof(path), "/proc/%d/environ", ctx.pid); ssprintf(path, sizeof(path), "/proc/%d/environ", ctx.pid);
auto env = full_read(path); auto env = full_read(path);