mirror of
https://github.com/joleuger/vuinputd.git
synced 2026-07-18 00:45:07 +00:00
Simple name refactoring
This commit is contained in:
parent
2192432915
commit
b645f73dc0
5 changed files with 54 additions and 54 deletions
|
|
@ -9,12 +9,12 @@ use async_pidfd::AsyncPidFd;
|
|||
use log::debug;
|
||||
|
||||
use crate::{
|
||||
container::{mknod_input_device::ensure_input_device, netlink_message::send_udev_monitor_message_with_properties, runtime_data::{self, ensure_udev_structure, read_udev_data, write_udev_data}}, jobs::job::{Job, JobTarget}, monitor_udev::EVENT_STORE, namespace::{run_in_net_and_mnt_namespace, Namespaces}
|
||||
container::{mknod_input_device::ensure_input_device, netlink_message::send_udev_monitor_message_with_properties, runtime_data::{self, ensure_udev_structure, read_udev_data, write_udev_data}}, jobs::job::{Job, JobTarget}, monitor_udev::EVENT_STORE, requesting_process::{run_in_net_and_mnt_namespace, RequestingProcess}
|
||||
};
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct InjectInContainerJob {
|
||||
namespaces: Namespaces,
|
||||
requesting_process: RequestingProcess,
|
||||
target: JobTarget,
|
||||
dev_path: String,
|
||||
sys_path: String,
|
||||
|
|
@ -23,10 +23,10 @@ pub struct InjectInContainerJob {
|
|||
}
|
||||
|
||||
impl InjectInContainerJob {
|
||||
pub fn new(namespaces: Namespaces,dev_path: String, sys_path: String, major: u64, minor: u64) -> Self {
|
||||
pub fn new(requesting_process: RequestingProcess,dev_path: String, sys_path: String, major: u64, minor: u64) -> Self {
|
||||
Self {
|
||||
namespaces: namespaces.clone(),
|
||||
target: JobTarget::Container(namespaces),
|
||||
requesting_process: requesting_process.clone(),
|
||||
target: JobTarget::Container(requesting_process),
|
||||
dev_path: dev_path,
|
||||
sys_path: sys_path,
|
||||
major: major ,
|
||||
|
|
@ -99,7 +99,7 @@ impl InjectInContainerJob {
|
|||
let netlink_data = netlink_data.unwrap();
|
||||
|
||||
|
||||
let child_pid = run_in_net_and_mnt_namespace(self.namespaces, Box::new(move || {
|
||||
let child_pid = run_in_net_and_mnt_namespace(self.requesting_process, Box::new(move || {
|
||||
|
||||
if let Err(e) = ensure_input_device(self.dev_path.clone(), self.major, self.minor) {
|
||||
debug!("Error creating input device {}: {e}",self.dev_path.clone());
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ use async_pidfd::AsyncPidFd;
|
|||
use log::debug;
|
||||
|
||||
use crate::{
|
||||
container::{mknod_input_device::{ensure_input_device, remove_input_device}, netlink_message::send_udev_monitor_message_with_properties, runtime_data::{self, delete_udev_data, ensure_udev_structure, read_udev_data, write_udev_data}}, jobs::job::{Job, JobTarget}, monitor_udev::EVENT_STORE, namespace::{Namespaces, run_in_net_and_mnt_namespace}
|
||||
container::{mknod_input_device::{ensure_input_device, remove_input_device}, netlink_message::send_udev_monitor_message_with_properties, runtime_data::{self, delete_udev_data, ensure_udev_structure, read_udev_data, write_udev_data}}, jobs::job::{Job, JobTarget}, monitor_udev::EVENT_STORE, requesting_process::{RequestingProcess, run_in_net_and_mnt_namespace}
|
||||
};
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct RemoveFromContainerJob {
|
||||
namespaces: Namespaces,
|
||||
requesting_process: RequestingProcess,
|
||||
target: JobTarget,
|
||||
dev_path: String,
|
||||
sys_path: String,
|
||||
|
|
@ -23,10 +23,10 @@ pub struct RemoveFromContainerJob {
|
|||
}
|
||||
|
||||
impl RemoveFromContainerJob {
|
||||
pub fn new(namespaces: Namespaces,dev_path: String, sys_path: String, major: u64, minor: u64) -> Self {
|
||||
pub fn new(requesting_process: RequestingProcess,dev_path: String, sys_path: String, major: u64, minor: u64) -> Self {
|
||||
Self {
|
||||
namespaces: namespaces.clone(),
|
||||
target: JobTarget::Container(namespaces),
|
||||
requesting_process: requesting_process.clone(),
|
||||
target: JobTarget::Container(requesting_process),
|
||||
dev_path: dev_path,
|
||||
sys_path: sys_path,
|
||||
major: major ,
|
||||
|
|
@ -75,7 +75,7 @@ impl RemoveFromContainerJob {
|
|||
let minor=self.minor;
|
||||
|
||||
let _ = netlink_data.insert("ACTION".to_string(),"remove".to_string());
|
||||
let child_pid = run_in_net_and_mnt_namespace(self.namespaces, Box::new(move || {
|
||||
let child_pid = run_in_net_and_mnt_namespace(self.requesting_process, Box::new(move || {
|
||||
// TODO: we should keep the same order as event_execute_rules_on_remove in
|
||||
// https://github.com/systemd/systemd/blob/main/src/udev/udev-event.c
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::sync::Mutex;
|
|||
use std::thread::{self, JoinHandle};
|
||||
use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc};
|
||||
|
||||
use crate::namespace::Namespaces;
|
||||
use crate::requesting_process::RequestingProcess;
|
||||
|
||||
// To discuss:
|
||||
// what we handle here, could also be named Task. The decision for job was more or less
|
||||
|
|
@ -25,7 +25,7 @@ pub enum JobTarget {
|
|||
Host,
|
||||
BackgroundLoop,
|
||||
/// A specific container or namespace target.
|
||||
Container(Namespaces),
|
||||
Container(RequestingProcess),
|
||||
}
|
||||
|
||||
pub trait Job: Send + 'static {
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ use std::sync::atomic::{AtomicU64, Ordering};
|
|||
use std::sync::{Arc, Mutex, OnceLock, RwLock};
|
||||
use uinput_ioctls::*;
|
||||
|
||||
pub mod namespace;
|
||||
pub mod requesting_process;
|
||||
pub mod monitor_udev;
|
||||
use crate::container::inject_in_container_job::InjectInContainerJob;
|
||||
use crate::container::remove_from_container_job::RemoveFromContainerJob;
|
||||
use crate::monitor_udev::MonitorBackgroundLoop;
|
||||
use crate::namespace::*;
|
||||
use crate::requesting_process::*;
|
||||
|
||||
pub mod jobs;
|
||||
use crate::jobs::job::*;
|
||||
|
|
@ -64,7 +64,7 @@ struct VuInputDevice {
|
|||
#[derive(Debug)]
|
||||
struct VuInputState {
|
||||
file: File,
|
||||
ns_of_requestor: Namespaces,
|
||||
requesting_process: RequestingProcess,
|
||||
input_device: Option<VuInputDevice>
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ enum VuError {
|
|||
static VUINPUT_COUNTER: OnceLock<AtomicU64> = OnceLock::new();
|
||||
static VUINPUT_STATE: OnceLock<RwLock<HashMap<VuFileHandle, Arc<Mutex<VuInputState>>>>> = OnceLock::new();
|
||||
static JOB_DISPATCHER: OnceLock<Mutex<Dispatcher>>= OnceLock::new();
|
||||
static SELF_NAMESPACES: OnceLock<Namespaces>= OnceLock::new();
|
||||
static SELF_REQUESTING_PROCESSES: OnceLock<RequestingProcess>= OnceLock::new();
|
||||
|
||||
// For log limiting. Idea: Move to log_limit crate
|
||||
static DEDUP_LAST_ERROR: OnceLock<Mutex<Option<(u64,VuError)>>> = OnceLock::new();
|
||||
|
|
@ -210,7 +210,7 @@ unsafe extern "C" fn vuinput_open(
|
|||
&VuFileHandle::from_fuse_file_info(_fi.as_ref().unwrap()),
|
||||
VuInputState {
|
||||
file: v,
|
||||
ns_of_requestor: namespaces,
|
||||
requesting_process: namespaces,
|
||||
input_device: None
|
||||
},
|
||||
)
|
||||
|
|
@ -317,9 +317,9 @@ unsafe extern "C" fn vuinput_release(
|
|||
// Only do this in case it has not already been done by the ioctl UI_DEV_DESTROY
|
||||
// this here is relevant if the process was killed and didn't have the chance to send the
|
||||
// ioctl UI_DEV_DESTROY.
|
||||
if input_device.is_some() && ! SELF_NAMESPACES.get().unwrap().equal_mnt_and_net(&vuinput_state.ns_of_requestor) {
|
||||
if input_device.is_some() && ! SELF_REQUESTING_PROCESSES.get().unwrap().equal_mnt_and_net(&vuinput_state.requesting_process) {
|
||||
let input_device = input_device.unwrap();
|
||||
let remove_job=RemoveFromContainerJob::new(vuinput_state.ns_of_requestor.clone(),input_device.devnode.clone(),input_device.syspath.clone(),input_device.major,input_device.minor);
|
||||
let remove_job=RemoveFromContainerJob::new(vuinput_state.requesting_process.clone(),input_device.devnode.clone(),input_device.syspath.clone(),input_device.major,input_device.minor);
|
||||
JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(remove_job));
|
||||
}
|
||||
|
||||
|
|
@ -485,8 +485,8 @@ unsafe extern "C" fn vuinput_ioctl(
|
|||
vuinput_state.input_device = Some(VuInputDevice {cuse_fh:*fh, major: major, minor: minor, syspath: sysname.clone(), devnode: devnode.clone(), runtime_data: None, netlink_data: None });
|
||||
|
||||
// Create device in container, if the request was really from another namespace
|
||||
if ! SELF_NAMESPACES.get().unwrap().equal_mnt_and_net(&vuinput_state.ns_of_requestor) {
|
||||
let inject_job=InjectInContainerJob::new(vuinput_state.ns_of_requestor.clone(),devnode.clone(),sysname.clone(),major,minor);
|
||||
if ! SELF_REQUESTING_PROCESSES.get().unwrap().equal_mnt_and_net(&vuinput_state.requesting_process) {
|
||||
let inject_job=InjectInContainerJob::new(vuinput_state.requesting_process.clone(),devnode.clone(),sysname.clone(),major,minor);
|
||||
JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(inject_job));
|
||||
}
|
||||
|
||||
|
|
@ -500,9 +500,9 @@ unsafe extern "C" fn vuinput_ioctl(
|
|||
let input_device = vuinput_state.input_device.take();
|
||||
|
||||
// Remove device in container, if the request was really from another namespace
|
||||
if input_device.is_some() && ! SELF_NAMESPACES.get().unwrap().equal_mnt_and_net(&vuinput_state.ns_of_requestor) {
|
||||
if input_device.is_some() && ! SELF_REQUESTING_PROCESSES.get().unwrap().equal_mnt_and_net(&vuinput_state.requesting_process) {
|
||||
let input_device = input_device.unwrap();
|
||||
let remove_job=RemoveFromContainerJob::new(vuinput_state.ns_of_requestor.clone(),input_device.devnode.clone(),input_device.syspath.clone(),input_device.major,input_device.minor);
|
||||
let remove_job=RemoveFromContainerJob::new(vuinput_state.requesting_process.clone(),input_device.devnode.clone(),input_device.syspath.clone(),input_device.major,input_device.minor);
|
||||
JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(remove_job));
|
||||
}
|
||||
|
||||
|
|
@ -702,6 +702,18 @@ fn check_permissions() -> Result<(), std::io::Error> {
|
|||
})
|
||||
}
|
||||
|
||||
// this is static for the architecture
|
||||
pub fn compat_uses_64bit_time() -> bool {
|
||||
let uname = nix::sys::utsname::uname().unwrap();
|
||||
let arch = uname.machine().to_str().unwrap();
|
||||
|
||||
match arch {
|
||||
"x86_64" => false,
|
||||
"ppc64" => false, // some setups still 32-bit time_t
|
||||
_ => true, // arm64, riscv64, s390x all use 64-bit
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
|
||||
|
||||
|
|
@ -712,7 +724,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(Pid::SelfPid)).unwrap();
|
||||
SELF_REQUESTING_PROCESSES.set(get_namespaces(Pid::SelfPid)).unwrap();
|
||||
DEDUP_LAST_ERROR.set(Mutex::new(None)).unwrap();
|
||||
JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(MonitorBackgroundLoop::new()));
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ impl Pid {
|
|||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||
struct NamespaceInodes {
|
||||
struct Namespaces {
|
||||
pub net: Option<u64>,
|
||||
pub uts: Option<u64>,
|
||||
pub ipc: Option<u64>,
|
||||
|
|
@ -45,18 +45,6 @@ struct NamespaceInodes {
|
|||
|
||||
}
|
||||
|
||||
// this is static for the architecture
|
||||
fn compat_uses_64bit_time() -> bool {
|
||||
let uname = nix::sys::utsname::uname().unwrap();
|
||||
let arch = uname.machine().to_str().unwrap();
|
||||
|
||||
match arch {
|
||||
"x86_64" => false,
|
||||
"ppc64" => false, // some setups still 32-bit time_t
|
||||
_ => true, // arm64, riscv64, s390x all use 64-bit
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the process with `pid` is a 32-bit (compat) process. None, if unsure.
|
||||
pub fn is_compat_process(pid: i32) -> Option<bool> {
|
||||
const EI_CLASS: usize = 4;
|
||||
|
|
@ -84,25 +72,25 @@ pub fn is_compat_process(pid: i32) -> Option<bool> {
|
|||
|
||||
// TODO: Rename to capture all relevant process information
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Namespaces {
|
||||
pub struct RequestingProcess {
|
||||
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
|
||||
}
|
||||
nsinodes: Namespaces,
|
||||
}
|
||||
|
||||
impl Namespaces {
|
||||
pub fn equal_mnt_and_net(&self, other: &Namespaces) -> bool {
|
||||
self.mnt == other.mnt && self.net == other.net
|
||||
}
|
||||
}
|
||||
|
||||
impl RequestingProcess {
|
||||
pub fn equal_mnt_and_net(&self, other: &RequestingProcess) -> bool {
|
||||
self.nsinodes.equal_mnt_and_net(&other.nsinodes)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Namespaces {
|
||||
impl std::fmt::Display for RequestingProcess {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "Namespaces:")?;
|
||||
writeln!(f, " net: {:?}", self.nsinodes.net)?;
|
||||
|
|
@ -119,14 +107,14 @@ impl std::fmt::Display for Namespaces {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_namespace_inodes(pid: Pid) -> NamespaceInodes {
|
||||
fn get_namespace_inodes(pid: Pid) -> Namespaces {
|
||||
let pid: String = match pid {
|
||||
Pid::Pid(pid) => pid.to_string(),
|
||||
Pid::SelfPid => "self".to_string(),
|
||||
};
|
||||
let nspath = format!("/proc/{}/ns", pid);
|
||||
|
||||
let mut ns = NamespaceInodes {
|
||||
let mut ns = Namespaces {
|
||||
net: None,
|
||||
uts: None,
|
||||
ipc: None,
|
||||
|
|
@ -183,7 +171,7 @@ fn get_ppid(pid: Pid) -> Option<Pid> {
|
|||
|
||||
|
||||
|
||||
pub fn get_namespaces(pid: Pid) -> Namespaces {
|
||||
pub fn get_namespaces(pid: Pid) -> RequestingProcess {
|
||||
|
||||
match pid {
|
||||
Pid::Pid(_) =>
|
||||
|
|
@ -211,7 +199,7 @@ pub fn get_namespaces(pid: Pid) -> Namespaces {
|
|||
|
||||
let nspath = format!("{}/ns", pid.path());
|
||||
let nsroot = format!("{}/ns", ppid.path());
|
||||
Namespaces {
|
||||
RequestingProcess {
|
||||
nspath: nspath,
|
||||
nsroot: nsroot,
|
||||
nsinodes: nsinodes,
|
||||
|
|
@ -221,7 +209,7 @@ pub fn get_namespaces(pid: Pid) -> Namespaces {
|
|||
{
|
||||
let nsinodes = get_namespace_inodes(pid);
|
||||
let nspath = format!("{}/ns", pid.path());
|
||||
Namespaces {
|
||||
RequestingProcess {
|
||||
nspath: nspath.clone(),
|
||||
nsroot: nspath,
|
||||
nsinodes: nsinodes,
|
||||
|
|
@ -232,7 +220,7 @@ pub fn get_namespaces(pid: Pid) -> Namespaces {
|
|||
|
||||
/// 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<nix::unistd::Pid> {
|
||||
pub fn run_in_net_and_mnt_namespace(ns: RequestingProcess, 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()? } {
|
||||
Loading…
Add table
Add a link
Reference in a new issue