@@ -1,6 +1,6 @@
|
|||||||
use anyhow::{Ok, Result};
|
use anyhow::{Ok, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
use android_logger::Config;
|
use android_logger::Config;
|
||||||
@@ -283,7 +283,7 @@ pub fn run() -> Result<()> {
|
|||||||
|
|
||||||
// the kernel executes su with argv[0] = "su" and replace it with us
|
// the kernel executes su with argv[0] = "su" and replace it with us
|
||||||
let arg0 = std::env::args().next().unwrap_or_default();
|
let arg0 = std::env::args().next().unwrap_or_default();
|
||||||
if Path::new(&arg0).file_name().and_then(|f| f.to_str()) == Some("su") {
|
if arg0 == "su" || arg0 == "/system/bin/su" {
|
||||||
return crate::su::root_shell();
|
return crate::su::root_shell();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,5 +43,3 @@ pub const VERSION_NAME: &str = include_str!(concat!(env!("OUT_DIR"), "/VERSION_N
|
|||||||
pub const KSU_BACKUP_DIR: &str = WORKING_DIR;
|
pub const KSU_BACKUP_DIR: &str = WORKING_DIR;
|
||||||
pub const KSU_BACKUP_FILE_PREFIX: &str = "ksu_backup_";
|
pub const KSU_BACKUP_FILE_PREFIX: &str = "ksu_backup_";
|
||||||
pub const BACKUP_FILENAME: &str = "stock_image.sha1";
|
pub const BACKUP_FILENAME: &str = "stock_image.sha1";
|
||||||
|
|
||||||
pub const PTS_NAME: &str = "pts";
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use anyhow::{bail, Context, Result};
|
|||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
use crate::defs::PTS_NAME;
|
|
||||||
use crate::module::prune_modules;
|
use crate::module::prune_modules;
|
||||||
use crate::{
|
use crate::{
|
||||||
assets, defs, ksucalls, mount, restorecon,
|
assets, defs, ksucalls, mount, restorecon,
|
||||||
@@ -194,11 +193,6 @@ pub fn on_post_data_fs() -> Result<()> {
|
|||||||
// mount temp dir
|
// mount temp dir
|
||||||
if let Err(e) = mount::mount_tmpfs(utils::get_tmp_path()) {
|
if let Err(e) = mount::mount_tmpfs(utils::get_tmp_path()) {
|
||||||
warn!("do temp dir mount failed: {}", e);
|
warn!("do temp dir mount failed: {}", e);
|
||||||
} else {
|
|
||||||
let pts_dir = format!("{}/{PTS_NAME}", utils::get_tmp_path());
|
|
||||||
if let Err(e) = mount::mount_devpts(pts_dir) {
|
|
||||||
warn!("do devpts mount failed: {}", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec modules post-fs-data scripts
|
// exec modules post-fs-data scripts
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ mod ksucalls;
|
|||||||
mod module;
|
mod module;
|
||||||
mod mount;
|
mod mount;
|
||||||
mod profile;
|
mod profile;
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
||||||
mod pty;
|
|
||||||
mod restorecon;
|
mod restorecon;
|
||||||
mod sepolicy;
|
mod sepolicy;
|
||||||
mod su;
|
mod su;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use anyhow::{anyhow, bail, Ok, Result};
|
use anyhow::{anyhow, bail, Ok, Result};
|
||||||
use std::fs::create_dir;
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
@@ -182,19 +181,6 @@ pub fn mount_tmpfs(dest: impl AsRef<Path>) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
||||||
pub fn mount_devpts(dest: impl AsRef<Path>) -> Result<()> {
|
|
||||||
create_dir(dest.as_ref())?;
|
|
||||||
mount(
|
|
||||||
KSU_OVERLAY_SOURCE,
|
|
||||||
dest.as_ref(),
|
|
||||||
"devpts",
|
|
||||||
MountFlags::empty(),
|
|
||||||
"newinstance",
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
pub fn bind_mount(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<()> {
|
pub fn bind_mount(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<()> {
|
||||||
info!(
|
info!(
|
||||||
@@ -339,8 +325,3 @@ pub fn mount_overlay(
|
|||||||
pub fn mount_tmpfs(_dest: impl AsRef<Path>) -> Result<()> {
|
pub fn mount_tmpfs(_dest: impl AsRef<Path>) -> Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
|
||||||
pub fn mount_devpts(_dest: impl AsRef<Path>) -> Result<()> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,195 +0,0 @@
|
|||||||
use std::ffi::c_int;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{stderr, stdin, stdout, Error, ErrorKind, Read, Write};
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
use std::os::fd::{AsFd, AsRawFd, OwnedFd, RawFd};
|
|
||||||
use std::process::exit;
|
|
||||||
use std::ptr::null_mut;
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
use anyhow::{bail, Ok, Result};
|
|
||||||
use libc::{
|
|
||||||
fork, pthread_sigmask, sigaddset, sigemptyset, sigset_t, sigwait, waitpid, winsize, SIGWINCH,
|
|
||||||
SIG_BLOCK, SIG_UNBLOCK, TIOCGWINSZ, TIOCSWINSZ,
|
|
||||||
};
|
|
||||||
use rustix::fs::{open, Mode, OFlags};
|
|
||||||
use rustix::io::dup;
|
|
||||||
use rustix::ioctl::{ioctl, Getter, ReadOpcode};
|
|
||||||
use rustix::process::setsid;
|
|
||||||
use rustix::pty::{grantpt, unlockpt};
|
|
||||||
use rustix::stdio::{dup2_stderr, dup2_stdin, dup2_stdout};
|
|
||||||
use rustix::termios::{isatty, tcgetattr, tcsetattr, OptionalActions, Termios};
|
|
||||||
|
|
||||||
use crate::defs::PTS_NAME;
|
|
||||||
use crate::utils::get_tmp_path;
|
|
||||||
|
|
||||||
// https://github.com/topjohnwu/Magisk/blob/5627053b7481618adfdf8fa3569b48275589915b/native/src/core/su/pts.cpp
|
|
||||||
|
|
||||||
fn get_pty_num<F: AsFd>(fd: F) -> Result<u32> {
|
|
||||||
Ok(unsafe {
|
|
||||||
let tiocgptn = Getter::<ReadOpcode<b'T', 0x30, u32>, u32>::new();
|
|
||||||
ioctl(fd, tiocgptn)?
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
static mut OLD_STDIN: Option<Termios> = None;
|
|
||||||
|
|
||||||
fn watch_sigwinch_async(slave: RawFd) {
|
|
||||||
let mut winch = MaybeUninit::<sigset_t>::uninit();
|
|
||||||
unsafe {
|
|
||||||
sigemptyset(winch.as_mut_ptr());
|
|
||||||
sigaddset(winch.as_mut_ptr(), SIGWINCH);
|
|
||||||
pthread_sigmask(SIG_BLOCK, winch.as_mut_ptr(), null_mut());
|
|
||||||
}
|
|
||||||
|
|
||||||
thread::spawn(move || unsafe {
|
|
||||||
let mut winch = MaybeUninit::<sigset_t>::uninit();
|
|
||||||
sigemptyset(winch.as_mut_ptr());
|
|
||||||
sigaddset(winch.as_mut_ptr(), SIGWINCH);
|
|
||||||
pthread_sigmask(SIG_UNBLOCK, winch.as_mut_ptr(), null_mut());
|
|
||||||
let mut sig: c_int = 0;
|
|
||||||
loop {
|
|
||||||
let mut w = MaybeUninit::<winsize>::uninit();
|
|
||||||
if libc::ioctl(1, TIOCGWINSZ, w.as_mut_ptr()) < 0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
libc::ioctl(slave, TIOCSWINSZ, w.as_mut_ptr());
|
|
||||||
if sigwait(winch.as_mut_ptr(), &mut sig) != 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_stdin_raw() {
|
|
||||||
let mut termios = match tcgetattr(stdin()) {
|
|
||||||
Result::Ok(termios) => {
|
|
||||||
unsafe {
|
|
||||||
OLD_STDIN = Some(termios.clone());
|
|
||||||
}
|
|
||||||
termios
|
|
||||||
}
|
|
||||||
Err(_) => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
termios.make_raw();
|
|
||||||
|
|
||||||
if tcsetattr(stdin(), OptionalActions::Flush, &termios).is_err() {
|
|
||||||
let _ = tcsetattr(stdin(), OptionalActions::Drain, &termios);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn restore_stdin() {
|
|
||||||
let Some(termios) = (unsafe { OLD_STDIN.take() }) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if tcsetattr(stdin(), OptionalActions::Flush, &termios).is_err() {
|
|
||||||
let _ = tcsetattr(stdin(), OptionalActions::Drain, &termios);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pump<R: Read, W: Write>(mut from: R, mut to: W) {
|
|
||||||
let mut buf = [0u8; 4096];
|
|
||||||
loop {
|
|
||||||
match from.read(&mut buf) {
|
|
||||||
Result::Ok(len) => {
|
|
||||||
if len == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if to.write_all(&buf[0..len]).is_err() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if to.flush().is_err() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pump_stdin_async(mut ptmx: File) {
|
|
||||||
set_stdin_raw();
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
let mut stdin = stdin();
|
|
||||||
pump(&mut stdin, &mut ptmx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pump_stdout_blocking(mut ptmx: File) {
|
|
||||||
let mut stdout = stdout();
|
|
||||||
pump(&mut ptmx, &mut stdout);
|
|
||||||
|
|
||||||
restore_stdin();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_transfer(ptmx: OwnedFd) -> Result<()> {
|
|
||||||
let pid = unsafe { fork() };
|
|
||||||
match pid {
|
|
||||||
d if d < 0 => bail!("fork"),
|
|
||||||
0 => return Ok(()),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ptmx_r = ptmx;
|
|
||||||
let ptmx_w = dup(&ptmx_r).unwrap();
|
|
||||||
|
|
||||||
let ptmx_r = File::from(ptmx_r);
|
|
||||||
let ptmx_w = File::from(ptmx_w);
|
|
||||||
|
|
||||||
watch_sigwinch_async(ptmx_w.as_raw_fd());
|
|
||||||
pump_stdin_async(ptmx_r);
|
|
||||||
pump_stdout_blocking(ptmx_w);
|
|
||||||
|
|
||||||
let mut status: c_int = -1;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
loop {
|
|
||||||
if waitpid(pid, &mut status, 0) == -1 {
|
|
||||||
let last_os_error = Error::last_os_error();
|
|
||||||
if last_os_error.kind() != ErrorKind::Interrupted {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(status)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn prepare_pty() -> Result<()> {
|
|
||||||
let tty_in = isatty(stdin());
|
|
||||||
let tty_out = isatty(stdout());
|
|
||||||
let tty_err = isatty(stderr());
|
|
||||||
if !tty_in && !tty_out && !tty_err {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut pts_path = format!("{}/{}", get_tmp_path(), PTS_NAME);
|
|
||||||
if !std::path::Path::new(&pts_path).exists() {
|
|
||||||
pts_path = "/dev/pts".to_string();
|
|
||||||
}
|
|
||||||
let ptmx_path = format!("{}/ptmx", pts_path);
|
|
||||||
let ptmx_fd = open(ptmx_path, OFlags::RDWR, Mode::empty())?;
|
|
||||||
grantpt(&ptmx_fd)?;
|
|
||||||
unlockpt(&ptmx_fd)?;
|
|
||||||
let pty_num = get_pty_num(&ptmx_fd)?;
|
|
||||||
create_transfer(ptmx_fd)?;
|
|
||||||
setsid()?;
|
|
||||||
let pty_fd = open(format!("{pts_path}/{pty_num}"), OFlags::RDWR, Mode::empty())?;
|
|
||||||
if tty_in {
|
|
||||||
dup2_stdin(&pty_fd)?;
|
|
||||||
}
|
|
||||||
if tty_out {
|
|
||||||
dup2_stdout(&pty_fd)?;
|
|
||||||
}
|
|
||||||
if tty_err {
|
|
||||||
dup2_stderr(&pty_fd)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -11,8 +11,6 @@ use crate::{
|
|||||||
utils::{self, umask},
|
utils::{self, umask},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
||||||
use crate::pty::prepare_pty;
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
use rustix::{
|
use rustix::{
|
||||||
process::getuid,
|
process::getuid,
|
||||||
@@ -140,7 +138,6 @@ 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.",
|
"Specify a supplementary group. The first specified supplementary group is also used as a primary group if the option -g is not specified.",
|
||||||
"GROUP",
|
"GROUP",
|
||||||
);
|
);
|
||||||
opts.optflag("", "no-pty", "Do not allocate a new pseudo terminal.");
|
|
||||||
|
|
||||||
// Replace -cn with -z, -mm with -M for supporting getopt_long
|
// Replace -cn with -z, -mm with -M for supporting getopt_long
|
||||||
let args = args
|
let args = args
|
||||||
@@ -268,13 +265,6 @@ pub fn root_shell() -> Result<()> {
|
|||||||
command = command.env("ENV", defs::KSURC_PATH);
|
command = command.env("ENV", defs::KSURC_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
if !matches.opt_present("no-pty") {
|
|
||||||
if let Err(e) = prepare_pty() {
|
|
||||||
log::error!("failed to prepare pty: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// escape from the current cgroup and become session leader
|
// escape from the current cgroup and become session leader
|
||||||
// WARNING!!! This cause some root shell hang forever!
|
// WARNING!!! This cause some root shell hang forever!
|
||||||
// command = command.process_group(0);
|
// command = command.process_group(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user