Skip to content

Commit 365d7d6

Browse files
WhatAmISupposedToPutHereslp
authored andcommitted
Merge hidpipe client into the main server binary
Signed-off-by: Sasha Finkelstein <[email protected]>
1 parent 610e787 commit 365d7d6

6 files changed

Lines changed: 60 additions & 44 deletions

File tree

crates/muvm/Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,3 @@ path = "src/bin/muvm.rs"
3535
[[bin]]
3636
name = "muvm-guest"
3737
path = "src/guest/bin/muvm-guest.rs"
38-
39-
[[bin]]
40-
name = "muvm-hidpipe"
41-
path = "src/hidpipe/bin/muvm-hidpipe.rs"

crates/muvm/src/guest/bin/muvm-guest.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use std::os::fd::AsFd;
2+
use std::panic::catch_unwind;
23
use std::process::Command;
3-
use std::{cmp, env};
4+
use std::{cmp, env, thread};
45

56
use anyhow::{Context, Result};
6-
use muvm::env::find_muvm_exec;
77
use muvm::guest::cli_options::options;
88
use muvm::guest::fex::setup_fex;
9+
use muvm::guest::hidpipe::start_hidpipe;
910
use muvm::guest::mount::mount_filesystems;
1011
use muvm::guest::net::configure_network;
1112
use muvm::guest::server::server_main;
@@ -60,12 +61,6 @@ fn main() -> Result<()> {
6061

6162
configure_network()?;
6263

63-
let muvm_hidpipe_path = find_muvm_exec("muvm-hidpipe")?;
64-
Command::new(muvm_hidpipe_path)
65-
.arg(format!("{}", options.uid))
66-
.spawn()
67-
.context("Failed to execute `muvm-hidpipe` as child process")?;
68-
6964
let run_path = match setup_user(options.username, options.uid, options.gid) {
7065
Ok(p) => p,
7166
Err(err) => return Err(err).context("Failed to set up user, bailing out"),
@@ -79,6 +74,13 @@ fn main() -> Result<()> {
7974

8075
setup_x11_forwarding(run_path)?;
8176

77+
let uid = options.uid.as_raw();
78+
thread::spawn(move || {
79+
if catch_unwind(|| start_hidpipe(uid)).is_err() {
80+
eprintln!("hidpipe thread crashed, input device passthrough will no longer function");
81+
}
82+
});
83+
8284
let rt = tokio::runtime::Runtime::new().unwrap();
8385
rt.block_on(async {
8486
server_main(options.server_port, options.command, options.command_args).await

crates/muvm/src/hidpipe/bin/muvm-hidpipe.rs renamed to crates/muvm/src/guest/hidpipe.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
use crate::guest::user;
2+
use crate::hidpipe_common::{
3+
empty_input_event, struct_to_socket, AddDevice, ClientHello, FFErase, FFUpload, InputEvent,
4+
MessageType, RemoveDevice, ServerHello,
5+
};
16
use input_linux::bitmask::BitmaskTrait;
27
use input_linux::{
38
AbsoluteAxis, AbsoluteInfo, Bitmask, EventKind, ForceFeedbackKind, InputProperty, Key, LedKind,
@@ -7,20 +12,16 @@ use input_linux_sys::{
712
ff_effect, ff_replay, ff_trigger, input_absinfo, input_id, uinput_abs_setup, uinput_ff_erase,
813
uinput_ff_upload, uinput_setup,
914
};
10-
use muvm::hidpipe_common::{
11-
empty_input_event, struct_to_socket, AddDevice, ClientHello, FFErase, FFUpload, InputEvent,
12-
MessageType, RemoveDevice, ServerHello,
13-
};
1415
use nix::errno::Errno;
1516
use nix::libc::{c_char, O_NONBLOCK};
1617
use nix::sys::epoll::{Epoll, EpollCreateFlags, EpollEvent, EpollFlags, EpollTimeout};
1718
use nix::sys::socket::{connect, socket, AddressFamily, SockFlag, SockType, VsockAddr};
1819
use std::collections::HashMap;
19-
use std::env;
20+
use std::ffi::CString;
2021
use std::fs::File;
2122
use std::io::{Read, Write};
2223
use std::os::fd::AsRawFd;
23-
use std::os::unix::fs::{chown, OpenOptionsExt};
24+
use std::os::unix::fs::OpenOptionsExt;
2425
use std::os::unix::net::UnixStream;
2526
use std::{mem, slice};
2627

@@ -29,6 +30,7 @@ const REMOVE_DEVICE: u32 = MessageType::RemoveDevice as u32;
2930
const INPUT_EVENT: u32 = MessageType::InputEvent as u32;
3031
const FF_UPLOAD: u32 = MessageType::FFUpload as u32;
3132
const FF_ERASE: u32 = MessageType::FFErase as u32;
33+
pub const UINPUT_PATH: &str = "/dev/uinput";
3234

3335
fn bitmask_from_slice<T, A>(s: &T::Array) -> Bitmask<T>
3436
where
@@ -53,7 +55,7 @@ fn init_uinput(sock: &mut UnixStream, user_id: u32) -> (u64, UInputHandle<File>)
5355
.read(true)
5456
.write(true)
5557
.custom_flags(O_NONBLOCK)
56-
.open("/dev/uinput")
58+
.open(UINPUT_PATH)
5759
.unwrap(),
5860
);
5961
for evbit in bitmask_from_slice::<EventKind, _>(&add_dev.evbits).iter() {
@@ -119,7 +121,18 @@ fn init_uinput(sock: &mut UnixStream, user_id: u32) -> (u64, UInputHandle<File>)
119121
})
120122
.unwrap();
121123
uinput.dev_create().unwrap();
122-
chown(uinput.evdev_path().unwrap(), Some(user_id), Some(0)).unwrap();
124+
let ev_path = CString::new(
125+
uinput
126+
.evdev_path()
127+
.unwrap()
128+
.into_os_string()
129+
.into_encoded_bytes(),
130+
)
131+
.unwrap();
132+
// SAFETY: chown is async signal safe
133+
unsafe {
134+
user::run_as_root(|| nix::libc::chown(ev_path.as_ptr(), user_id, 0)).unwrap();
135+
}
123136
(add_dev.id, uinput)
124137
}
125138

@@ -140,8 +153,7 @@ fn ff_effect_empty() -> ff_effect {
140153
}
141154
}
142155

143-
fn main() {
144-
let user_id = env::args().nth(1).unwrap().parse::<u32>().unwrap();
156+
pub fn start_hidpipe(user_id: u32) {
145157
let sock_fd = socket(
146158
AddressFamily::Vsock,
147159
SockType::Stream,

crates/muvm/src/guest/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod cli_options;
22
pub mod fex;
3+
pub mod hidpipe;
34
pub mod mount;
45
pub mod net;
56
pub mod server;

crates/muvm/src/guest/server_worker.rs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ use log::{debug, error};
1616
use nix::errno::Errno;
1717
use nix::sys::epoll::{Epoll, EpollCreateFlags, EpollEvent, EpollFlags, EpollTimeout};
1818
use nix::sys::socket::{connect, socket, AddressFamily, SockFlag, SockType, VsockAddr};
19-
use nix::sys::wait::{waitpid, WaitStatus};
20-
use nix::unistd::{fork, pipe, setresgid, setresuid, setsid, ForkResult, Gid, Uid};
19+
use nix::unistd::{pipe, setresgid, setresuid, setsid, Gid, Uid};
2120
use rustix::process::ioctl_tiocsctty;
2221
use rustix::pty::{ptsname, unlockpt};
2322
use rustix::termios::{tcsetwinsize, Winsize};
@@ -30,6 +29,7 @@ use tokio_stream::wrappers::TcpListenerStream;
3029
use tokio_stream::StreamExt as _;
3130
use uuid::Uuid;
3231

32+
use crate::guest::user;
3333
use crate::utils::launch::Launch;
3434
use crate::utils::stdio::make_stdout_stderr;
3535
use crate::utils::tty::*;
@@ -220,7 +220,7 @@ async fn handle_connection(
220220
if command == Path::new("/muvmdropcaches") {
221221
// SAFETY: everything below should be async signal safe
222222
let code = unsafe {
223-
run_as_root(|| {
223+
user::run_as_root(|| {
224224
let fd = nix::libc::open(c"/proc/sys/vm/drop_caches".as_ptr(), nix::libc::O_WRONLY);
225225
if fd < 0 {
226226
return 1;
@@ -464,21 +464,3 @@ fn run_io_guest(
464464
}
465465
}
466466
}
467-
468-
// SAFETY: f will be run in post-fork environment, and so must bas async signal safe
469-
unsafe fn run_as_root(f: impl FnOnce() -> i32) -> Result<i32> {
470-
// SAFETY: child only calls _exit, setuid, and f, all are async signal safe
471-
match unsafe { fork()? } {
472-
ForkResult::Child => {
473-
// SAFETY: _exit and setuid are safe as no pointers are involved
474-
unsafe {
475-
nix::libc::setuid(0);
476-
nix::libc::_exit(f());
477-
}
478-
},
479-
ForkResult::Parent { child } => match waitpid(child, None)? {
480-
WaitStatus::Exited(_, code) => Ok(code),
481-
e => Err(anyhow!("Unexpected status: {:?}", e)),
482-
},
483-
}
484-
}

crates/muvm/src/guest/user.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ use std::fs::{self, Permissions};
33
use std::os::unix::fs::{chown, PermissionsExt as _};
44
use std::path::{Path, PathBuf};
55

6+
use crate::guest::hidpipe::UINPUT_PATH;
67
use anyhow::{anyhow, Context, Result};
7-
use nix::unistd::{setresgid, setresuid, Gid, Uid, User};
8+
use nix::sys::wait::{waitpid, WaitStatus};
9+
use nix::unistd::{fork, setresgid, setresuid, ForkResult, Gid, Uid, User};
810

911
pub fn setup_user(username: String, uid: Uid, gid: Gid) -> Result<PathBuf> {
1012
setup_directories(uid, gid)?;
@@ -59,5 +61,26 @@ fn setup_directories(uid: Uid, gid: Gid) -> Result<()> {
5961
.context("Failed to chown `/dev/vsock`")?;
6062
}
6163

64+
chown(UINPUT_PATH, Some(uid.into()), Some(gid.into()))?;
65+
6266
Ok(())
6367
}
68+
69+
/// # Safety
70+
/// f will be run in post-fork environment, and so must be async signal safe
71+
pub unsafe fn run_as_root(f: impl FnOnce() -> i32) -> Result<i32> {
72+
// SAFETY: child only calls _exit, setuid, and f, all are async signal safe
73+
match unsafe { fork()? } {
74+
ForkResult::Child => {
75+
// SAFETY: _exit and setuid are safe as no pointers are involved
76+
unsafe {
77+
nix::libc::setuid(0);
78+
nix::libc::_exit(f());
79+
}
80+
},
81+
ForkResult::Parent { child } => match waitpid(child, None)? {
82+
WaitStatus::Exited(_, code) => Ok(code),
83+
e => Err(anyhow!("Unexpected status: {:?}", e)),
84+
},
85+
}
86+
}

0 commit comments

Comments
 (0)