mirror of
https://github.com/joleuger/vuinputd.git
synced 2026-07-18 00:45:07 +00:00
Try to get root process id of the process that tries to create a input
device. This should be more stable, because the process itself more likely vanishes that its parent process.
This commit is contained in:
parent
53bc1ff153
commit
f04550d9d5
2 changed files with 122 additions and 26 deletions
|
|
@ -187,7 +187,7 @@ unsafe extern "C" fn vuinput_open(
|
|||
let fh = get_fresh_filehandle();
|
||||
let ctx = fuse_lowlevel::fuse_req_ctx(_req);
|
||||
debug!("fh {}: opened by process id {} (host view)", fh, (*ctx).pid);
|
||||
let namespaces = get_namespaces(Some((*ctx).pid));
|
||||
let namespaces = get_namespaces(Pid::Pid((*ctx).pid));
|
||||
debug!("fh {}: namespaces {}", fh, namespaces);
|
||||
// namespaces net:4026531840, uts:4026531838, ipc:4026531839, pid:4026531836, pid_for_children:4026531836, user:4026531837, mnt:4026531841, cgroup:4026531835, time:4026531834, time_for_children:4026531834
|
||||
(*_fi).fh = fh;
|
||||
|
|
@ -645,7 +645,7 @@ fn main() -> std::io::Result<()> {
|
|||
VUINPUT_STATE.set(RwLock::new(HashMap::new())).unwrap();
|
||||
VUINPUT_COUNTER.set(AtomicU64::new(3)).unwrap();
|
||||
JOB_DISPATCHER.set(Mutex::new(Dispatcher::new())).unwrap();
|
||||
SELF_NAMESPACES.set(get_namespaces(None)).unwrap();
|
||||
SELF_NAMESPACES.set(get_namespaces(Pid::SelfPid)).unwrap();
|
||||
JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(MonitorBackgroundLoop::new()));
|
||||
|
||||
info!("Starting vuinputd");
|
||||
|
|
|
|||
|
|
@ -5,16 +5,34 @@
|
|||
use log::debug;
|
||||
use nix::{
|
||||
sched::{setns, CloneFlags},
|
||||
unistd::{fork, ForkResult, Pid},
|
||||
unistd::{fork, ForkResult},
|
||||
};
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
os::fd::AsFd, path::{self, Path},
|
||||
};
|
||||
|
||||
use std::io::{self, BufRead};
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum Pid {
|
||||
SelfPid,
|
||||
Pid(i32),
|
||||
}
|
||||
|
||||
impl Pid {
|
||||
pub fn path(&self) -> String {
|
||||
match self {
|
||||
Pid::SelfPid => "/proc/self".to_string(),
|
||||
Pid::Pid(pid_no) => format!("/proc/{}",pid_no)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Namespaces {
|
||||
pub nspath: String,
|
||||
struct NamespaceInodes {
|
||||
pub net: Option<u64>,
|
||||
pub uts: Option<u64>,
|
||||
pub ipc: Option<u64>,
|
||||
|
|
@ -25,40 +43,53 @@ pub struct Namespaces {
|
|||
pub cgroup: Option<u64>,
|
||||
pub time: Option<u64>,
|
||||
pub time_for_children: Option<u64>,
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Namespaces {
|
||||
pub nspath: String,
|
||||
pub nsroot: String,
|
||||
nsinodes: NamespaceInodes,
|
||||
}
|
||||
|
||||
impl NamespaceInodes {
|
||||
pub fn equal_mnt_and_net(&self, other: &NamespaceInodes) -> bool {
|
||||
self.mnt == other.mnt && self.net == other.net
|
||||
}
|
||||
}
|
||||
|
||||
impl Namespaces {
|
||||
pub fn equal_mnt_and_net(&self, other: &Namespaces) -> bool {
|
||||
self.mnt == other.mnt && self.net == other.net
|
||||
self.nsinodes.equal_mnt_and_net(&other.nsinodes)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Namespaces {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "Namespaces:")?;
|
||||
writeln!(f, " net: {:?}", self.net)?;
|
||||
writeln!(f, " uts: {:?}", self.uts)?;
|
||||
writeln!(f, " ipc: {:?}", self.ipc)?;
|
||||
writeln!(f, " pid: {:?}", self.pid)?;
|
||||
writeln!(f, " pid_for_children: {:?}", self.pid_for_children)?;
|
||||
writeln!(f, " user: {:?}", self.user)?;
|
||||
writeln!(f, " mnt: {:?}", self.mnt)?;
|
||||
writeln!(f, " cgroup: {:?}", self.cgroup)?;
|
||||
writeln!(f, " time: {:?}", self.time)?;
|
||||
writeln!(f, " time_for_children: {:?}", self.time_for_children)?;
|
||||
writeln!(f, " net: {:?}", self.nsinodes.net)?;
|
||||
writeln!(f, " uts: {:?}", self.nsinodes.uts)?;
|
||||
writeln!(f, " ipc: {:?}", self.nsinodes.ipc)?;
|
||||
writeln!(f, " pid: {:?}", self.nsinodes.pid)?;
|
||||
writeln!(f, " pid_for_children: {:?}", self.nsinodes.pid_for_children)?;
|
||||
writeln!(f, " user: {:?}", self.nsinodes.user)?;
|
||||
writeln!(f, " mnt: {:?}", self.nsinodes.mnt)?;
|
||||
writeln!(f, " cgroup: {:?}", self.nsinodes.cgroup)?;
|
||||
writeln!(f, " time: {:?}", self.nsinodes.time)?;
|
||||
writeln!(f, " time_for_children: {:?}", self.nsinodes.time_for_children)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_namespaces(pid: Option<i32>) -> Namespaces {
|
||||
fn get_namespace_inodes(pid: Pid) -> NamespaceInodes {
|
||||
let pid: String = match pid {
|
||||
Some(pid) => pid.to_string(),
|
||||
None => "self".to_string(),
|
||||
Pid::Pid(pid) => pid.to_string(),
|
||||
Pid::SelfPid => "self".to_string(),
|
||||
};
|
||||
let nspath = format!("/proc/{}/ns", pid);
|
||||
|
||||
let mut ns = Namespaces {
|
||||
nspath: nspath.clone(),
|
||||
let mut ns = NamespaceInodes {
|
||||
net: None,
|
||||
uts: None,
|
||||
ipc: None,
|
||||
|
|
@ -96,9 +127,74 @@ pub fn get_namespaces(pid: Option<i32>) -> Namespaces {
|
|||
ns
|
||||
}
|
||||
|
||||
fn get_ppid(pid: Pid) -> Option<Pid> {
|
||||
let content =
|
||||
match pid {
|
||||
Pid::SelfPid => fs::read_to_string(format!("/proc/self/status")).ok()?,
|
||||
Pid::Pid(pid) => fs::read_to_string(format!("/proc/{}/status", pid)).ok()?
|
||||
};
|
||||
let ppid=content
|
||||
.lines()
|
||||
.find(|line| line.starts_with("PPid:"))
|
||||
.and_then(|line| line.split_whitespace().nth(1))
|
||||
.and_then(|ppid| ppid.parse::<i32>().ok());
|
||||
match ppid {
|
||||
None => None,
|
||||
Some(ppid)=> Some(Pid::Pid(ppid))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn get_namespaces(pid: Pid) -> Namespaces {
|
||||
|
||||
match pid {
|
||||
Pid::Pid(_) =>
|
||||
{
|
||||
// go up the parent hierarchy until we find a parent with different namespaces
|
||||
let mut ppid = pid;
|
||||
let nsinodes = get_namespace_inodes(pid);
|
||||
loop {
|
||||
let candidate_ppid = get_ppid(ppid);
|
||||
match candidate_ppid {
|
||||
None => break,
|
||||
Some(candidate_ppid) =>
|
||||
{
|
||||
let ppid_nsinodes = get_namespace_inodes(candidate_ppid);
|
||||
if nsinodes.equal_mnt_and_net(&ppid_nsinodes) {
|
||||
ppid=candidate_ppid;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let nspath = format!("{}/ns", pid.path());
|
||||
let nsroot = format!("{}/ns", ppid.path());
|
||||
Namespaces {
|
||||
nspath: nspath,
|
||||
nsroot: nsroot,
|
||||
nsinodes: nsinodes,
|
||||
}
|
||||
},
|
||||
Pid::SelfPid =>
|
||||
{
|
||||
let nsinodes = get_namespace_inodes(pid);
|
||||
let nspath = format!("{}/ns", pid.path());
|
||||
Namespaces {
|
||||
nspath: nspath.clone(),
|
||||
nsroot: nspath,
|
||||
nsinodes: nsinodes,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs a function inside the given network and mount namespaces.
|
||||
/// Returns the child PID so the caller can `waitpid` on it.
|
||||
pub fn run_in_net_and_mnt_namespace(ns: Namespaces, func: Box<dyn Fn()>) -> nix::Result<Pid> {
|
||||
pub fn run_in_net_and_mnt_namespace(ns: Namespaces, func: Box<dyn Fn()>) -> nix::Result<nix::unistd::Pid> {
|
||||
//Note: The child process is created with a single thread—the one that called fork().
|
||||
match unsafe { fork()? } {
|
||||
ForkResult::Parent { child } => {
|
||||
|
|
@ -107,13 +203,13 @@ pub fn run_in_net_and_mnt_namespace(ns: Namespaces, func: Box<dyn Fn()>) -> nix:
|
|||
}
|
||||
ForkResult::Child => {
|
||||
// enter namespace
|
||||
let path: &Path = Path::new(ns.nspath.as_str());
|
||||
let path: &Path = Path::new(ns.nsroot.as_str());
|
||||
if !fs::exists(path).unwrap() {
|
||||
debug!("the process whose namespaces we want to enter does not exist anymore!");
|
||||
debug!("the root process of the container whose namespaces we want to enter does not exist anymore!");
|
||||
std::process::exit(0);
|
||||
}
|
||||
let net = File::open(ns.nspath.clone() + "/net").expect("net not found");
|
||||
let mnt = File::open(ns.nspath.clone() + "/mnt").expect("mnt not found");
|
||||
let net = File::open(ns.nsroot.clone() + "/net").expect("net not found");
|
||||
let mnt = File::open(ns.nsroot.clone() + "/mnt").expect("mnt not found");
|
||||
setns(net.as_fd(), CloneFlags::CLONE_NEWNET).expect("couldn't enter net");
|
||||
setns(mnt.as_fd(), CloneFlags::CLONE_NEWNS).expect("couldn't enter mnt");
|
||||
// execute your function
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue