diff --git a/vuinputd/src/container_runtime/injection_strategy.rs b/vuinputd/src/container_runtime/injection_strategy.rs index e0847b8..896a633 100644 --- a/vuinputd/src/container_runtime/injection_strategy.rs +++ b/vuinputd/src/container_runtime/injection_strategy.rs @@ -83,8 +83,9 @@ impl InjectionStrategy for GenericPlacementInContainer { minor: minor, }; - let child_pid = process_tools::start_action(mknod_device_action, &requesting_process) - .expect("subprocess should work"); + let child_pid = + process_tools::start_action(mknod_device_action, &requesting_process, false) + .expect("subprocess should work"); let _exit_info = process_tools::await_process(Pid::Pid(child_pid)) .await @@ -106,8 +107,9 @@ impl InjectionStrategy for GenericPlacementInContainer { minor: minor, }; - let child_pid_1 = process_tools::start_action(remove_device_action, &requesting_process) - .expect("subprocess should work"); + let child_pid_1 = + process_tools::start_action(remove_device_action, &requesting_process, false) + .expect("subprocess should work"); let _exit_info = process_tools::await_process(Pid::Pid(child_pid_1)).await; Ok(()) @@ -126,8 +128,9 @@ impl InjectionStrategy for GenericPlacementInContainer { minor: minor, }; - let child_pid = process_tools::start_action(write_udev_runtime_data, &requesting_process) - .expect("subprocess should work"); + let child_pid = + process_tools::start_action(write_udev_runtime_data, &requesting_process, false) + .expect("subprocess should work"); let _exit_info = process_tools::await_process(Pid::Pid(child_pid)) .await @@ -148,7 +151,7 @@ impl InjectionStrategy for GenericPlacementInContainer { }; let child_pid_2 = - process_tools::start_action(write_udev_runtime_data_action, &requesting_process) + process_tools::start_action(write_udev_runtime_data_action, &requesting_process, false) .expect("subprocess should work"); let _exit_info = process_tools::await_process(Pid::Pid(child_pid_2)).await; Ok(()) @@ -164,8 +167,9 @@ impl InjectionStrategy for GenericPlacementInContainer { netlink_message: netlink_message, }; - let child_pid = process_tools::start_action(emit_netlink_message, requesting_process) - .expect("subprocess should work"); + let child_pid = + process_tools::start_action(emit_netlink_message, requesting_process, false) + .expect("subprocess should work"); let _exit_info = process_tools::await_process(Pid::Pid(child_pid)).await; Ok(()) @@ -235,7 +239,6 @@ impl InjectionStrategy for GenericPlacementOnHost { Ok(()) } - /// Emit netlink message. async fn emit_netlink_message( &self, @@ -382,14 +385,21 @@ impl InjectionStrategy for Incus { .await } + /// Emit netlink message. /// Emit netlink message. async fn emit_netlink_message( &self, requesting_process: &RequestingProcess, netlink_message: HashMap, ) -> anyhow::Result<()> { - PLACEMENT_IN_CONTAINER - .emit_netlink_message(requesting_process, netlink_message) - .await + let emit_netlink_message = Action::EmitNetlinkMessage { + netlink_message: netlink_message, + }; + + let child_pid = process_tools::start_action(emit_netlink_message, requesting_process, true) + .expect("subprocess should work"); + + let _exit_info = process_tools::await_process(Pid::Pid(child_pid)).await; + Ok(()) } } diff --git a/vuinputd/src/cuse_device/vuinput_poll.rs b/vuinputd/src/cuse_device/vuinput_poll.rs index 80c6ccf..2dd658d 100644 --- a/vuinputd/src/cuse_device/vuinput_poll.rs +++ b/vuinputd/src/cuse_device/vuinput_poll.rs @@ -33,8 +33,6 @@ pub unsafe extern "C" fn vuinput_poll( get_vuinput_state(&VuFileHandle::from_fuse_file_info(fi.as_ref().unwrap())).unwrap(); let mut vuinput_state = vuinput_state_mutex.lock().unwrap(); - debug!("poll"); - match vuinput_state.poll.pollphase { PollPhase::Empty => { if ph != std::ptr::null_mut() { diff --git a/vuinputd/src/jobs/emit_udev_event_job.rs b/vuinputd/src/jobs/emit_udev_event_job.rs index 18d0389..ca5ff90 100644 --- a/vuinputd/src/jobs/emit_udev_event_job.rs +++ b/vuinputd/src/jobs/emit_udev_event_job.rs @@ -158,7 +158,10 @@ impl EmitUdevEventJob { .await .unwrap(); - injector.emit_netlink_message(&self.requesting_process, netlink_data).await.unwrap(); + injector + .emit_netlink_message(&self.requesting_process, netlink_data) + .await + .unwrap(); self.set_state(&State::Finished); } diff --git a/vuinputd/src/jobs/remove_device_job.rs b/vuinputd/src/jobs/remove_device_job.rs index 3e610b9..503e9cd 100644 --- a/vuinputd/src/jobs/remove_device_job.rs +++ b/vuinputd/src/jobs/remove_device_job.rs @@ -142,16 +142,10 @@ impl RemoveDeviceJob { .await .unwrap(); - // this is always in the container - let emit_netlink_message = Action::EmitNetlinkMessage { - netlink_message: netlink_data.clone(), - }; - - let child_pid_netlink = - process_tools::start_action(emit_netlink_message, &self.requesting_process) - .expect("subprocess should work"); - - let _exit_info = await_process(Pid::Pid(child_pid_netlink)).await; + injector + .emit_netlink_message(&self.requesting_process, netlink_data) + .await + .unwrap(); self.set_state(&State::Finished); } diff --git a/vuinputd/src/main.rs b/vuinputd/src/main.rs index 875768b..701d58f 100644 --- a/vuinputd/src/main.rs +++ b/vuinputd/src/main.rs @@ -82,14 +82,22 @@ struct Args { #[arg(long = "action-base64", value_name = "BASE64")] pub action_base64: Option, - /// Process id that is used as the namespace source (e.g. 1234 is used to read the namespaces from /proc/1234/ns). + /// Process id that is used as the namespace source (e.g. 1234 is used to read the namespaces from /proc/1234/ns). Enters net and + /// mnt namespaces by default. #[arg( long = "target-pid", value_name = "PID", - help = "Process id that is used as the namespace source (e.g. 1234 is used to read the namespaces from /proc/1234/ns)." + help = "Process id that is used as the namespace source (e.g. 1234 is used to read the namespaces from /proc/1234/ns). Enters net and mnt namespaces by default." )] pub target_pid: Option, + /// Enter also the user namespace. Used together with --target-pid. + #[arg( + long = "enter-user-namespace", + help = "Enter also the user namespace. Used together with --target-pid." + )] + pub enter_user_namespace: bool, + #[arg( long = "vt-guard", help = "Prevent all keyboard input from reaching the VT by setting K_OFF on /dev/tty0.", @@ -229,8 +237,12 @@ fn main() -> std::io::Result<()> { if action.is_some() { if let Some(target_pid) = args.target_pid { - process_tools::run_in_net_and_mnt_namespace(target_pid.as_str(), &args.device_owner) - .unwrap(); + process_tools::run_in_net_and_mnt_namespace( + target_pid.as_str(), + &args.device_owner, + args.enter_user_namespace, + ) + .unwrap(); } let error_code = actions::handle_action::handle_cli_action(action.unwrap()); std::process::exit(error_code); @@ -245,7 +257,7 @@ fn main() -> std::io::Result<()> { vt_tools::check_vt_status(); let container_runtime = args.resolve_runtime(); - let scope= args.get_scope(); + let scope = args.get_scope(); global_config::initialize_global_config( &args.device_policy, diff --git a/vuinputd/src/process_tools/mod.rs b/vuinputd/src/process_tools/mod.rs index ad78125..d0dac8b 100644 --- a/vuinputd/src/process_tools/mod.rs +++ b/vuinputd/src/process_tools/mod.rs @@ -282,46 +282,57 @@ fn print_debug_string(action: &str, ns: &RequestingProcess) { /// Runs a function inside the given network and mount namespaces. /// Returns the child PID so the caller can `waitpid` on it. -pub fn start_action(action: Action, ns: &RequestingProcess) -> anyhow::Result { +pub fn start_action( + action: Action, + ns: &RequestingProcess, + enter_user_ns: bool, +) -> anyhow::Result { let action_json = serde_json::to_string(&action).unwrap(); print_debug_string(&action_json, &ns); let device_owner = get_device_owner().to_string_rep(); let child = unsafe { - Command::new("/proc/self/exe") - .args([ - "--action", - action_json.as_str(), - "--target-pid", - ns.pid_requestor_root.to_string_rep().as_str(), - "--device-owner", - device_owner.as_str(), - ]) - .pre_exec(|| { - // Last resort, if the parent just is killed. - libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL); - Ok(()) - }) - .spawn() - .expect("failed to start vuinputd") + let mut cmd = Command::new("/proc/self/exe"); + cmd.args([ + "--action", + action_json.as_str(), + "--target-pid", + ns.pid_requestor_root.to_string_rep().as_str(), + "--device-owner", + device_owner.as_str(), + ]); + if enter_user_ns { + cmd.arg("--enter-user-namespace"); + } + cmd.pre_exec(|| { + // Last resort, if the parent just is killed. + libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL); + Ok(()) + }) + .spawn() + .expect("failed to start vuinputd") }; Result::Ok(child.id()) } -pub fn run_in_net_and_mnt_namespace(target_pid: &str, device_owner: &DeviceOwner) -> anyhow::Result<()> { +pub fn run_in_net_and_mnt_namespace( + target_pid: &str, + device_owner: &DeviceOwner, + enter_user_ns: bool, +) -> anyhow::Result<()> { debug!( "Entering namespaces of process {}. We assume this is the root process of the container.", target_pid ); let fs_uid_gid = if *device_owner == DeviceOwner::ContainerDevFolder { - let pid:u32 = target_pid.trim().parse()?; + let pid: u32 = target_pid.trim().parse()?; let pid = Pid::Pid(pid); - let fs_uid=ns_fscreds::get_uid_in_container(pid, 0)?; - let fs_gid=ns_fscreds::get_gid_in_container(pid, 0)?; - Some((fs_uid,fs_gid)) + let fs_uid = ns_fscreds::get_uid_in_container(pid, 0)?; + let fs_gid = ns_fscreds::get_gid_in_container(pid, 0)?; + Some((fs_uid, fs_gid)) } else { None }; @@ -331,16 +342,22 @@ pub fn run_in_net_and_mnt_namespace(target_pid: &str, device_owner: &DeviceOwner if !fs::exists(path).unwrap() { return Err(anyhow!("the root process of the container whose namespaces we want to enter does not exist anymore")); } + let user = File::open(nspath.to_string() + "/user")?; let net = File::open(nspath.to_string() + "/net")?; let mnt = File::open(nspath.to_string() + "/mnt")?; unsafe { // enter namespaces + if enter_user_ns { + libc::setns(user.as_raw_fd(), libc::CLONE_NEWUSER); + libc::setresgid(0, 0, 0); + libc::setresuid(0, 0, 0); + } libc::setns(net.as_raw_fd(), libc::CLONE_NEWNET); libc::setns(mnt.as_raw_fd(), libc::CLONE_NEWNS); }; - if let Some((fs_uid,fs_gid)) = fs_uid_gid { + if let Some((fs_uid, fs_gid)) = fs_uid_gid { ns_fscreds::acquire_uid_and_gid(fs_uid, fs_gid)?; }