feature: add devpts fd wrapper (#21)
This feature is intended to resolve devpts problem.
This commit is contained in:
@@ -40,3 +40,5 @@ pub const BACKUP_FILENAME: &str = "stock_image.sha1";
|
||||
|
||||
pub const NO_TMPFS_PATH: &str = concatcp!(WORKING_DIR, ".notmpfs");
|
||||
pub const NO_MOUNT_PATH: &str = concatcp!(WORKING_DIR, ".nomount");
|
||||
|
||||
pub const NO_FD_WRAPPER_PATH: &str = concatcp!(WORKING_DIR, ".nofdwrapper");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::fs;
|
||||
use std::os::fd::OwnedFd;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use std::os::fd::RawFd;
|
||||
use std::sync::OnceLock;
|
||||
@@ -15,6 +16,7 @@ const KSU_IOCTL_SET_SEPOLICY: u32 = 0xc0004b04; // _IOC(_IOC_READ|_IOC_WRITE, 'K
|
||||
const KSU_IOCTL_CHECK_SAFEMODE: u32 = 0x80004b05; // _IOC(_IOC_READ, 'K', 5, 0)
|
||||
const KSU_IOCTL_GET_FEATURE: u32 = 0xc0004b0d; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 13, 0)
|
||||
const KSU_IOCTL_SET_FEATURE: u32 = 0x40004b0e; // _IOC(_IOC_WRITE, 'K', 14, 0)
|
||||
const KSU_IOCTL_GET_WRAPPER_FD: u32 = 0x00006f10; // _IOC(_IOC_NONE, 'K', 10000, 0)
|
||||
#[allow(dead_code)]
|
||||
const KSU_IOCTL_KPM: u32 = 0xc0004bc8; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 200, 0)
|
||||
|
||||
@@ -58,6 +60,13 @@ struct SetFeatureCmd {
|
||||
value: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
struct GetWrapperFdCmd {
|
||||
fd: i32,
|
||||
flags: u32,
|
||||
}
|
||||
|
||||
// Global driver fd cache
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
static DRIVER_FD: OnceLock<RawFd> = OnceLock::new();
|
||||
@@ -223,6 +232,12 @@ pub fn set_feature(feature_id: u32, value: u64) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_wrapped_fd(fd: RawFd) -> std::io::Result<RawFd> {
|
||||
let mut cmd = GetWrapperFdCmd { fd, flags: 0 };
|
||||
let result = ksuctl(KSU_IOCTL_GET_WRAPPER_FD, &mut cmd as *mut _)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
#[allow(dead_code)]
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
use crate::{
|
||||
defs,
|
||||
utils::{self, umask},
|
||||
};
|
||||
use anyhow::{Context, Ok, Result, bail};
|
||||
use getopts::Options;
|
||||
use libc::c_int;
|
||||
use log::{debug, error, info};
|
||||
use procfs::process::FDTarget::Path;
|
||||
use std::fs::File;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::{env, ffi::CStr, path::PathBuf, process::Command};
|
||||
|
||||
use anyhow::{Ok, Result};
|
||||
use getopts::Options;
|
||||
use crate::defs::NO_FD_WRAPPER_PATH;
|
||||
use crate::ksucalls::get_wrapped_fd;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use rustix::{
|
||||
process::getuid,
|
||||
thread::{Gid, Uid, set_thread_res_gid, set_thread_res_uid},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
defs,
|
||||
utils::{self, umask},
|
||||
};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn grant_root(global_mnt: bool) -> Result<()> {
|
||||
crate::ksucalls::grant_root()?;
|
||||
@@ -62,6 +68,29 @@ fn set_identity(uid: u32, gid: u32, groups: &[u32]) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android"))]
|
||||
fn wrap_tty(fd: c_int) {
|
||||
let inner_fn = move || -> Result<()> {
|
||||
if unsafe { libc::isatty(fd) != 1 } {
|
||||
debug!("not a tty: {fd}");
|
||||
return Ok(());
|
||||
}
|
||||
let new_fd = get_wrapped_fd(fd).context("get_wrapped_fd")?;
|
||||
if unsafe { libc::dup2(new_fd, fd) } == -1 {
|
||||
bail!("dup {new_fd} -> {fd} errno: {}", unsafe {
|
||||
*libc::__errno()
|
||||
});
|
||||
} else {
|
||||
unsafe { libc::close(new_fd) };
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = inner_fn() {
|
||||
error!("wrap tty {fd}: {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
pub fn root_shell() -> Result<()> {
|
||||
unimplemented!()
|
||||
@@ -122,6 +151,8 @@ pub fn root_shell() -> Result<()> {
|
||||
"Specify a supplementary group. The first specified supplementary group is also used as a primary group if the option -g is not specified.",
|
||||
"GROUP",
|
||||
);
|
||||
opts.optflag("w", "wrapper", "Use mksu fd wrapper");
|
||||
opts.optflag("W", "no-wrapper", "Don't use mksu fd wrapper");
|
||||
|
||||
// Replace -cn with -z, -mm with -M for supporting getopt_long
|
||||
let args = args
|
||||
@@ -165,6 +196,11 @@ pub fn root_shell() -> Result<()> {
|
||||
let mut is_login = matches.opt_present("l");
|
||||
let preserve_env = matches.opt_present("p");
|
||||
let mount_master = matches.opt_present("M");
|
||||
let use_fd_wrapper = (!std::path::Path::new(NO_FD_WRAPPER_PATH).exists()
|
||||
|| matches.opt_present("w"))
|
||||
&& !matches.opt_present("W");
|
||||
|
||||
info!("use_fd_wrapper={use_fd_wrapper}");
|
||||
|
||||
let groups = matches
|
||||
.opt_strs("G")
|
||||
@@ -263,6 +299,13 @@ pub fn root_shell() -> Result<()> {
|
||||
let _ = utils::switch_mnt_ns(1);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android"))]
|
||||
if use_fd_wrapper {
|
||||
wrap_tty(0);
|
||||
wrap_tty(1);
|
||||
wrap_tty(2);
|
||||
}
|
||||
|
||||
set_identity(uid, gid, &groups);
|
||||
|
||||
Result::Ok(())
|
||||
|
||||
Reference in New Issue
Block a user