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