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