xref: /aosp_15_r20/external/crosvm/fuse/src/server.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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::cmp::max;
6 use std::cmp::min;
7 use std::convert::TryInto;
8 use std::ffi::CStr;
9 use std::io;
10 use std::mem::size_of;
11 use std::mem::MaybeUninit;
12 use std::os::unix::io::AsRawFd;
13 use std::time::Duration;
14 
15 use base::error;
16 use base::pagesize;
17 use base::Protection;
18 use zerocopy::AsBytes;
19 use zerocopy::FromBytes;
20 use zerocopy::FromZeroes;
21 
22 use crate::filesystem::Context;
23 use crate::filesystem::DirEntry;
24 use crate::filesystem::DirectoryIterator;
25 use crate::filesystem::Entry;
26 use crate::filesystem::FileSystem;
27 use crate::filesystem::GetxattrReply;
28 use crate::filesystem::IoctlReply;
29 use crate::filesystem::ListxattrReply;
30 use crate::filesystem::ZeroCopyReader;
31 use crate::filesystem::ZeroCopyWriter;
32 use crate::sys::*;
33 use crate::Error;
34 use crate::Result;
35 
36 const DIRENT_PADDING: [u8; 8] = [0; 8];
37 
38 const SELINUX_XATTR_CSTR: &[u8] = b"security.selinux\0";
39 
40 /// A trait for reading from the underlying FUSE endpoint.
41 pub trait Reader: io::Read {
read_struct<T: AsBytes + FromBytes + FromZeroes>(&mut self) -> Result<T>42     fn read_struct<T: AsBytes + FromBytes + FromZeroes>(&mut self) -> Result<T> {
43         let mut out = T::new_zeroed();
44         self.read_exact(out.as_bytes_mut())
45             .map_err(Error::DecodeMessage)?;
46         Ok(out)
47     }
48 }
49 
50 impl<R: Reader> Reader for &'_ mut R {}
51 
52 /// A trait for writing to the underlying FUSE endpoint. The FUSE device expects the write
53 /// operation to happen in one write transaction. Since there are cases when data needs to be
54 /// generated earlier than the header, it implies the writer implementation to keep an internal
55 /// buffer. The buffer then can be flushed once header and data are both prepared.
56 pub trait Writer: io::Write {
57     /// The type passed in to the closure in `write_at`. For most implementations, this should be
58     /// `Self`.
59     type ClosureWriter: Writer + ZeroCopyWriter;
60 
61     /// Allows a closure to generate and write data at the current writer's offset. The current
62     /// writer is passed as a mutable reference to the closure. As an example, this provides an
63     /// adapter for the read implementation of a filesystem to write directly to the final buffer
64     /// without generating the FUSE header first.
65     ///
66     /// Notes: An alternative implementation would be to return a slightly different writer for the
67     /// API client to write to the offset. Since the API needs to be called for more than one time,
68     /// it imposes some complexity to deal with borrowing and mutability. The current approach
69     /// simply does not need to create a different writer, thus no need to deal with the mentioned
70     /// complexity.
write_at<F>(&mut self, offset: usize, f: F) -> io::Result<usize> where F: Fn(&mut Self::ClosureWriter) -> io::Result<usize>71     fn write_at<F>(&mut self, offset: usize, f: F) -> io::Result<usize>
72     where
73         F: Fn(&mut Self::ClosureWriter) -> io::Result<usize>;
74 
75     /// Checks if the writer can still accept certain amount of data.
has_sufficient_buffer(&self, size: u32) -> bool76     fn has_sufficient_buffer(&self, size: u32) -> bool;
77 }
78 
79 impl<W: Writer> Writer for &'_ mut W {
80     type ClosureWriter = W::ClosureWriter;
81 
write_at<F>(&mut self, offset: usize, f: F) -> io::Result<usize> where F: Fn(&mut Self::ClosureWriter) -> io::Result<usize>,82     fn write_at<F>(&mut self, offset: usize, f: F) -> io::Result<usize>
83     where
84         F: Fn(&mut Self::ClosureWriter) -> io::Result<usize>,
85     {
86         (**self).write_at(offset, f)
87     }
88 
has_sufficient_buffer(&self, size: u32) -> bool89     fn has_sufficient_buffer(&self, size: u32) -> bool {
90         (**self).has_sufficient_buffer(size)
91     }
92 }
93 
94 /// A trait for memory mapping for DAX.
95 ///
96 /// For some transports (like virtio) it may be possible to share a region of memory with the
97 /// FUSE kernel driver so that it can access file contents directly without issuing read or
98 /// write requests.  In this case the driver will instead send requests to map a section of a
99 /// file into the shared memory region.
100 pub trait Mapper {
101     /// Maps `size` bytes starting at `file_offset` bytes from within the given `fd` at `mem_offset`
102     /// bytes from the start of the memory region with `prot` protections. `mem_offset` must be
103     /// page aligned.
104     ///
105     /// # Arguments
106     /// * `mem_offset` - Page aligned offset into the memory region in bytes.
107     /// * `size` - Size of memory region in bytes.
108     /// * `fd` - File descriptor to mmap from.
109     /// * `file_offset` - Offset in bytes from the beginning of `fd` to start the mmap.
110     /// * `prot` - Protection of the memory region.
map( &self, mem_offset: u64, size: usize, fd: &dyn AsRawFd, file_offset: u64, prot: Protection, ) -> io::Result<()>111     fn map(
112         &self,
113         mem_offset: u64,
114         size: usize,
115         fd: &dyn AsRawFd,
116         file_offset: u64,
117         prot: Protection,
118     ) -> io::Result<()>;
119 
120     /// Unmaps `size` bytes at `offset` bytes from the start of the memory region. `offset` must be
121     /// page aligned.
122     ///
123     /// # Arguments
124     /// * `offset` - Page aligned offset into the arena in bytes.
125     /// * `size` - Size of memory region in bytes.
unmap(&self, offset: u64, size: u64) -> io::Result<()>126     fn unmap(&self, offset: u64, size: u64) -> io::Result<()>;
127 }
128 
129 impl<'a, M: Mapper> Mapper for &'a M {
map( &self, mem_offset: u64, size: usize, fd: &dyn AsRawFd, file_offset: u64, prot: Protection, ) -> io::Result<()>130     fn map(
131         &self,
132         mem_offset: u64,
133         size: usize,
134         fd: &dyn AsRawFd,
135         file_offset: u64,
136         prot: Protection,
137     ) -> io::Result<()> {
138         (**self).map(mem_offset, size, fd, file_offset, prot)
139     }
140 
unmap(&self, offset: u64, size: u64) -> io::Result<()>141     fn unmap(&self, offset: u64, size: u64) -> io::Result<()> {
142         (**self).unmap(offset, size)
143     }
144 }
145 
146 pub struct Server<F: FileSystem + Sync> {
147     fs: F,
148 }
149 
150 impl<F: FileSystem + Sync> Server<F> {
new(fs: F) -> Server<F>151     pub fn new(fs: F) -> Server<F> {
152         Server { fs }
153     }
154 
handle_message<R: Reader + ZeroCopyReader, W: Writer + ZeroCopyWriter, M: Mapper>( &self, mut r: R, w: W, mapper: M, ) -> Result<usize>155     pub fn handle_message<R: Reader + ZeroCopyReader, W: Writer + ZeroCopyWriter, M: Mapper>(
156         &self,
157         mut r: R,
158         w: W,
159         mapper: M,
160     ) -> Result<usize> {
161         let in_header: InHeader = r.read_struct()?;
162         cros_tracing::trace_simple_print!("fuse server: handle_message: in_header={:?}", in_header);
163 
164         if in_header.len
165             > size_of::<InHeader>() as u32 + size_of::<WriteIn>() as u32 + self.fs.max_buffer_size()
166         {
167             return reply_error(
168                 io::Error::from_raw_os_error(libc::ENOMEM),
169                 in_header.unique,
170                 w,
171             );
172         }
173         match Opcode::n(in_header.opcode) {
174             Some(Opcode::Lookup) => self.lookup(in_header, r, w),
175             Some(Opcode::Forget) => self.forget(in_header, r), // No reply.
176             Some(Opcode::Getattr) => self.getattr(in_header, r, w),
177             Some(Opcode::Setattr) => self.setattr(in_header, r, w),
178             Some(Opcode::Readlink) => self.readlink(in_header, w),
179             Some(Opcode::Symlink) => self.symlink(in_header, r, w),
180             Some(Opcode::Mknod) => self.mknod(in_header, r, w),
181             Some(Opcode::Mkdir) => self.mkdir(in_header, r, w),
182             Some(Opcode::Unlink) => self.unlink(in_header, r, w),
183             Some(Opcode::Rmdir) => self.rmdir(in_header, r, w),
184             Some(Opcode::Rename) => self.rename(in_header, r, w),
185             Some(Opcode::Link) => self.link(in_header, r, w),
186             Some(Opcode::Open) => self.open(in_header, r, w),
187             Some(Opcode::Read) => self.read(in_header, r, w),
188             Some(Opcode::Write) => self.write(in_header, r, w),
189             Some(Opcode::Statfs) => self.statfs(in_header, w),
190             Some(Opcode::Release) => self.release(in_header, r, w),
191             Some(Opcode::Fsync) => self.fsync(in_header, r, w),
192             Some(Opcode::Setxattr) => self.setxattr(in_header, r, w),
193             Some(Opcode::Getxattr) => self.getxattr(in_header, r, w),
194             Some(Opcode::Listxattr) => self.listxattr(in_header, r, w),
195             Some(Opcode::Removexattr) => self.removexattr(in_header, r, w),
196             Some(Opcode::Flush) => self.flush(in_header, r, w),
197             Some(Opcode::Init) => self.init(in_header, r, w),
198             Some(Opcode::Opendir) => self.opendir(in_header, r, w),
199             Some(Opcode::Readdir) => self.readdir(in_header, r, w),
200             Some(Opcode::Releasedir) => self.releasedir(in_header, r, w),
201             Some(Opcode::Fsyncdir) => self.fsyncdir(in_header, r, w),
202             Some(Opcode::Getlk) => self.getlk(in_header, r, w),
203             Some(Opcode::Setlk) => self.setlk(in_header, r, w),
204             Some(Opcode::Setlkw) => self.setlkw(in_header, r, w),
205             Some(Opcode::Access) => self.access(in_header, r, w),
206             Some(Opcode::Create) => self.create(in_header, r, w),
207             Some(Opcode::Interrupt) => self.interrupt(in_header),
208             Some(Opcode::Bmap) => self.bmap(in_header, r, w),
209             Some(Opcode::Destroy) => self.destroy(),
210             Some(Opcode::Ioctl) => self.ioctl(in_header, r, w),
211             Some(Opcode::Poll) => self.poll(in_header, r, w),
212             Some(Opcode::NotifyReply) => self.notify_reply(in_header, r, w),
213             Some(Opcode::BatchForget) => self.batch_forget(in_header, r, w),
214             Some(Opcode::Fallocate) => self.fallocate(in_header, r, w),
215             Some(Opcode::Readdirplus) => self.readdirplus(in_header, r, w),
216             Some(Opcode::Rename2) => self.rename2(in_header, r, w),
217             Some(Opcode::Lseek) => self.lseek(in_header, r, w),
218             Some(Opcode::CopyFileRange) => self.copy_file_range(in_header, r, w),
219             Some(Opcode::ChromeOsTmpfile) => self.chromeos_tmpfile(in_header, r, w),
220             Some(Opcode::SetUpMapping) => self.set_up_mapping(in_header, r, w, mapper),
221             Some(Opcode::RemoveMapping) => self.remove_mapping(in_header, r, w, mapper),
222             Some(Opcode::OpenAtomic) => self.open_atomic(in_header, r, w),
223             None => reply_error(
224                 io::Error::from_raw_os_error(libc::ENOSYS),
225                 in_header.unique,
226                 w,
227             ),
228         }
229     }
230 
lookup<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>231     fn lookup<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
232         let namelen = (in_header.len as usize)
233             .checked_sub(size_of::<InHeader>())
234             .ok_or(Error::InvalidHeaderLength)?;
235 
236         let mut buf = vec![0; namelen];
237 
238         r.read_exact(&mut buf).map_err(Error::DecodeMessage)?;
239 
240         let name = bytes_to_cstr(&buf)?;
241 
242         match self
243             .fs
244             .lookup(Context::from(in_header), in_header.nodeid.into(), name)
245         {
246             Ok(entry) => {
247                 let out = EntryOut::from(entry);
248 
249                 reply_ok(Some(out), None, in_header.unique, w)
250             }
251             Err(e) => reply_error(e, in_header.unique, w),
252         }
253     }
254 
forget<R: Reader>(&self, in_header: InHeader, mut r: R) -> Result<usize>255     fn forget<R: Reader>(&self, in_header: InHeader, mut r: R) -> Result<usize> {
256         let ForgetIn { nlookup } = r.read_struct()?;
257 
258         self.fs
259             .forget(Context::from(in_header), in_header.nodeid.into(), nlookup);
260 
261         // There is no reply for forget messages.
262         Ok(0)
263     }
264 
getattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>265     fn getattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
266         let GetattrIn {
267             flags,
268             dummy: _,
269             fh,
270         } = r.read_struct()?;
271 
272         let handle = if (flags & GETATTR_FH) != 0 {
273             Some(fh.into())
274         } else {
275             None
276         };
277 
278         match self
279             .fs
280             .getattr(Context::from(in_header), in_header.nodeid.into(), handle)
281         {
282             Ok((st, timeout)) => {
283                 let out = AttrOut {
284                     attr_valid: timeout.as_secs(),
285                     attr_valid_nsec: timeout.subsec_nanos(),
286                     dummy: 0,
287                     attr: st.into(),
288                 };
289                 reply_ok(Some(out), None, in_header.unique, w)
290             }
291             Err(e) => reply_error(e, in_header.unique, w),
292         }
293     }
294 
setattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>295     fn setattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
296         let setattr_in: SetattrIn = r.read_struct()?;
297 
298         let handle = if setattr_in.valid & FATTR_FH != 0 {
299             Some(setattr_in.fh.into())
300         } else {
301             None
302         };
303 
304         let valid = SetattrValid::from_bits_truncate(setattr_in.valid);
305 
306         let st: libc::stat64 = setattr_in.into();
307 
308         match self.fs.setattr(
309             Context::from(in_header),
310             in_header.nodeid.into(),
311             st,
312             handle,
313             valid,
314         ) {
315             Ok((st, timeout)) => {
316                 let out = AttrOut {
317                     attr_valid: timeout.as_secs(),
318                     attr_valid_nsec: timeout.subsec_nanos(),
319                     dummy: 0,
320                     attr: st.into(),
321                 };
322                 reply_ok(Some(out), None, in_header.unique, w)
323             }
324             Err(e) => reply_error(e, in_header.unique, w),
325         }
326     }
327 
readlink<W: Writer>(&self, in_header: InHeader, w: W) -> Result<usize>328     fn readlink<W: Writer>(&self, in_header: InHeader, w: W) -> Result<usize> {
329         match self
330             .fs
331             .readlink(Context::from(in_header), in_header.nodeid.into())
332         {
333             Ok(linkname) => {
334                 // We need to disambiguate the option type here even though it is `None`.
335                 reply_ok(None::<u8>, Some(&linkname), in_header.unique, w)
336             }
337             Err(e) => reply_error(e, in_header.unique, w),
338         }
339     }
340 
symlink<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>341     fn symlink<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
342         // Unfortunately the name and linkname are encoded one after another and
343         // separated by a nul character.
344         let len = (in_header.len as usize)
345             .checked_sub(size_of::<InHeader>())
346             .ok_or(Error::InvalidHeaderLength)?;
347         let mut buf = vec![0; len];
348 
349         r.read_exact(&mut buf).map_err(Error::DecodeMessage)?;
350 
351         let mut iter = buf.split_inclusive(|&c| c == b'\0');
352         let name = iter
353             .next()
354             .ok_or(Error::MissingParameter)
355             .and_then(bytes_to_cstr)?;
356         let linkname = iter
357             .next()
358             .ok_or(Error::MissingParameter)
359             .and_then(bytes_to_cstr)?;
360 
361         let split_pos = name.to_bytes_with_nul().len() + linkname.to_bytes_with_nul().len();
362         let security_ctx = parse_selinux_xattr(&buf[split_pos..])?;
363 
364         match self.fs.symlink(
365             Context::from(in_header),
366             linkname,
367             in_header.nodeid.into(),
368             name,
369             security_ctx,
370         ) {
371             Ok(entry) => {
372                 let out = EntryOut::from(entry);
373 
374                 reply_ok(Some(out), None, in_header.unique, w)
375             }
376             Err(e) => reply_error(e, in_header.unique, w),
377         }
378     }
379 
mknod<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>380     fn mknod<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
381         let MknodIn {
382             mode, rdev, umask, ..
383         } = r.read_struct()?;
384 
385         let buflen = (in_header.len as usize)
386             .checked_sub(size_of::<InHeader>())
387             .and_then(|l| l.checked_sub(size_of::<MknodIn>()))
388             .ok_or(Error::InvalidHeaderLength)?;
389         let mut buf = vec![0; buflen];
390 
391         r.read_exact(&mut buf).map_err(Error::DecodeMessage)?;
392 
393         let mut iter = buf.split_inclusive(|&c| c == b'\0');
394         let name = iter
395             .next()
396             .ok_or(Error::MissingParameter)
397             .and_then(bytes_to_cstr)?;
398 
399         let split_pos = name.to_bytes_with_nul().len();
400         let security_ctx = parse_selinux_xattr(&buf[split_pos..])?;
401 
402         match self.fs.mknod(
403             Context::from(in_header),
404             in_header.nodeid.into(),
405             name,
406             mode,
407             rdev,
408             umask,
409             security_ctx,
410         ) {
411             Ok(entry) => {
412                 let out = EntryOut::from(entry);
413 
414                 reply_ok(Some(out), None, in_header.unique, w)
415             }
416             Err(e) => reply_error(e, in_header.unique, w),
417         }
418     }
419 
mkdir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>420     fn mkdir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
421         let MkdirIn { mode, umask } = r.read_struct()?;
422 
423         let buflen = (in_header.len as usize)
424             .checked_sub(size_of::<InHeader>())
425             .and_then(|l| l.checked_sub(size_of::<MkdirIn>()))
426             .ok_or(Error::InvalidHeaderLength)?;
427         let mut buf = vec![0; buflen];
428 
429         r.read_exact(&mut buf).map_err(Error::DecodeMessage)?;
430 
431         let mut iter = buf.split_inclusive(|&c| c == b'\0');
432         let name = iter
433             .next()
434             .ok_or(Error::MissingParameter)
435             .and_then(bytes_to_cstr)?;
436 
437         let split_pos = name.to_bytes_with_nul().len();
438         let security_ctx = parse_selinux_xattr(&buf[split_pos..])?;
439 
440         match self.fs.mkdir(
441             Context::from(in_header),
442             in_header.nodeid.into(),
443             name,
444             mode,
445             umask,
446             security_ctx,
447         ) {
448             Ok(entry) => {
449                 let out = EntryOut::from(entry);
450 
451                 reply_ok(Some(out), None, in_header.unique, w)
452             }
453             Err(e) => reply_error(e, in_header.unique, w),
454         }
455     }
456 
chromeos_tmpfile<R: Reader, W: Writer>( &self, in_header: InHeader, mut r: R, w: W, ) -> Result<usize>457     fn chromeos_tmpfile<R: Reader, W: Writer>(
458         &self,
459         in_header: InHeader,
460         mut r: R,
461         w: W,
462     ) -> Result<usize> {
463         let ChromeOsTmpfileIn { mode, umask } = r.read_struct()?;
464 
465         let len = (in_header.len as usize)
466             .checked_sub(size_of::<InHeader>())
467             .and_then(|l| l.checked_sub(size_of::<ChromeOsTmpfileIn>()))
468             .ok_or(Error::InvalidHeaderLength)?;
469         let mut buf = vec![0; len];
470 
471         r.read_exact(&mut buf).map_err(Error::DecodeMessage)?;
472 
473         let security_ctx = parse_selinux_xattr(&buf)?;
474 
475         match self.fs.chromeos_tmpfile(
476             Context::from(in_header),
477             in_header.nodeid.into(),
478             mode,
479             umask,
480             security_ctx,
481         ) {
482             Ok(entry) => {
483                 let out = EntryOut::from(entry);
484 
485                 reply_ok(Some(out), None, in_header.unique, w)
486             }
487             Err(e) => reply_error(e, in_header.unique, w),
488         }
489     }
490 
unlink<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>491     fn unlink<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
492         let namelen = (in_header.len as usize)
493             .checked_sub(size_of::<InHeader>())
494             .ok_or(Error::InvalidHeaderLength)?;
495         let mut name = vec![0; namelen];
496 
497         r.read_exact(&mut name).map_err(Error::DecodeMessage)?;
498 
499         match self.fs.unlink(
500             Context::from(in_header),
501             in_header.nodeid.into(),
502             bytes_to_cstr(&name)?,
503         ) {
504             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
505             Err(e) => reply_error(e, in_header.unique, w),
506         }
507     }
508 
rmdir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>509     fn rmdir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
510         let namelen = (in_header.len as usize)
511             .checked_sub(size_of::<InHeader>())
512             .ok_or(Error::InvalidHeaderLength)?;
513         let mut name = vec![0; namelen];
514 
515         r.read_exact(&mut name).map_err(Error::DecodeMessage)?;
516 
517         match self.fs.rmdir(
518             Context::from(in_header),
519             in_header.nodeid.into(),
520             bytes_to_cstr(&name)?,
521         ) {
522             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
523             Err(e) => reply_error(e, in_header.unique, w),
524         }
525     }
526 
do_rename<R: Reader, W: Writer>( &self, in_header: InHeader, msg_size: usize, newdir: u64, flags: u32, mut r: R, w: W, ) -> Result<usize>527     fn do_rename<R: Reader, W: Writer>(
528         &self,
529         in_header: InHeader,
530         msg_size: usize,
531         newdir: u64,
532         flags: u32,
533         mut r: R,
534         w: W,
535     ) -> Result<usize> {
536         let buflen = (in_header.len as usize)
537             .checked_sub(size_of::<InHeader>())
538             .and_then(|l| l.checked_sub(msg_size))
539             .ok_or(Error::InvalidHeaderLength)?;
540         let mut buf = vec![0; buflen];
541 
542         r.read_exact(&mut buf).map_err(Error::DecodeMessage)?;
543 
544         // We want to include the '\0' byte in the first slice.
545         let split_pos = buf
546             .iter()
547             .position(|c| *c == b'\0')
548             .map(|p| p + 1)
549             .ok_or(Error::MissingParameter)?;
550 
551         let (oldname, newname) = buf.split_at(split_pos);
552 
553         match self.fs.rename(
554             Context::from(in_header),
555             in_header.nodeid.into(),
556             bytes_to_cstr(oldname)?,
557             newdir.into(),
558             bytes_to_cstr(newname)?,
559             flags,
560         ) {
561             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
562             Err(e) => reply_error(e, in_header.unique, w),
563         }
564     }
565 
rename<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>566     fn rename<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
567         let RenameIn { newdir } = r.read_struct()?;
568 
569         self.do_rename(in_header, size_of::<RenameIn>(), newdir, 0, r, w)
570     }
571 
rename2<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>572     fn rename2<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
573         let Rename2In { newdir, flags, .. } = r.read_struct()?;
574 
575         #[allow(clippy::unnecessary_cast)]
576         let flags = flags & (libc::RENAME_EXCHANGE | libc::RENAME_NOREPLACE) as u32;
577 
578         self.do_rename(in_header, size_of::<Rename2In>(), newdir, flags, r, w)
579     }
580 
link<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>581     fn link<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
582         let LinkIn { oldnodeid } = r.read_struct()?;
583 
584         let namelen = (in_header.len as usize)
585             .checked_sub(size_of::<InHeader>())
586             .and_then(|l| l.checked_sub(size_of::<LinkIn>()))
587             .ok_or(Error::InvalidHeaderLength)?;
588         let mut name = vec![0; namelen];
589 
590         r.read_exact(&mut name).map_err(Error::DecodeMessage)?;
591 
592         match self.fs.link(
593             Context::from(in_header),
594             oldnodeid.into(),
595             in_header.nodeid.into(),
596             bytes_to_cstr(&name)?,
597         ) {
598             Ok(entry) => {
599                 let out = EntryOut::from(entry);
600 
601                 reply_ok(Some(out), None, in_header.unique, w)
602             }
603             Err(e) => reply_error(e, in_header.unique, w),
604         }
605     }
606 
open<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>607     fn open<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
608         let OpenIn { flags, .. } = r.read_struct()?;
609 
610         match self
611             .fs
612             .open(Context::from(in_header), in_header.nodeid.into(), flags)
613         {
614             Ok((handle, opts)) => {
615                 let out = OpenOut {
616                     fh: handle.map(Into::into).unwrap_or(0),
617                     open_flags: opts.bits(),
618                     ..Default::default()
619                 };
620 
621                 reply_ok(Some(out), None, in_header.unique, w)
622             }
623             Err(e) => reply_error(e, in_header.unique, w),
624         }
625     }
626 
read<R: Reader, W: ZeroCopyWriter + Writer>( &self, in_header: InHeader, mut r: R, mut w: W, ) -> Result<usize>627     fn read<R: Reader, W: ZeroCopyWriter + Writer>(
628         &self,
629         in_header: InHeader,
630         mut r: R,
631         mut w: W,
632     ) -> Result<usize> {
633         let ReadIn {
634             fh,
635             offset,
636             size,
637             read_flags,
638             lock_owner,
639             flags,
640             ..
641         } = r.read_struct()?;
642 
643         if size > self.fs.max_buffer_size() {
644             return reply_error(
645                 io::Error::from_raw_os_error(libc::ENOMEM),
646                 in_header.unique,
647                 w,
648             );
649         }
650 
651         let owner = if read_flags & READ_LOCKOWNER != 0 {
652             Some(lock_owner)
653         } else {
654             None
655         };
656 
657         // Skip for the header size to write the data first.
658         match w.write_at(size_of::<OutHeader>(), |writer| {
659             self.fs.read(
660                 Context::from(in_header),
661                 in_header.nodeid.into(),
662                 fh.into(),
663                 writer,
664                 size,
665                 offset,
666                 owner,
667                 flags,
668             )
669         }) {
670             Ok(count) => {
671                 // Don't use `reply_ok` because we need to set a custom size length for the
672                 // header.
673                 let out = OutHeader {
674                     len: (size_of::<OutHeader>() + count) as u32,
675                     error: 0,
676                     unique: in_header.unique,
677                 };
678 
679                 w.write_all(out.as_bytes()).map_err(Error::EncodeMessage)?;
680                 w.flush().map_err(Error::FlushMessage)?;
681                 Ok(out.len as usize)
682             }
683             Err(e) => reply_error(e, in_header.unique, w),
684         }
685     }
686 
write<R: Reader + ZeroCopyReader, W: Writer>( &self, in_header: InHeader, mut r: R, w: W, ) -> Result<usize>687     fn write<R: Reader + ZeroCopyReader, W: Writer>(
688         &self,
689         in_header: InHeader,
690         mut r: R,
691         w: W,
692     ) -> Result<usize> {
693         let WriteIn {
694             fh,
695             offset,
696             size,
697             write_flags,
698             lock_owner,
699             flags,
700             ..
701         } = r.read_struct()?;
702 
703         if size > self.fs.max_buffer_size() {
704             return reply_error(
705                 io::Error::from_raw_os_error(libc::ENOMEM),
706                 in_header.unique,
707                 w,
708             );
709         }
710 
711         let owner = if write_flags & WRITE_LOCKOWNER != 0 {
712             Some(lock_owner)
713         } else {
714             None
715         };
716 
717         let delayed_write = write_flags & WRITE_CACHE != 0;
718 
719         match self.fs.write(
720             Context::from(in_header),
721             in_header.nodeid.into(),
722             fh.into(),
723             r,
724             size,
725             offset,
726             owner,
727             delayed_write,
728             flags,
729         ) {
730             Ok(count) => {
731                 let out = WriteOut {
732                     size: count as u32,
733                     ..Default::default()
734                 };
735 
736                 reply_ok(Some(out), None, in_header.unique, w)
737             }
738             Err(e) => reply_error(e, in_header.unique, w),
739         }
740     }
741 
statfs<W: Writer>(&self, in_header: InHeader, w: W) -> Result<usize>742     fn statfs<W: Writer>(&self, in_header: InHeader, w: W) -> Result<usize> {
743         match self
744             .fs
745             .statfs(Context::from(in_header), in_header.nodeid.into())
746         {
747             Ok(st) => reply_ok(Some(Kstatfs::from(st)), None, in_header.unique, w),
748             Err(e) => reply_error(e, in_header.unique, w),
749         }
750     }
751 
release<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>752     fn release<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
753         let ReleaseIn {
754             fh,
755             flags,
756             release_flags,
757             lock_owner,
758         } = r.read_struct()?;
759 
760         let flush = release_flags & RELEASE_FLUSH != 0;
761         let flock_release = release_flags & RELEASE_FLOCK_UNLOCK != 0;
762         let lock_owner = if flush || flock_release {
763             Some(lock_owner)
764         } else {
765             None
766         };
767 
768         match self.fs.release(
769             Context::from(in_header),
770             in_header.nodeid.into(),
771             flags,
772             fh.into(),
773             flush,
774             flock_release,
775             lock_owner,
776         ) {
777             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
778             Err(e) => reply_error(e, in_header.unique, w),
779         }
780     }
781 
fsync<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>782     fn fsync<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
783         let FsyncIn {
784             fh, fsync_flags, ..
785         } = r.read_struct()?;
786         let datasync = fsync_flags & 0x1 != 0;
787 
788         match self.fs.fsync(
789             Context::from(in_header),
790             in_header.nodeid.into(),
791             datasync,
792             fh.into(),
793         ) {
794             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
795             Err(e) => reply_error(e, in_header.unique, w),
796         }
797     }
798 
setxattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>799     fn setxattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
800         let SetxattrIn { size, flags } = r.read_struct()?;
801 
802         // The name and value and encoded one after another and separated by a '\0' character.
803         let len = (in_header.len as usize)
804             .checked_sub(size_of::<InHeader>())
805             .and_then(|l| l.checked_sub(size_of::<SetxattrIn>()))
806             .ok_or(Error::InvalidHeaderLength)?;
807         let mut buf = vec![0; len];
808 
809         r.read_exact(&mut buf).map_err(Error::DecodeMessage)?;
810 
811         // We want to include the '\0' byte in the first slice.
812         let split_pos = buf
813             .iter()
814             .position(|c| *c == b'\0')
815             .map(|p| p + 1)
816             .ok_or(Error::MissingParameter)?;
817 
818         let (name, value) = buf.split_at(split_pos);
819 
820         if size != value.len() as u32 {
821             return Err(Error::InvalidXattrSize(size, value.len()));
822         }
823 
824         match self.fs.setxattr(
825             Context::from(in_header),
826             in_header.nodeid.into(),
827             bytes_to_cstr(name)?,
828             value,
829             flags,
830         ) {
831             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
832             Err(e) => reply_error(e, in_header.unique, w),
833         }
834     }
835 
getxattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>836     fn getxattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
837         let GetxattrIn { size, .. } = r.read_struct()?;
838 
839         let namelen = (in_header.len as usize)
840             .checked_sub(size_of::<InHeader>())
841             .and_then(|l| l.checked_sub(size_of::<GetxattrIn>()))
842             .ok_or(Error::InvalidHeaderLength)?;
843         let mut name = vec![0; namelen];
844 
845         r.read_exact(&mut name).map_err(Error::DecodeMessage)?;
846 
847         if size > self.fs.max_buffer_size() {
848             return reply_error(
849                 io::Error::from_raw_os_error(libc::ENOMEM),
850                 in_header.unique,
851                 w,
852             );
853         }
854 
855         match self.fs.getxattr(
856             Context::from(in_header),
857             in_header.nodeid.into(),
858             bytes_to_cstr(&name)?,
859             size,
860         ) {
861             Ok(GetxattrReply::Value(val)) => reply_ok(None::<u8>, Some(&val), in_header.unique, w),
862             Ok(GetxattrReply::Count(count)) => {
863                 let out = GetxattrOut {
864                     size: count,
865                     ..Default::default()
866                 };
867 
868                 reply_ok(Some(out), None, in_header.unique, w)
869             }
870             Err(e) => reply_error(e, in_header.unique, w),
871         }
872     }
873 
listxattr<R: Reader, W: Writer>( &self, in_header: InHeader, mut r: R, w: W, ) -> Result<usize>874     fn listxattr<R: Reader, W: Writer>(
875         &self,
876         in_header: InHeader,
877         mut r: R,
878         w: W,
879     ) -> Result<usize> {
880         let GetxattrIn { size, .. } = r.read_struct()?;
881 
882         if size > self.fs.max_buffer_size() {
883             return reply_error(
884                 io::Error::from_raw_os_error(libc::ENOMEM),
885                 in_header.unique,
886                 w,
887             );
888         }
889 
890         match self
891             .fs
892             .listxattr(Context::from(in_header), in_header.nodeid.into(), size)
893         {
894             Ok(ListxattrReply::Names(val)) => reply_ok(None::<u8>, Some(&val), in_header.unique, w),
895             Ok(ListxattrReply::Count(count)) => {
896                 let out = GetxattrOut {
897                     size: count,
898                     ..Default::default()
899                 };
900 
901                 reply_ok(Some(out), None, in_header.unique, w)
902             }
903             Err(e) => reply_error(e, in_header.unique, w),
904         }
905     }
906 
removexattr<R: Reader, W: Writer>( &self, in_header: InHeader, mut r: R, w: W, ) -> Result<usize>907     fn removexattr<R: Reader, W: Writer>(
908         &self,
909         in_header: InHeader,
910         mut r: R,
911         w: W,
912     ) -> Result<usize> {
913         let namelen = (in_header.len as usize)
914             .checked_sub(size_of::<InHeader>())
915             .ok_or(Error::InvalidHeaderLength)?;
916 
917         let mut buf = vec![0; namelen];
918 
919         r.read_exact(&mut buf).map_err(Error::DecodeMessage)?;
920 
921         let name = bytes_to_cstr(&buf)?;
922 
923         match self
924             .fs
925             .removexattr(Context::from(in_header), in_header.nodeid.into(), name)
926         {
927             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
928             Err(e) => reply_error(e, in_header.unique, w),
929         }
930     }
931 
flush<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>932     fn flush<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
933         let FlushIn {
934             fh,
935             unused: _,
936             padding: _,
937             lock_owner,
938         } = r.read_struct()?;
939 
940         match self.fs.flush(
941             Context::from(in_header),
942             in_header.nodeid.into(),
943             fh.into(),
944             lock_owner,
945         ) {
946             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
947             Err(e) => reply_error(e, in_header.unique, w),
948         }
949     }
950 
init<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>951     fn init<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
952         cros_tracing::trace_simple_print!("fuse server: init: in_header={:?}", in_header);
953         let InitIn {
954             major,
955             minor,
956             max_readahead,
957             flags,
958         } = r.read_struct()?;
959 
960         if major < KERNEL_VERSION {
961             error!("Unsupported fuse protocol version: {}.{}", major, minor);
962             return reply_error(
963                 io::Error::from_raw_os_error(libc::EPROTO),
964                 in_header.unique,
965                 w,
966             );
967         }
968 
969         if major > KERNEL_VERSION {
970             // Wait for the kernel to reply back with a 7.X version.
971             let out = InitOut {
972                 major: KERNEL_VERSION,
973                 minor: KERNEL_MINOR_VERSION,
974                 ..Default::default()
975             };
976 
977             return reply_ok(Some(out), None, in_header.unique, w);
978         }
979 
980         if minor < OLDEST_SUPPORTED_KERNEL_MINOR_VERSION {
981             error!(
982                 "Unsupported fuse protocol minor version: {}.{}",
983                 major, minor
984             );
985             return reply_error(
986                 io::Error::from_raw_os_error(libc::EPROTO),
987                 in_header.unique,
988                 w,
989             );
990         }
991 
992         let InitInExt { flags2, .. } =
993             if (FsOptions::from_bits_truncate(u64::from(flags)) & FsOptions::INIT_EXT).is_empty() {
994                 InitInExt::default()
995             } else {
996                 r.read_struct()?
997             };
998 
999         // These fuse features are supported by this server by default.
1000         let supported = FsOptions::ASYNC_READ
1001             | FsOptions::PARALLEL_DIROPS
1002             | FsOptions::BIG_WRITES
1003             | FsOptions::AUTO_INVAL_DATA
1004             | FsOptions::HANDLE_KILLPRIV
1005             | FsOptions::ASYNC_DIO
1006             | FsOptions::HAS_IOCTL_DIR
1007             | FsOptions::DO_READDIRPLUS
1008             | FsOptions::READDIRPLUS_AUTO
1009             | FsOptions::ATOMIC_O_TRUNC
1010             | FsOptions::MAX_PAGES
1011             | FsOptions::MAP_ALIGNMENT
1012             | FsOptions::INIT_EXT;
1013 
1014         let capable = FsOptions::from_bits_truncate(u64::from(flags) | u64::from(flags2) << 32);
1015 
1016         match self.fs.init(capable) {
1017             Ok(want) => {
1018                 let mut enabled = capable & (want | supported);
1019 
1020                 // HANDLE_KILLPRIV doesn't work correctly when writeback caching is enabled so turn
1021                 // it off.
1022                 if enabled.contains(FsOptions::WRITEBACK_CACHE) {
1023                     enabled.remove(FsOptions::HANDLE_KILLPRIV);
1024                 }
1025 
1026                 // ATOMIC_O_TRUNC doesn't work with ZERO_MESSAGE_OPEN.
1027                 if enabled.contains(FsOptions::ZERO_MESSAGE_OPEN) {
1028                     enabled.remove(FsOptions::ATOMIC_O_TRUNC);
1029                 }
1030 
1031                 let max_write = self.fs.max_buffer_size();
1032                 let max_pages = min(
1033                     max(max_readahead, max_write) / pagesize() as u32,
1034                     u16::MAX as u32,
1035                 ) as u16;
1036                 let out = InitOut {
1037                     major: KERNEL_VERSION,
1038                     minor: KERNEL_MINOR_VERSION,
1039                     max_readahead,
1040                     flags: enabled.bits() as u32,
1041                     max_background: u16::MAX,
1042                     congestion_threshold: (u16::MAX / 4) * 3,
1043                     max_write,
1044                     time_gran: 1, // nanoseconds
1045                     max_pages,
1046                     map_alignment: pagesize().trailing_zeros() as u16,
1047                     flags2: (enabled.bits() >> 32) as u32,
1048                     ..Default::default()
1049                 };
1050 
1051                 reply_ok(Some(out), None, in_header.unique, w)
1052             }
1053             Err(e) => reply_error(e, in_header.unique, w),
1054         }
1055     }
1056 
opendir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>1057     fn opendir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
1058         let OpenIn { flags, .. } = r.read_struct()?;
1059 
1060         match self
1061             .fs
1062             .opendir(Context::from(in_header), in_header.nodeid.into(), flags)
1063         {
1064             Ok((handle, opts)) => {
1065                 let out = OpenOut {
1066                     fh: handle.map(Into::into).unwrap_or(0),
1067                     open_flags: opts.bits(),
1068                     ..Default::default()
1069                 };
1070 
1071                 reply_ok(Some(out), None, in_header.unique, w)
1072             }
1073             Err(e) => reply_error(e, in_header.unique, w),
1074         }
1075     }
1076 
readdir<R: Reader, W: Writer>( &self, in_header: InHeader, mut r: R, mut w: W, ) -> Result<usize>1077     fn readdir<R: Reader, W: Writer>(
1078         &self,
1079         in_header: InHeader,
1080         mut r: R,
1081         mut w: W,
1082     ) -> Result<usize> {
1083         let ReadIn {
1084             fh, offset, size, ..
1085         } = r.read_struct()?;
1086 
1087         if size > self.fs.max_buffer_size() {
1088             return reply_error(
1089                 io::Error::from_raw_os_error(libc::ENOMEM),
1090                 in_header.unique,
1091                 w,
1092             );
1093         }
1094 
1095         if !w.has_sufficient_buffer(size) {
1096             return reply_error(
1097                 io::Error::from_raw_os_error(libc::ENOMEM),
1098                 in_header.unique,
1099                 w,
1100             );
1101         }
1102 
1103         // Skip over enough bytes for the header.
1104         let unique = in_header.unique;
1105         let result = w.write_at(size_of::<OutHeader>(), |cursor| {
1106             match self.fs.readdir(
1107                 Context::from(in_header),
1108                 in_header.nodeid.into(),
1109                 fh.into(),
1110                 size,
1111                 offset,
1112             ) {
1113                 Ok(mut entries) => {
1114                     let mut total_written = 0;
1115                     while let Some(dirent) = entries.next() {
1116                         let remaining = (size as usize).saturating_sub(total_written);
1117                         match add_dirent(cursor, remaining, &dirent, None) {
1118                             // No more space left in the buffer.
1119                             Ok(0) => break,
1120                             Ok(bytes_written) => {
1121                                 total_written += bytes_written;
1122                             }
1123                             Err(e) => return Err(e),
1124                         }
1125                     }
1126                     Ok(total_written)
1127                 }
1128                 Err(e) => Err(e),
1129             }
1130         });
1131 
1132         match result {
1133             Ok(total_written) => reply_readdir(total_written, unique, w),
1134             Err(e) => reply_error(e, unique, w),
1135         }
1136     }
1137 
lookup_dirent_attribute( &self, in_header: &InHeader, dir_entry: &DirEntry, ) -> io::Result<Entry>1138     fn lookup_dirent_attribute(
1139         &self,
1140         in_header: &InHeader,
1141         dir_entry: &DirEntry,
1142     ) -> io::Result<Entry> {
1143         let parent = in_header.nodeid.into();
1144         let name = dir_entry.name.to_bytes();
1145         let entry = if name == b"." || name == b".." {
1146             // Don't do lookups on the current directory or the parent directory.
1147             // SAFETY: struct only contains integer fields and any value is valid.
1148             let mut attr = unsafe { MaybeUninit::<libc::stat64>::zeroed().assume_init() };
1149             attr.st_ino = dir_entry.ino;
1150             attr.st_mode = dir_entry.type_;
1151 
1152             // We use 0 for the inode value to indicate a negative entry.
1153             Entry {
1154                 inode: 0,
1155                 generation: 0,
1156                 attr,
1157                 attr_timeout: Duration::from_secs(0),
1158                 entry_timeout: Duration::from_secs(0),
1159             }
1160         } else {
1161             self.fs
1162                 .lookup(Context::from(*in_header), parent, dir_entry.name)?
1163         };
1164 
1165         Ok(entry)
1166     }
1167 
readdirplus<R: Reader, W: Writer>( &self, in_header: InHeader, mut r: R, mut w: W, ) -> Result<usize>1168     fn readdirplus<R: Reader, W: Writer>(
1169         &self,
1170         in_header: InHeader,
1171         mut r: R,
1172         mut w: W,
1173     ) -> Result<usize> {
1174         cros_tracing::trace_simple_print!("fuse server: readdirplus: in_header={:?}", in_header);
1175         let ReadIn {
1176             fh, offset, size, ..
1177         } = r.read_struct()?;
1178 
1179         if size > self.fs.max_buffer_size() {
1180             return reply_error(
1181                 io::Error::from_raw_os_error(libc::ENOMEM),
1182                 in_header.unique,
1183                 w,
1184             );
1185         }
1186 
1187         if !w.has_sufficient_buffer(size) {
1188             return reply_error(
1189                 io::Error::from_raw_os_error(libc::ENOMEM),
1190                 in_header.unique,
1191                 w,
1192             );
1193         }
1194 
1195         // Skip over enough bytes for the header.
1196         let unique = in_header.unique;
1197         let result = w.write_at(size_of::<OutHeader>(), |cursor| {
1198             match self.fs.readdir(
1199                 Context::from(in_header),
1200                 in_header.nodeid.into(),
1201                 fh.into(),
1202                 size,
1203                 offset,
1204             ) {
1205                 Ok(mut entries) => {
1206                     let mut total_written = 0;
1207                     while let Some(dirent) = entries.next() {
1208                         let mut entry_inode = None;
1209                         let dirent_result = self
1210                             .lookup_dirent_attribute(&in_header, &dirent)
1211                             .and_then(|e| {
1212                                 entry_inode = Some(e.inode);
1213                                 let remaining = (size as usize).saturating_sub(total_written);
1214                                 add_dirent(cursor, remaining, &dirent, Some(e))
1215                             });
1216 
1217                         match dirent_result {
1218                             Ok(0) => {
1219                                 // No more space left in the buffer but we need to undo the lookup
1220                                 // that created the Entry or we will end up with mismatched lookup
1221                                 // counts.
1222                                 if let Some(inode) = entry_inode {
1223                                     self.fs.forget(Context::from(in_header), inode.into(), 1);
1224                                 }
1225                                 break;
1226                             }
1227                             Ok(bytes_written) => {
1228                                 total_written += bytes_written;
1229                             }
1230                             Err(e) => {
1231                                 if let Some(inode) = entry_inode {
1232                                     self.fs.forget(Context::from(in_header), inode.into(), 1);
1233                                 }
1234 
1235                                 if total_written == 0 {
1236                                     // We haven't filled any entries yet so we can just propagate
1237                                     // the error.
1238                                     return Err(e);
1239                                 }
1240 
1241                                 // We already filled in some entries. Returning an error now will
1242                                 // cause lookup count mismatches for those entries so just return
1243                                 // whatever we already have.
1244                                 break;
1245                             }
1246                         }
1247                     }
1248                     Ok(total_written)
1249                 }
1250                 Err(e) => Err(e),
1251             }
1252         });
1253 
1254         match result {
1255             Ok(total_written) => reply_readdir(total_written, unique, w),
1256             Err(e) => reply_error(e, unique, w),
1257         }
1258     }
1259 
releasedir<R: Reader, W: Writer>( &self, in_header: InHeader, mut r: R, w: W, ) -> Result<usize>1260     fn releasedir<R: Reader, W: Writer>(
1261         &self,
1262         in_header: InHeader,
1263         mut r: R,
1264         w: W,
1265     ) -> Result<usize> {
1266         let ReleaseIn { fh, flags, .. } = r.read_struct()?;
1267 
1268         match self.fs.releasedir(
1269             Context::from(in_header),
1270             in_header.nodeid.into(),
1271             flags,
1272             fh.into(),
1273         ) {
1274             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
1275             Err(e) => reply_error(e, in_header.unique, w),
1276         }
1277     }
1278 
fsyncdir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>1279     fn fsyncdir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
1280         let FsyncIn {
1281             fh, fsync_flags, ..
1282         } = r.read_struct()?;
1283         let datasync = fsync_flags & 0x1 != 0;
1284 
1285         match self.fs.fsyncdir(
1286             Context::from(in_header),
1287             in_header.nodeid.into(),
1288             datasync,
1289             fh.into(),
1290         ) {
1291             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
1292             Err(e) => reply_error(e, in_header.unique, w),
1293         }
1294     }
1295 
getlk<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize>1296     fn getlk<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
1297         if let Err(e) = self.fs.getlk() {
1298             reply_error(e, in_header.unique, w)
1299         } else {
1300             Ok(0)
1301         }
1302     }
1303 
setlk<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize>1304     fn setlk<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
1305         if let Err(e) = self.fs.setlk() {
1306             reply_error(e, in_header.unique, w)
1307         } else {
1308             Ok(0)
1309         }
1310     }
1311 
setlkw<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize>1312     fn setlkw<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
1313         if let Err(e) = self.fs.setlkw() {
1314             reply_error(e, in_header.unique, w)
1315         } else {
1316             Ok(0)
1317         }
1318     }
1319 
access<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>1320     fn access<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
1321         let AccessIn { mask, .. } = r.read_struct()?;
1322 
1323         match self
1324             .fs
1325             .access(Context::from(in_header), in_header.nodeid.into(), mask)
1326         {
1327             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
1328             Err(e) => reply_error(e, in_header.unique, w),
1329         }
1330     }
1331 
create<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>1332     fn create<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
1333         let CreateIn {
1334             flags, mode, umask, ..
1335         } = r.read_struct()?;
1336 
1337         let buflen = (in_header.len as usize)
1338             .checked_sub(size_of::<InHeader>())
1339             .and_then(|l| l.checked_sub(size_of::<CreateIn>()))
1340             .ok_or(Error::InvalidHeaderLength)?;
1341 
1342         let mut buf = vec![0; buflen];
1343 
1344         r.read_exact(&mut buf).map_err(Error::DecodeMessage)?;
1345 
1346         let mut iter = buf.split_inclusive(|&c| c == b'\0');
1347         let name = iter
1348             .next()
1349             .ok_or(Error::MissingParameter)
1350             .and_then(bytes_to_cstr)?;
1351 
1352         let split_pos = name.to_bytes_with_nul().len();
1353         let security_ctx = parse_selinux_xattr(&buf[split_pos..])?;
1354 
1355         match self.fs.create(
1356             Context::from(in_header),
1357             in_header.nodeid.into(),
1358             name,
1359             mode,
1360             flags,
1361             umask,
1362             security_ctx,
1363         ) {
1364             Ok((entry, handle, opts)) => {
1365                 let entry_out = EntryOut {
1366                     nodeid: entry.inode,
1367                     generation: entry.generation,
1368                     entry_valid: entry.entry_timeout.as_secs(),
1369                     attr_valid: entry.attr_timeout.as_secs(),
1370                     entry_valid_nsec: entry.entry_timeout.subsec_nanos(),
1371                     attr_valid_nsec: entry.attr_timeout.subsec_nanos(),
1372                     attr: entry.attr.into(),
1373                 };
1374                 let open_out = OpenOut {
1375                     fh: handle.map(Into::into).unwrap_or(0),
1376                     open_flags: opts.bits(),
1377                     ..Default::default()
1378                 };
1379 
1380                 // Kind of a hack to write both structs.
1381                 reply_ok(
1382                     Some(entry_out),
1383                     Some(open_out.as_bytes()),
1384                     in_header.unique,
1385                     w,
1386                 )
1387             }
1388             Err(e) => reply_error(e, in_header.unique, w),
1389         }
1390     }
1391 
1392     #[allow(clippy::unnecessary_wraps)]
interrupt(&self, _in_header: InHeader) -> Result<usize>1393     fn interrupt(&self, _in_header: InHeader) -> Result<usize> {
1394         Ok(0)
1395     }
1396 
bmap<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize>1397     fn bmap<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
1398         if let Err(e) = self.fs.bmap() {
1399             reply_error(e, in_header.unique, w)
1400         } else {
1401             Ok(0)
1402         }
1403     }
1404 
1405     #[allow(clippy::unnecessary_wraps)]
destroy(&self) -> Result<usize>1406     fn destroy(&self) -> Result<usize> {
1407         // No reply to this function.
1408         self.fs.destroy();
1409 
1410         Ok(0)
1411     }
1412 
ioctl<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize>1413     fn ioctl<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
1414         let IoctlIn {
1415             fh,
1416             flags,
1417             cmd,
1418             arg,
1419             in_size,
1420             out_size,
1421         } = r.read_struct()?;
1422 
1423         let res = self.fs.ioctl(
1424             in_header.into(),
1425             in_header.nodeid.into(),
1426             fh.into(),
1427             IoctlFlags::from_bits_truncate(flags),
1428             cmd,
1429             arg,
1430             in_size,
1431             out_size,
1432             r,
1433         );
1434 
1435         match res {
1436             Ok(reply) => match reply {
1437                 IoctlReply::Retry { input, output } => {
1438                     retry_ioctl(in_header.unique, input, output, w)
1439                 }
1440                 IoctlReply::Done(res) => finish_ioctl(in_header.unique, res, w),
1441             },
1442             Err(e) => reply_error(e, in_header.unique, w),
1443         }
1444     }
1445 
poll<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize>1446     fn poll<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
1447         if let Err(e) = self.fs.poll() {
1448             reply_error(e, in_header.unique, w)
1449         } else {
1450             Ok(0)
1451         }
1452     }
1453 
notify_reply<R: Reader, W: Writer>( &self, in_header: InHeader, mut _r: R, w: W, ) -> Result<usize>1454     fn notify_reply<R: Reader, W: Writer>(
1455         &self,
1456         in_header: InHeader,
1457         mut _r: R,
1458         w: W,
1459     ) -> Result<usize> {
1460         if let Err(e) = self.fs.notify_reply() {
1461             reply_error(e, in_header.unique, w)
1462         } else {
1463             Ok(0)
1464         }
1465     }
1466 
batch_forget<R: Reader, W: Writer>( &self, in_header: InHeader, mut r: R, w: W, ) -> Result<usize>1467     fn batch_forget<R: Reader, W: Writer>(
1468         &self,
1469         in_header: InHeader,
1470         mut r: R,
1471         w: W,
1472     ) -> Result<usize> {
1473         let BatchForgetIn { count, .. } = r.read_struct()?;
1474 
1475         if let Some(size) = (count as usize).checked_mul(size_of::<ForgetOne>()) {
1476             if size > self.fs.max_buffer_size() as usize {
1477                 return reply_error(
1478                     io::Error::from_raw_os_error(libc::ENOMEM),
1479                     in_header.unique,
1480                     w,
1481                 );
1482             }
1483         } else {
1484             return reply_error(
1485                 io::Error::from_raw_os_error(libc::EOVERFLOW),
1486                 in_header.unique,
1487                 w,
1488             );
1489         }
1490 
1491         let mut requests = Vec::with_capacity(count as usize);
1492         for _ in 0..count {
1493             let f: ForgetOne = r.read_struct()?;
1494             requests.push((f.nodeid.into(), f.nlookup));
1495         }
1496 
1497         self.fs.batch_forget(Context::from(in_header), requests);
1498 
1499         // No reply for forget messages.
1500         Ok(0)
1501     }
1502 
fallocate<R: Reader, W: Writer>( &self, in_header: InHeader, mut r: R, w: W, ) -> Result<usize>1503     fn fallocate<R: Reader, W: Writer>(
1504         &self,
1505         in_header: InHeader,
1506         mut r: R,
1507         w: W,
1508     ) -> Result<usize> {
1509         let FallocateIn {
1510             fh,
1511             offset,
1512             length,
1513             mode,
1514             ..
1515         } = r.read_struct()?;
1516 
1517         match self.fs.fallocate(
1518             Context::from(in_header),
1519             in_header.nodeid.into(),
1520             fh.into(),
1521             mode,
1522             offset,
1523             length,
1524         ) {
1525             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
1526             Err(e) => reply_error(e, in_header.unique, w),
1527         }
1528     }
1529 
lseek<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize>1530     fn lseek<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
1531         if let Err(e) = self.fs.lseek() {
1532             reply_error(e, in_header.unique, w)
1533         } else {
1534             Ok(0)
1535         }
1536     }
1537 
copy_file_range<R: Reader, W: Writer>( &self, in_header: InHeader, mut r: R, w: W, ) -> Result<usize>1538     fn copy_file_range<R: Reader, W: Writer>(
1539         &self,
1540         in_header: InHeader,
1541         mut r: R,
1542         w: W,
1543     ) -> Result<usize> {
1544         let CopyFileRangeIn {
1545             fh_src,
1546             off_src,
1547             nodeid_dst,
1548             fh_dst,
1549             off_dst,
1550             len,
1551             flags,
1552         } = r.read_struct()?;
1553 
1554         match self.fs.copy_file_range(
1555             Context::from(in_header),
1556             in_header.nodeid.into(),
1557             fh_src.into(),
1558             off_src,
1559             nodeid_dst.into(),
1560             fh_dst.into(),
1561             off_dst,
1562             len,
1563             flags,
1564         ) {
1565             Ok(count) => {
1566                 let out = WriteOut {
1567                     size: count as u32,
1568                     ..Default::default()
1569                 };
1570 
1571                 reply_ok(Some(out), None, in_header.unique, w)
1572             }
1573             Err(e) => reply_error(e, in_header.unique, w),
1574         }
1575     }
1576 
set_up_mapping<R, W, M>( &self, in_header: InHeader, mut r: R, w: W, mapper: M, ) -> Result<usize> where R: Reader, W: Writer, M: Mapper,1577     fn set_up_mapping<R, W, M>(
1578         &self,
1579         in_header: InHeader,
1580         mut r: R,
1581         w: W,
1582         mapper: M,
1583     ) -> Result<usize>
1584     where
1585         R: Reader,
1586         W: Writer,
1587         M: Mapper,
1588     {
1589         let SetUpMappingIn {
1590             fh,
1591             foffset,
1592             len,
1593             flags,
1594             moffset,
1595         } = r.read_struct()?;
1596         let flags = SetUpMappingFlags::from_bits_truncate(flags);
1597 
1598         let mut prot = 0;
1599         if flags.contains(SetUpMappingFlags::READ) {
1600             prot |= libc::PROT_READ as u32;
1601         }
1602         if flags.contains(SetUpMappingFlags::WRITE) {
1603             prot |= libc::PROT_WRITE as u32;
1604         }
1605 
1606         let size = if let Ok(s) = len.try_into() {
1607             s
1608         } else {
1609             return reply_error(
1610                 io::Error::from_raw_os_error(libc::EOVERFLOW),
1611                 in_header.unique,
1612                 w,
1613             );
1614         };
1615 
1616         match self.fs.set_up_mapping(
1617             Context::from(in_header),
1618             in_header.nodeid.into(),
1619             fh.into(),
1620             foffset,
1621             moffset,
1622             size,
1623             prot,
1624             mapper,
1625         ) {
1626             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
1627             Err(e) => {
1628                 error!("set_up_mapping failed: {}", e);
1629                 reply_error(e, in_header.unique, w)
1630             }
1631         }
1632     }
1633 
remove_mapping<R, W, M>( &self, in_header: InHeader, mut r: R, w: W, mapper: M, ) -> Result<usize> where R: Reader, W: Writer, M: Mapper,1634     fn remove_mapping<R, W, M>(
1635         &self,
1636         in_header: InHeader,
1637         mut r: R,
1638         w: W,
1639         mapper: M,
1640     ) -> Result<usize>
1641     where
1642         R: Reader,
1643         W: Writer,
1644         M: Mapper,
1645     {
1646         let RemoveMappingIn { count } = r.read_struct()?;
1647 
1648         // `FUSE_REMOVEMAPPING_MAX_ENTRY` is defined as
1649         // `PAGE_SIZE / sizeof(struct fuse_removemapping_one)` in /kernel/include/uapi/linux/fuse.h.
1650         let max_entry = pagesize() / std::mem::size_of::<RemoveMappingOne>();
1651 
1652         if max_entry < count as usize {
1653             return reply_error(
1654                 io::Error::from_raw_os_error(libc::EINVAL),
1655                 in_header.unique,
1656                 w,
1657             );
1658         }
1659 
1660         let mut msgs = Vec::with_capacity(count as usize);
1661         for _ in 0..(count as usize) {
1662             let msg: RemoveMappingOne = r.read_struct()?;
1663             msgs.push(msg);
1664         }
1665 
1666         match self.fs.remove_mapping(&msgs, mapper) {
1667             Ok(()) => reply_ok(None::<u8>, None, in_header.unique, w),
1668             Err(e) => reply_error(e, in_header.unique, w),
1669         }
1670     }
1671 
open_atomic<R: Reader, W: Writer>( &self, in_header: InHeader, mut r: R, w: W, ) -> Result<usize>1672     fn open_atomic<R: Reader, W: Writer>(
1673         &self,
1674         in_header: InHeader,
1675         mut r: R,
1676         w: W,
1677     ) -> Result<usize> {
1678         let CreateIn {
1679             flags, mode, umask, ..
1680         } = r.read_struct()?;
1681 
1682         let buflen = (in_header.len as usize)
1683             .checked_sub(size_of::<InHeader>())
1684             .and_then(|l| l.checked_sub(size_of::<CreateIn>()))
1685             .ok_or(Error::InvalidHeaderLength)?;
1686 
1687         let mut buf = vec![0; buflen];
1688 
1689         r.read_exact(&mut buf).map_err(Error::DecodeMessage)?;
1690 
1691         let mut iter = buf.split_inclusive(|&c| c == b'\0');
1692         let name = iter
1693             .next()
1694             .ok_or(Error::MissingParameter)
1695             .and_then(bytes_to_cstr)?;
1696 
1697         let split_pos = name.to_bytes_with_nul().len();
1698         let security_ctx = parse_selinux_xattr(&buf[split_pos..])?;
1699 
1700         match self.fs.atomic_open(
1701             Context::from(in_header),
1702             in_header.nodeid.into(),
1703             name,
1704             mode,
1705             flags,
1706             umask,
1707             security_ctx,
1708         ) {
1709             Ok((entry, handle, opts)) => {
1710                 let entry_out = EntryOut {
1711                     nodeid: entry.inode,
1712                     generation: entry.generation,
1713                     entry_valid: entry.entry_timeout.as_secs(),
1714                     attr_valid: entry.attr_timeout.as_secs(),
1715                     entry_valid_nsec: entry.entry_timeout.subsec_nanos(),
1716                     attr_valid_nsec: entry.attr_timeout.subsec_nanos(),
1717                     attr: entry.attr.into(),
1718                 };
1719                 let open_out = OpenOut {
1720                     fh: handle.map(Into::into).unwrap_or(0),
1721                     open_flags: opts.bits(),
1722                     ..Default::default()
1723                 };
1724 
1725                 // open_out passed the `data` argument, but the two out structs are independent
1726                 // This is a hack to return two out stucts in one fuse reply
1727                 reply_ok(
1728                     Some(entry_out),
1729                     Some(open_out.as_bytes()),
1730                     in_header.unique,
1731                     w,
1732                 )
1733             }
1734             Err(e) => reply_error(e, in_header.unique, w),
1735         }
1736     }
1737 }
1738 
retry_ioctl<W: Writer>( unique: u64, input: Vec<IoctlIovec>, output: Vec<IoctlIovec>, mut w: W, ) -> Result<usize>1739 fn retry_ioctl<W: Writer>(
1740     unique: u64,
1741     input: Vec<IoctlIovec>,
1742     output: Vec<IoctlIovec>,
1743     mut w: W,
1744 ) -> Result<usize> {
1745     // We don't need to check for overflow here because if adding these 2 values caused an overflow
1746     // we would have run out of memory before reaching this point.
1747     if input.len() + output.len() > IOCTL_MAX_IOV {
1748         return Err(Error::TooManyIovecs(
1749             input.len() + output.len(),
1750             IOCTL_MAX_IOV,
1751         ));
1752     }
1753 
1754     let len = size_of::<OutHeader>()
1755         + size_of::<IoctlOut>()
1756         + (input.len() * size_of::<IoctlIovec>())
1757         + (output.len() * size_of::<IoctlIovec>());
1758     let header = OutHeader {
1759         len: len as u32,
1760         error: 0,
1761         unique,
1762     };
1763     let out = IoctlOut {
1764         result: 0,
1765         flags: IoctlFlags::RETRY.bits(),
1766         in_iovs: input.len() as u32,
1767         out_iovs: output.len() as u32,
1768     };
1769 
1770     let mut total_bytes = size_of::<OutHeader>() + size_of::<IoctlOut>();
1771     w.write_all(header.as_bytes())
1772         .map_err(Error::EncodeMessage)?;
1773     w.write_all(out.as_bytes()).map_err(Error::EncodeMessage)?;
1774     for i in input.into_iter().chain(output.into_iter()) {
1775         total_bytes += i.as_bytes().len();
1776         w.write_all(i.as_bytes()).map_err(Error::EncodeMessage)?;
1777     }
1778 
1779     w.flush().map_err(Error::FlushMessage)?;
1780     debug_assert_eq!(len, total_bytes);
1781     Ok(len)
1782 }
1783 
finish_ioctl<W: Writer>(unique: u64, res: io::Result<Vec<u8>>, w: W) -> Result<usize>1784 fn finish_ioctl<W: Writer>(unique: u64, res: io::Result<Vec<u8>>, w: W) -> Result<usize> {
1785     let (out, data) = match res {
1786         Ok(data) => {
1787             let out = IoctlOut {
1788                 result: 0,
1789                 ..Default::default()
1790             };
1791             (out, Some(data))
1792         }
1793         Err(e) => {
1794             let out = IoctlOut {
1795                 result: -e.raw_os_error().unwrap_or(libc::EIO),
1796                 ..Default::default()
1797             };
1798             (out, None)
1799         }
1800     };
1801     reply_ok(Some(out), data.as_ref().map(|d| &d[..]), unique, w)
1802 }
1803 
reply_readdir<W: Writer>(len: usize, unique: u64, mut w: W) -> Result<usize>1804 fn reply_readdir<W: Writer>(len: usize, unique: u64, mut w: W) -> Result<usize> {
1805     let out = OutHeader {
1806         len: (size_of::<OutHeader>() + len) as u32,
1807         error: 0,
1808         unique,
1809     };
1810 
1811     w.write_all(out.as_bytes()).map_err(Error::EncodeMessage)?;
1812     w.flush().map_err(Error::FlushMessage)?;
1813     Ok(out.len as usize)
1814 }
1815 
reply_ok<T: AsBytes, W: Writer>( out: Option<T>, data: Option<&[u8]>, unique: u64, mut w: W, ) -> Result<usize>1816 fn reply_ok<T: AsBytes, W: Writer>(
1817     out: Option<T>,
1818     data: Option<&[u8]>,
1819     unique: u64,
1820     mut w: W,
1821 ) -> Result<usize> {
1822     let mut len = size_of::<OutHeader>();
1823 
1824     if out.is_some() {
1825         len += size_of::<T>();
1826     }
1827 
1828     if let Some(data) = data {
1829         len += data.len();
1830     }
1831 
1832     let header = OutHeader {
1833         len: len as u32,
1834         error: 0,
1835         unique,
1836     };
1837 
1838     let mut total_bytes = size_of::<OutHeader>();
1839     w.write_all(header.as_bytes())
1840         .map_err(Error::EncodeMessage)?;
1841 
1842     if let Some(out) = out {
1843         total_bytes += out.as_bytes().len();
1844         w.write_all(out.as_bytes()).map_err(Error::EncodeMessage)?;
1845     }
1846 
1847     if let Some(data) = data {
1848         total_bytes += data.len();
1849         w.write_all(data).map_err(Error::EncodeMessage)?;
1850     }
1851 
1852     w.flush().map_err(Error::FlushMessage)?;
1853     debug_assert_eq!(len, total_bytes);
1854     Ok(len)
1855 }
1856 
reply_error<W: Writer>(e: io::Error, unique: u64, mut w: W) -> Result<usize>1857 fn reply_error<W: Writer>(e: io::Error, unique: u64, mut w: W) -> Result<usize> {
1858     let header = OutHeader {
1859         len: size_of::<OutHeader>() as u32,
1860         error: -e.raw_os_error().unwrap_or(libc::EIO),
1861         unique,
1862     };
1863 
1864     w.write_all(header.as_bytes())
1865         .map_err(Error::EncodeMessage)?;
1866     w.flush().map_err(Error::FlushMessage)?;
1867 
1868     Ok(header.len as usize)
1869 }
1870 
bytes_to_cstr(buf: &[u8]) -> Result<&CStr>1871 fn bytes_to_cstr(buf: &[u8]) -> Result<&CStr> {
1872     // Convert to a `CStr` first so that we can drop the '\0' byte at the end
1873     // and make sure there are no interior '\0' bytes.
1874     CStr::from_bytes_with_nul(buf).map_err(Error::InvalidCString)
1875 }
1876 
add_dirent<W: Writer>( cursor: &mut W, max: usize, d: &DirEntry, entry: Option<Entry>, ) -> io::Result<usize>1877 fn add_dirent<W: Writer>(
1878     cursor: &mut W,
1879     max: usize,
1880     d: &DirEntry,
1881     entry: Option<Entry>,
1882 ) -> io::Result<usize> {
1883     // Strip the trailing '\0'.
1884     let name = d.name.to_bytes();
1885     if name.len() > u32::MAX as usize {
1886         return Err(io::Error::from_raw_os_error(libc::EOVERFLOW));
1887     }
1888 
1889     let dirent_len = size_of::<Dirent>()
1890         .checked_add(name.len())
1891         .ok_or_else(|| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
1892 
1893     // Directory entries must be padded to 8-byte alignment.  If adding 7 causes
1894     // an overflow then this dirent cannot be properly padded.
1895     let padded_dirent_len = dirent_len
1896         .checked_add(7)
1897         .map(|l| l & !7)
1898         .ok_or_else(|| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
1899 
1900     let total_len = if entry.is_some() {
1901         padded_dirent_len
1902             .checked_add(size_of::<EntryOut>())
1903             .ok_or_else(|| io::Error::from_raw_os_error(libc::EOVERFLOW))?
1904     } else {
1905         padded_dirent_len
1906     };
1907 
1908     if max < total_len {
1909         Ok(0)
1910     } else {
1911         if let Some(entry) = entry {
1912             cursor.write_all(EntryOut::from(entry).as_bytes())?;
1913         }
1914 
1915         let dirent = Dirent {
1916             ino: d.ino,
1917             off: d.offset,
1918             namelen: name.len() as u32,
1919             type_: d.type_,
1920         };
1921 
1922         cursor.write_all(dirent.as_bytes())?;
1923         cursor.write_all(name)?;
1924 
1925         // We know that `dirent_len` <= `padded_dirent_len` due to the check above
1926         // so there's no need for checked arithmetic.
1927         let padding = padded_dirent_len - dirent_len;
1928         if padding > 0 {
1929             cursor.write_all(&DIRENT_PADDING[..padding])?;
1930         }
1931 
1932         Ok(total_len)
1933     }
1934 }
1935 
1936 /// Parses the value of the desired attribute from the FUSE request input and returns it as an
1937 /// `Ok(CStr)`. Returns `Ok(None)` if `buf` is empty or appears to be a valid request extension that
1938 /// does not contain any security context information.
1939 ///
1940 /// # Arguments
1941 ///
1942 /// * `buf` - a byte array that contains the contents following any expected byte string parameters
1943 ///   of the FUSE request from the server. It begins with a struct `SecctxHeader`, and then the
1944 ///   subsequent entry is a struct `Secctx` followed by a nul-terminated string with the xattribute
1945 ///   name and then another nul-terminated string with the value for that xattr.
1946 ///
1947 /// # Errors
1948 ///
1949 /// * `Error::InvalidHeaderLength` - indicates that there is an inconsistency between the size of
1950 ///   the data read from `buf` and the stated `size` of the `SecctxHeader`, the respective `Secctx`
1951 ///   struct, or `buf` itself.
1952 /// * `Error::DecodeMessage` - indicates that the expected structs cannot be read from `buf`.
1953 /// * `Error::MissingParameter` - indicates that either a security context `name` or `value` is
1954 ///   missing from a security context entry.
parse_selinux_xattr(buf: &[u8]) -> Result<Option<&CStr>>1955 fn parse_selinux_xattr(buf: &[u8]) -> Result<Option<&CStr>> {
1956     // Return early if request was not followed by context information
1957     if buf.is_empty() {
1958         return Ok(None);
1959     } else if buf.len() < size_of::<SecctxHeader>() {
1960         return Err(Error::InvalidHeaderLength);
1961     }
1962 
1963     // Because the security context data block may have been preceded by variable-length strings,
1964     // `SecctxHeader` and the subsequent `Secctx` structs may not be correctly byte-aligned
1965     // within `buf`.
1966     let secctx_header = SecctxHeader::read_from_prefix(buf).ok_or(Error::DecodeMessage(
1967         io::Error::from_raw_os_error(libc::EINVAL),
1968     ))?;
1969 
1970     // FUSE 7.38 introduced a generic request extension with the same structure as  `SecctxHeader`.
1971     // A `nr_secctx` value above `MAX_NR_SECCTX` indicates that this data block does not contain
1972     // any security context information.
1973     if secctx_header.nr_secctx > MAX_NR_SECCTX {
1974         return Ok(None);
1975     }
1976 
1977     let mut cur_secctx_pos = size_of::<SecctxHeader>();
1978     for _ in 0..secctx_header.nr_secctx {
1979         // `SecctxHeader.size` denotes the total size for the `SecctxHeader`, each of the
1980         // `nr_secctx` `Secctx` structs along with the corresponding context name and value,
1981         // and any additional padding.
1982         if (cur_secctx_pos + size_of::<Secctx>()) > buf.len()
1983             || (cur_secctx_pos + size_of::<Secctx>()) > secctx_header.size as usize
1984         {
1985             return Err(Error::InvalidHeaderLength);
1986         }
1987 
1988         let secctx =
1989             Secctx::read_from(&buf[cur_secctx_pos..(cur_secctx_pos + size_of::<Secctx>())]).ok_or(
1990                 Error::DecodeMessage(io::Error::from_raw_os_error(libc::EINVAL)),
1991             )?;
1992 
1993         cur_secctx_pos += size_of::<Secctx>();
1994 
1995         let secctx_data = &buf[cur_secctx_pos..]
1996             .split_inclusive(|&c| c == b'\0')
1997             .take(2)
1998             .map(bytes_to_cstr)
1999             .collect::<Result<Vec<&CStr>>>()?;
2000 
2001         if secctx_data.len() != 2 {
2002             return Err(Error::MissingParameter);
2003         }
2004 
2005         let name = secctx_data[0];
2006         let value = secctx_data[1];
2007 
2008         cur_secctx_pos += name.to_bytes_with_nul().len() + value.to_bytes_with_nul().len();
2009         if cur_secctx_pos > secctx_header.size as usize {
2010             return Err(Error::InvalidHeaderLength);
2011         }
2012 
2013         // `Secctx.size` contains the size of the security context value (not including the
2014         // corresponding context name).
2015         if value.to_bytes_with_nul().len() as u32 != secctx.size {
2016             return Err(Error::InvalidHeaderLength);
2017         }
2018 
2019         if name.to_bytes_with_nul() == SELINUX_XATTR_CSTR {
2020             return Ok(Some(value));
2021         }
2022     }
2023 
2024     // `SecctxHeader.size` is always the total size of the security context data padded to an
2025     // 8-byte alignment. If adding 7 causes an overflow, then the `size` field of our header
2026     // is invalid, so we should return an error.
2027     let padded_secctx_size = cur_secctx_pos
2028         .checked_add(7)
2029         .map(|l| l & !7)
2030         .ok_or_else(|| Error::InvalidHeaderLength)?;
2031     if padded_secctx_size != secctx_header.size as usize {
2032         return Err(Error::InvalidHeaderLength);
2033     }
2034 
2035     // None of the `nr_secctx` attributes we parsed had a `name` matching `SELINUX_XATTR_CSTR`.
2036     // Return `Ok(None)` to indicate that the security context data block was valid but there was no
2037     // specified selinux label attached to this request.
2038     Ok(None)
2039 }
2040 
2041 #[cfg(test)]
2042 mod tests {
2043     use super::*;
2044 
create_secctx(ctxs: &[(&[u8], &[u8])], size_truncation: u32) -> Vec<u8>2045     fn create_secctx(ctxs: &[(&[u8], &[u8])], size_truncation: u32) -> Vec<u8> {
2046         let nr_secctx = ctxs.len();
2047         let total_size = (size_of::<SecctxHeader>() as u32
2048             + (size_of::<Secctx>() * nr_secctx) as u32
2049             + ctxs
2050                 .iter()
2051                 .fold(0, |s, &(n, v)| s + n.len() as u32 + v.len() as u32))
2052         .checked_add(7)
2053         .map(|l| l & !7)
2054         .expect("total_size padded to 8-byte boundary")
2055         .checked_sub(size_truncation)
2056         .expect("size truncated by bytes < total_size");
2057 
2058         let ctx_data: Vec<_> = ctxs
2059             .iter()
2060             .map(|(n, v)| {
2061                 [
2062                     Secctx {
2063                         size: v.len() as u32,
2064                         padding: 0,
2065                     }
2066                     .as_bytes(),
2067                     n,
2068                     v,
2069                 ]
2070                 .concat()
2071             })
2072             .collect::<Vec<_>>()
2073             .concat();
2074 
2075         [
2076             SecctxHeader {
2077                 size: total_size,
2078                 nr_secctx: nr_secctx as u32,
2079             }
2080             .as_bytes(),
2081             ctx_data.as_slice(),
2082         ]
2083         .concat()
2084     }
2085 
2086     #[test]
parse_selinux_xattr_empty()2087     fn parse_selinux_xattr_empty() {
2088         let v: Vec<u8> = vec![];
2089         let res = parse_selinux_xattr(&v);
2090         assert_eq!(res.unwrap(), None);
2091     }
2092 
2093     #[test]
parse_selinux_xattr_basic()2094     fn parse_selinux_xattr_basic() {
2095         let sec_value = CStr::from_bytes_with_nul(b"user_u:object_r:security_type:s0\0").unwrap();
2096         let v = create_secctx(&[(SELINUX_XATTR_CSTR, sec_value.to_bytes_with_nul())], 0);
2097 
2098         let res = parse_selinux_xattr(&v);
2099         assert_eq!(res.unwrap(), Some(sec_value));
2100     }
2101 
2102     #[test]
parse_selinux_xattr_find_attr()2103     fn parse_selinux_xattr_find_attr() {
2104         let foo_value: &CStr =
2105             CStr::from_bytes_with_nul(b"user_foo:object_foo:foo_type:s0\0").unwrap();
2106         let sec_value: &CStr =
2107             CStr::from_bytes_with_nul(b"user_u:object_r:security_type:s0\0").unwrap();
2108         let v = create_secctx(
2109             &[
2110                 (b"foo\0", foo_value.to_bytes_with_nul()),
2111                 (SELINUX_XATTR_CSTR, sec_value.to_bytes_with_nul()),
2112             ],
2113             0,
2114         );
2115 
2116         let res = parse_selinux_xattr(&v);
2117         assert_eq!(res.unwrap(), Some(sec_value));
2118     }
2119 
2120     #[test]
parse_selinux_xattr_wrong_attr()2121     fn parse_selinux_xattr_wrong_attr() {
2122         // Test with an xattr name that looks similar to security.selinux, but has extra
2123         // characters to ensure that `parse_selinux_xattr` will not return the associated
2124         // context value to the caller.
2125         let invalid_selinux_value: &CStr =
2126             CStr::from_bytes_with_nul(b"user_invalid:object_invalid:invalid_type:s0\0").unwrap();
2127         let v = create_secctx(
2128             &[(
2129                 b"invalid.security.selinux\0",
2130                 invalid_selinux_value.to_bytes_with_nul(),
2131             )],
2132             0,
2133         );
2134 
2135         let res = parse_selinux_xattr(&v);
2136         assert_eq!(res.unwrap(), None);
2137     }
2138 
2139     #[test]
parse_selinux_xattr_too_short()2140     fn parse_selinux_xattr_too_short() {
2141         // Test that parse_selinux_xattr will return an `Error::InvalidHeaderLength` when
2142         // the total size in the `SecctxHeader` does not encompass the entirety of the
2143         // associated data.
2144         let foo_value: &CStr =
2145             CStr::from_bytes_with_nul(b"user_foo:object_foo:foo_type:s0\0").unwrap();
2146         let sec_value: &CStr =
2147             CStr::from_bytes_with_nul(b"user_u:object_r:security_type:s0\0").unwrap();
2148         let v = create_secctx(
2149             &[
2150                 (b"foo\0", foo_value.to_bytes_with_nul()),
2151                 (SELINUX_XATTR_CSTR, sec_value.to_bytes_with_nul()),
2152             ],
2153             8,
2154         );
2155 
2156         let res = parse_selinux_xattr(&v);
2157         assert!(matches!(res, Err(Error::InvalidHeaderLength)));
2158     }
2159 }
2160