feature: add devpts fd wrapper (#21)

This feature is intended to resolve devpts problem.
This commit is contained in:
5ec1cff
2025-11-06 23:29:58 +08:00
committed by ShirkNeko
parent f86c71efc5
commit 826661dffb
15 changed files with 526 additions and 22 deletions

View File

@@ -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(())