]> git.proxmox.com Git - pve-lxc-syscalld.git/blob - src/client.rs
syscalls are processed sequentially
[pve-lxc-syscalld.git] / src / client.rs
1 use std::sync::Arc;
2
3 use failure::Error;
4 use nix::errno::Errno;
5
6 use crate::io::seq_packet::SeqPacketSocket;
7 use crate::lxcseccomp::ProxyMessageBuffer;
8 use crate::syscall::{self, Syscall, SyscallStatus};
9
10 pub struct Client {
11 socket: SeqPacketSocket,
12 }
13
14 impl Client {
15 pub fn new(socket: SeqPacketSocket) -> Arc<Self> {
16 Arc::new(Self { socket })
17 }
18
19 /// Wrap futures returning a `Result` so if they fail we `shutdown()` the socket to drop the
20 /// client.
21 async fn wrap_error<F>(self: Arc<Self>, fut: F)
22 where
23 F: std::future::Future<Output = Result<(), Error>>,
24 {
25 if let Err(err) = fut.await {
26 eprintln!("client error, dropping connection: {}", err);
27 if let Err(err) = self.socket.shutdown(nix::sys::socket::Shutdown::Both) {
28 eprintln!(" (error shutting down client socket: {})", err);
29 }
30 }
31 }
32
33 pub async fn main(self: Arc<Self>) {
34 self.clone().wrap_error(self.main_do()).await
35 }
36
37 async fn main_do(self: Arc<Self>) -> Result<(), Error> {
38 let mut msg = ProxyMessageBuffer::new(64);
39 loop {
40 if !msg.recv(&self.socket).await? {
41 break Ok(());
42 }
43
44 self.handle_syscall(&mut msg).await?;
45 }
46 }
47
48 async fn handle_syscall(&self, msg: &mut ProxyMessageBuffer) -> Result<(), Error> {
49 let result = match Self::handle_syscall_do(&msg).await {
50 Ok(r) => r,
51 Err(err) => {
52 // handle the various kinds of errors we may get:
53 if let Some(errno) = err.downcast_ref::<nix::errno::Errno>() {
54 SyscallStatus::Err(*errno as _)
55 } else if let Some(nix::Error::Sys(errno)) = err.downcast_ref::<nix::Error>() {
56 SyscallStatus::Err(*errno as _)
57 } else if let Some(ioerr) = err.downcast_ref::<std::io::Error>() {
58 if let Some(errno) = ioerr.raw_os_error() {
59 SyscallStatus::Err(errno)
60 } else {
61 return Err(err);
62 }
63 } else {
64 return Err(err);
65 }
66 }
67 };
68
69 let resp = msg.response_mut();
70 match result {
71 SyscallStatus::Ok(val) => {
72 resp.val = val;
73 resp.error = 0;
74 }
75 SyscallStatus::Err(err) => {
76 resp.val = -1;
77 resp.error = -err;
78 }
79 }
80
81 msg.respond(&self.socket).await.map_err(Error::from)
82 }
83
84 async fn handle_syscall_do(msg: &ProxyMessageBuffer) -> Result<SyscallStatus, Error> {
85 let (arch, sysnr) = (msg.request().data.arch, msg.request().data.nr);
86
87 let syscall_nr = match syscall::translate_syscall(arch, sysnr) {
88 Some(nr) => nr,
89 None => return Ok(Errno::ENOSYS.into()),
90 };
91
92 match syscall_nr {
93 Syscall::Mknod => crate::sys_mknod::mknod(msg).await,
94 Syscall::MknodAt => crate::sys_mknod::mknodat(msg).await,
95 Syscall::Quotactl => crate::sys_quotactl::quotactl(msg).await,
96 }
97 }
98 }