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 pub(crate) 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>( queue: &mut Queue, server: &Arc<fuse::Server<F>>, tube: &Arc<Mutex<Tube>>, slot: u32, ) -> Result<()>149 fn process_fs_queue<F: FileSystem + Sync>(
150 queue: &mut Queue,
151 server: &Arc<fuse::Server<F>>,
152 tube: &Arc<Mutex<Tube>>,
153 slot: u32,
154 ) -> Result<()> {
155 let mapper = Mapper::new(Arc::clone(tube), slot);
156 while let Some(mut avail_desc) = queue.pop() {
157 let total =
158 server.handle_message(&mut avail_desc.reader, &mut avail_desc.writer, &mapper)?;
159
160 queue.add_used(avail_desc, total as u32);
161 queue.trigger_interrupt();
162 }
163
164 Ok(())
165 }
166
167 impl<F: FileSystem + Sync> Worker<F> {
new( queue: Queue, server: Arc<fuse::Server<F>>, irq: Interrupt, tube: Arc<Mutex<Tube>>, slot: u32, ) -> Worker<F>168 pub fn new(
169 queue: Queue,
170 server: Arc<fuse::Server<F>>,
171 irq: Interrupt,
172 tube: Arc<Mutex<Tube>>,
173 slot: u32,
174 ) -> Worker<F> {
175 Worker {
176 queue,
177 server,
178 irq,
179 tube,
180 slot,
181 }
182 }
183
run(&mut self, kill_evt: Event, watch_resample_event: bool) -> Result<()>184 pub fn run(&mut self, kill_evt: Event, watch_resample_event: bool) -> Result<()> {
185 let mut ruid: libc::uid_t = 0;
186 let mut euid: libc::uid_t = 0;
187 let mut suid: libc::uid_t = 0;
188 // SAFETY: Safe because this doesn't modify any memory and we check the return value.
189 syscall!(unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) })
190 .map_err(Error::GetResuid)?;
191
192 // Only need to set SECBIT_NO_SETUID_FIXUP for threads which could change uid.
193 if ruid == 0 || ruid != euid || ruid != suid {
194 // We need to set the no setuid fixup secure bit so that we don't drop capabilities when
195 // changing the thread uid/gid. Without this, creating new entries can fail in some
196 // corner cases.
197 const SECBIT_NO_SETUID_FIXUP: i32 = 1 << 2;
198
199 let mut securebits = syscall!(
200 // SAFETY:
201 // Safe because this doesn't modify any memory and we check the return value.
202 unsafe { libc::prctl(libc::PR_GET_SECUREBITS) }
203 )
204 .map_err(Error::GetSecurebits)?;
205
206 securebits |= SECBIT_NO_SETUID_FIXUP;
207
208 syscall!(
209 // SAFETY:
210 // Safe because this doesn't modify any memory and we check the return value.
211 unsafe { libc::prctl(libc::PR_SET_SECUREBITS, securebits) }
212 )
213 .map_err(Error::SetSecurebits)?;
214 }
215
216 // To avoid extra locking, unshare filesystem attributes from parent. This includes the
217 // current working directory and umask.
218 syscall!(
219 // SAFETY: Safe because this doesn't modify any memory and we check the return value.
220 unsafe { libc::unshare(libc::CLONE_FS) }
221 )
222 .map_err(Error::UnshareFromParent)?;
223
224 #[derive(EventToken)]
225 enum Token {
226 // A request is ready on the queue.
227 QueueReady,
228 // Check if any interrupts need to be re-asserted.
229 InterruptResample,
230 // The parent thread requested an exit.
231 Kill,
232 }
233
234 let wait_ctx = WaitContext::build_with(&[
235 (self.queue.event(), Token::QueueReady),
236 (&kill_evt, Token::Kill),
237 ])
238 .map_err(Error::CreateWaitContext)?;
239
240 if watch_resample_event {
241 if let Some(resample_evt) = self.irq.get_resample_evt() {
242 wait_ctx
243 .add(resample_evt, Token::InterruptResample)
244 .map_err(Error::CreateWaitContext)?;
245 }
246 }
247
248 loop {
249 let events = wait_ctx.wait().map_err(Error::WaitError)?;
250 for event in events.iter().filter(|e| e.is_readable) {
251 match event.token {
252 Token::QueueReady => {
253 self.queue.event().wait().map_err(Error::ReadQueueEvent)?;
254 if let Err(e) =
255 process_fs_queue(&mut self.queue, &self.server, &self.tube, self.slot)
256 {
257 error!("virtio-fs transport error: {}", e);
258 return Err(e);
259 }
260 }
261 Token::InterruptResample => {
262 self.irq.interrupt_resample();
263 }
264 Token::Kill => return Ok(()),
265 }
266 }
267 }
268 }
269 }
270