• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::convert::TryFrom;
6 use std::convert::TryInto;
7 use std::fs::File;
8 use std::io;
9 use std::os::unix::io::AsRawFd;
10 use std::sync::Arc;
11 
12 use base::error;
13 use base::syscall;
14 use base::Event;
15 use base::EventToken;
16 use base::Protection;
17 use base::SafeDescriptor;
18 use base::Tube;
19 use base::WaitContext;
20 use fuse::filesystem::FileSystem;
21 use fuse::filesystem::ZeroCopyReader;
22 use fuse::filesystem::ZeroCopyWriter;
23 use sync::Mutex;
24 use vm_control::FsMappingRequest;
25 use vm_control::VmResponse;
26 
27 use crate::virtio::fs::Error;
28 use crate::virtio::fs::Result;
29 use crate::virtio::Interrupt;
30 use crate::virtio::Queue;
31 use crate::virtio::Reader;
32 use crate::virtio::Writer;
33 
34 impl fuse::Reader for Reader {}
35 
36 impl fuse::Writer for Writer {
37     type ClosureWriter = Self;
38 
write_at<F>(&mut self, offset: usize, f: F) -> io::Result<usize> where F: Fn(&mut Self) -> io::Result<usize>,39     fn write_at<F>(&mut self, offset: usize, f: F) -> io::Result<usize>
40     where
41         F: Fn(&mut Self) -> io::Result<usize>,
42     {
43         let mut writer = Writer::split_at(self, offset);
44         f(&mut writer)
45     }
46 
has_sufficient_buffer(&self, size: u32) -> bool47     fn has_sufficient_buffer(&self, size: u32) -> bool {
48         self.available_bytes() >= size as usize
49     }
50 }
51 
52 impl ZeroCopyReader for Reader {
read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>53     fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
54         self.read_to_at(f, count, off)
55     }
56 }
57 
58 impl ZeroCopyWriter for Writer {
write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>59     fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
60         self.write_from_at(f, count, off)
61     }
62 }
63 
64 struct Mapper {
65     tube: Arc<Mutex<Tube>>,
66     slot: u32,
67 }
68 
69 impl Mapper {
new(tube: Arc<Mutex<Tube>>, slot: u32) -> Self70     fn new(tube: Arc<Mutex<Tube>>, slot: u32) -> Self {
71         Self { tube, slot }
72     }
73 
process_request(&self, request: &FsMappingRequest) -> io::Result<()>74     fn process_request(&self, request: &FsMappingRequest) -> io::Result<()> {
75         let tube = self.tube.lock();
76 
77         tube.send(request).map_err(|e| {
78             error!("failed to send request {:?}: {}", request, e);
79             io::Error::from_raw_os_error(libc::EINVAL)
80         })?;
81 
82         match tube.recv() {
83             Ok(VmResponse::Ok) => Ok(()),
84             Ok(VmResponse::Err(e)) => Err(e.into()),
85             r => {
86                 error!("failed to process {:?}: {:?}", request, r);
87                 Err(io::Error::from_raw_os_error(libc::EIO))
88             }
89         }
90     }
91 }
92 
93 impl fuse::Mapper for Mapper {
map( &self, mem_offset: u64, size: usize, fd: &dyn AsRawFd, file_offset: u64, prot: Protection, ) -> io::Result<()>94     fn map(
95         &self,
96         mem_offset: u64,
97         size: usize,
98         fd: &dyn AsRawFd,
99         file_offset: u64,
100         prot: Protection,
101     ) -> io::Result<()> {
102         let mem_offset: usize = mem_offset.try_into().map_err(|e| {
103             error!("mem_offset {} is too big: {}", mem_offset, e);
104             io::Error::from_raw_os_error(libc::EINVAL)
105         })?;
106 
107         let fd = SafeDescriptor::try_from(fd)?;
108 
109         let request = FsMappingRequest::CreateMemoryMapping {
110             slot: self.slot,
111             fd,
112             size,
113             file_offset,
114             prot,
115             mem_offset,
116         };
117 
118         self.process_request(&request)
119     }
120 
unmap(&self, offset: u64, size: u64) -> io::Result<()>121     fn unmap(&self, offset: u64, size: u64) -> io::Result<()> {
122         let offset: usize = offset.try_into().map_err(|e| {
123             error!("offset {} is too big: {}", offset, e);
124             io::Error::from_raw_os_error(libc::EINVAL)
125         })?;
126         let size: usize = size.try_into().map_err(|e| {
127             error!("size {} is too big: {}", size, e);
128             io::Error::from_raw_os_error(libc::EINVAL)
129         })?;
130 
131         let request = FsMappingRequest::RemoveMemoryMapping {
132             slot: self.slot,
133             offset,
134             size,
135         };
136 
137         self.process_request(&request)
138     }
139 }
140 
141 pub struct Worker<F: FileSystem + Sync> {
142     queue: Queue,
143     server: Arc<fuse::Server<F>>,
144     irq: Interrupt,
145     tube: Arc<Mutex<Tube>>,
146     slot: u32,
147 }
148 
process_fs_queue<F: FileSystem + Sync>( interrupt: &Interrupt, queue: &mut Queue, server: &Arc<fuse::Server<F>>, tube: &Arc<Mutex<Tube>>, slot: u32, ) -> Result<()>149 pub fn process_fs_queue<F: FileSystem + Sync>(
150     interrupt: &Interrupt,
151     queue: &mut Queue,
152     server: &Arc<fuse::Server<F>>,
153     tube: &Arc<Mutex<Tube>>,
154     slot: u32,
155 ) -> Result<()> {
156     let mapper = Mapper::new(Arc::clone(tube), slot);
157     while let Some(mut avail_desc) = queue.pop() {
158         let total =
159             server.handle_message(&mut avail_desc.reader, &mut avail_desc.writer, &mapper)?;
160 
161         queue.add_used(avail_desc, total as u32);
162         queue.trigger_interrupt(interrupt);
163     }
164 
165     Ok(())
166 }
167 
168 impl<F: FileSystem + Sync> Worker<F> {
new( queue: Queue, server: Arc<fuse::Server<F>>, irq: Interrupt, tube: Arc<Mutex<Tube>>, slot: u32, ) -> Worker<F>169     pub fn new(
170         queue: Queue,
171         server: Arc<fuse::Server<F>>,
172         irq: Interrupt,
173         tube: Arc<Mutex<Tube>>,
174         slot: u32,
175     ) -> Worker<F> {
176         Worker {
177             queue,
178             server,
179             irq,
180             tube,
181             slot,
182         }
183     }
184 
run(&mut self, kill_evt: Event, watch_resample_event: bool) -> Result<()>185     pub fn run(&mut self, kill_evt: Event, watch_resample_event: bool) -> Result<()> {
186         let mut ruid: libc::uid_t = 0;
187         let mut euid: libc::uid_t = 0;
188         let mut suid: libc::uid_t = 0;
189         // SAFETY: Safe because this doesn't modify any memory and we check the return value.
190         syscall!(unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) })
191             .map_err(Error::GetResuid)?;
192 
193         // Only need to set SECBIT_NO_SETUID_FIXUP for threads which could change uid.
194         if ruid == 0 || ruid != euid || ruid != suid {
195             // We need to set the no setuid fixup secure bit so that we don't drop capabilities when
196             // changing the thread uid/gid. Without this, creating new entries can fail in some
197             // corner cases.
198             const SECBIT_NO_SETUID_FIXUP: i32 = 1 << 2;
199 
200             let mut securebits = syscall!(
201                 // SAFETY:
202                 // Safe because this doesn't modify any memory and we check the return value.
203                 unsafe { libc::prctl(libc::PR_GET_SECUREBITS) }
204             )
205             .map_err(Error::GetSecurebits)?;
206 
207             securebits |= SECBIT_NO_SETUID_FIXUP;
208 
209             syscall!(
210                 // SAFETY:
211                 // Safe because this doesn't modify any memory and we check the return value.
212                 unsafe { libc::prctl(libc::PR_SET_SECUREBITS, securebits) }
213             )
214             .map_err(Error::SetSecurebits)?;
215         }
216 
217         // To avoid extra locking, unshare filesystem attributes from parent. This includes the
218         // current working directory and umask.
219         syscall!(
220             // SAFETY: Safe because this doesn't modify any memory and we check the return value.
221             unsafe { libc::unshare(libc::CLONE_FS) }
222         )
223         .map_err(Error::UnshareFromParent)?;
224 
225         #[derive(EventToken)]
226         enum Token {
227             // A request is ready on the queue.
228             QueueReady,
229             // Check if any interrupts need to be re-asserted.
230             InterruptResample,
231             // The parent thread requested an exit.
232             Kill,
233         }
234 
235         let wait_ctx = WaitContext::build_with(&[
236             (self.queue.event(), Token::QueueReady),
237             (&kill_evt, Token::Kill),
238         ])
239         .map_err(Error::CreateWaitContext)?;
240 
241         if watch_resample_event {
242             if let Some(resample_evt) = self.irq.get_resample_evt() {
243                 wait_ctx
244                     .add(resample_evt, Token::InterruptResample)
245                     .map_err(Error::CreateWaitContext)?;
246             }
247         }
248 
249         loop {
250             let events = wait_ctx.wait().map_err(Error::WaitError)?;
251             for event in events.iter().filter(|e| e.is_readable) {
252                 match event.token {
253                     Token::QueueReady => {
254                         self.queue.event().wait().map_err(Error::ReadQueueEvent)?;
255                         if let Err(e) = process_fs_queue(
256                             &self.irq,
257                             &mut self.queue,
258                             &self.server,
259                             &self.tube,
260                             self.slot,
261                         ) {
262                             error!("virtio-fs transport error: {}", e);
263                             return Err(e);
264                         }
265                     }
266                     Token::InterruptResample => {
267                         self.irq.interrupt_resample();
268                     }
269                     Token::Kill => return Ok(()),
270                 }
271             }
272         }
273     }
274 }
275