Coverage Report

Created: 2026-02-14 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}