devices/virtio/fs/
worker.rs

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
5use 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        // SAFETY: Safe because this doesn't modify any memory and we check the return value.
185        syscall!(unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) })
186            .map_err(Error::GetResuid)?;
187
188        // Only need to set SECBIT_NO_SETUID_FIXUP for threads which could change uid.
189        if ruid == 0 || ruid != euid || ruid != suid {
190            // We need to set the no setuid fixup secure bit so that we don't drop capabilities when
191            // changing the thread uid/gid. Without this, creating new entries can fail in some
192            // corner cases.
193            const SECBIT_NO_SETUID_FIXUP: i32 = 1 << 2;
194
195            let mut securebits = syscall!(
196                // SAFETY:
197                // Safe because this doesn't modify any memory and we check the return value.
198                unsafe { libc::prctl(libc::PR_GET_SECUREBITS) }
199            )
200            .map_err(Error::GetSecurebits)?;
201
202            securebits |= SECBIT_NO_SETUID_FIXUP;
203
204            syscall!(
205                // SAFETY:
206                // Safe because this doesn't modify any memory and we check the return value.
207                unsafe { libc::prctl(libc::PR_SET_SECUREBITS, securebits) }
208            )
209            .map_err(Error::SetSecurebits)?;
210        }
211
212        // To avoid extra locking, unshare filesystem attributes from parent. This includes the
213        // current working directory and umask.
214        syscall!(
215            // SAFETY: Safe because this doesn't modify any memory and we check the return value.
216            unsafe { libc::unshare(libc::CLONE_FS) }
217        )
218        .map_err(Error::UnshareFromParent)?;
219
220        #[derive(EventToken)]
221        enum Token {
222            // A request is ready on the queue.
223            QueueReady,
224            // The parent thread requested an exit.
225            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}