devices/virtio/fs/
worker.rs1use std::convert::TryFrom;
6use std::convert::TryInto;
7use std::fs::File;
8use std::io;
9use std::os::unix::io::AsRawFd;
10use std::sync::Arc;
11
12use base::error;
13use base::syscall;
14use base::Event;
15use base::EventToken;
16use base::Protection;
17use base::SafeDescriptor;
18use base::Tube;
19use base::WaitContext;
20use fuse::filesystem::FileSystem;
21use fuse::filesystem::ZeroCopyReader;
22use fuse::filesystem::ZeroCopyWriter;
23use sync::Mutex;
24use vm_control::FsMappingRequest;
25use vm_control::VmResponse;
26
27use crate::virtio::fs::Error;
28use crate::virtio::fs::Result;
29use crate::virtio::Queue;
30use crate::virtio::Reader;
31use crate::virtio::Writer;
32
33impl fuse::Reader for Reader {}
34
35impl fuse::Writer for Writer {
36 type ClosureWriter = Self;
37
38 fn write_at<F>(&mut self, offset: usize, f: F) -> io::Result<usize>
39 where
40 F: Fn(&mut Self) -> io::Result<usize>,
41 {
42 let mut writer = Writer::split_at(self, offset);
43 f(&mut writer)
44 }
45
46 fn has_sufficient_buffer(&self, size: u32) -> bool {
47 self.available_bytes() >= size as usize
48 }
49}
50
51impl ZeroCopyReader for Reader {
52 fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
53 self.read_to_at(f, count, off)
54 }
55}
56
57impl ZeroCopyWriter for Writer {
58 fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
59 self.write_from_at(f, count, off)
60 }
61}
62
63struct Mapper {
64 tube: Arc<Mutex<Tube>>,
65 slot: u32,
66}
67
68impl Mapper {
69 fn new(tube: Arc<Mutex<Tube>>, slot: u32) -> Self {
70 Self { tube, slot }
71 }
72
73 fn process_request(&self, request: &FsMappingRequest) -> io::Result<()> {
74 let tube = self.tube.lock();
75
76 tube.send(request).map_err(|e| {
77 error!("failed to send request {:?}: {}", request, e);
78 io::Error::from_raw_os_error(libc::EINVAL)
79 })?;
80
81 match tube.recv() {
82 Ok(VmResponse::Ok) => Ok(()),
83 Ok(VmResponse::Err(e)) => Err(e.into()),
84 r => {
85 error!("failed to process {:?}: {:?}", request, r);
86 Err(io::Error::from_raw_os_error(libc::EIO))
87 }
88 }
89 }
90}
91
92impl fuse::Mapper for Mapper {
93 fn map(
94 &self,
95 mem_offset: u64,
96 size: usize,
97 fd: &dyn AsRawFd,
98 file_offset: u64,
99 prot: Protection,
100 ) -> io::Result<()> {
101 let mem_offset: usize = mem_offset.try_into().map_err(|e| {
102 error!("mem_offset {} is too big: {}", mem_offset, e);
103 io::Error::from_raw_os_error(libc::EINVAL)
104 })?;
105
106 let fd = SafeDescriptor::try_from(fd)?;
107
108 let request = FsMappingRequest::CreateMemoryMapping {
109 slot: self.slot,
110 fd,
111 size,
112 file_offset,
113 prot,
114 mem_offset,
115 };
116
117 self.process_request(&request)
118 }
119
120 fn unmap(&self, offset: u64, size: u64) -> io::Result<()> {
121 let offset: usize = offset.try_into().map_err(|e| {
122 error!("offset {} is too big: {}", offset, e);
123 io::Error::from_raw_os_error(libc::EINVAL)
124 })?;
125 let size: usize = size.try_into().map_err(|e| {
126 error!("size {} is too big: {}", size, e);
127 io::Error::from_raw_os_error(libc::EINVAL)
128 })?;
129
130 let request = FsMappingRequest::RemoveMemoryMapping {
131 slot: self.slot,
132 offset,
133 size,
134 };
135
136 self.process_request(&request)
137 }
138}
139
140pub struct Worker<F: FileSystem + Sync> {
141 pub(crate) queue: Queue,
142 server: Arc<fuse::Server<F>>,
143 tube: Arc<Mutex<Tube>>,
144 slot: u32,
145}
146
147fn process_fs_queue<F: FileSystem + Sync>(
148 queue: &mut Queue,
149 server: &Arc<fuse::Server<F>>,
150 tube: &Arc<Mutex<Tube>>,
151 slot: u32,
152) -> Result<()> {
153 let mapper = Mapper::new(Arc::clone(tube), slot);
154 while let Some(mut avail_desc) = queue.pop() {
155 let total =
156 server.handle_message(&mut avail_desc.reader, &mut avail_desc.writer, &mapper)?;
157
158 queue.add_used_with_bytes_written(avail_desc, total as u32);
159 queue.trigger_interrupt();
160 }
161
162 Ok(())
163}
164
165impl<F: FileSystem + Sync> Worker<F> {
166 pub fn new(
167 queue: Queue,
168 server: Arc<fuse::Server<F>>,
169 tube: Arc<Mutex<Tube>>,
170 slot: u32,
171 ) -> Worker<F> {
172 Worker {
173 queue,
174 server,
175 tube,
176 slot,
177 }
178 }
179
180 pub fn run(&mut self, kill_evt: Event) -> Result<()> {
181 let mut ruid: libc::uid_t = 0;
182 let mut euid: libc::uid_t = 0;
183 let mut suid: libc::uid_t = 0;
184 syscall!(unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) })
186 .map_err(Error::GetResuid)?;
187
188 if ruid == 0 || ruid != euid || ruid != suid {
190 const SECBIT_NO_SETUID_FIXUP: i32 = 1 << 2;
194
195 let mut securebits = syscall!(
196 unsafe { libc::prctl(libc::PR_GET_SECUREBITS) }
199 )
200 .map_err(Error::GetSecurebits)?;
201
202 securebits |= SECBIT_NO_SETUID_FIXUP;
203
204 syscall!(
205 unsafe { libc::prctl(libc::PR_SET_SECUREBITS, securebits) }
208 )
209 .map_err(Error::SetSecurebits)?;
210 }
211
212 syscall!(
215 unsafe { libc::unshare(libc::CLONE_FS) }
217 )
218 .map_err(Error::UnshareFromParent)?;
219
220 #[derive(EventToken)]
221 enum Token {
222 QueueReady,
224 Kill,
226 }
227
228 let wait_ctx = WaitContext::build_with(&[
229 (self.queue.event(), Token::QueueReady),
230 (&kill_evt, Token::Kill),
231 ])
232 .map_err(Error::CreateWaitContext)?;
233
234 loop {
235 let events = wait_ctx.wait().map_err(Error::WaitError)?;
236 for event in events.iter().filter(|e| e.is_readable) {
237 match event.token {
238 Token::QueueReady => {
239 self.queue.event().wait().map_err(Error::ReadQueueEvent)?;
240 if let Err(e) =
241 process_fs_queue(&mut self.queue, &self.server, &self.tube, self.slot)
242 {
243 error!("virtio-fs transport error: {}", e);
244 return Err(e);
245 }
246 }
247 Token::Kill => return Ok(()),
248 }
249 }
250 }
251 }
252}