fuse/
request.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#[macro_use]
5mod macros;
6
7use crate::protocol::*;
8use std::io;
9use zerocopy::FromBytes;
10use zerocopy::Immutable;
11use zerocopy::IntoBytes;
12use zerocopy::KnownLayout;
13
14// Define an enum for all operations and their arguments.
15fuse_operations! {
16    FUSE_LOOKUP Lookup name:name;
17    FUSE_FORGET Forget arg:fuse_forget_in;
18    FUSE_GETATTR GetAttr arg:fuse_getattr_in;
19    FUSE_SETATTR SetAttr arg:fuse_setattr_in;
20    FUSE_READLINK ReadLink;
21    FUSE_SYMLINK Symlink name:name target:str;
22    FUSE_MKNOD MkNod arg:fuse_mknod_in name:name;
23    FUSE_MKDIR MkDir arg:fuse_mkdir_in name:name;
24    FUSE_UNLINK Unlink name:name;
25    FUSE_RMDIR RmDir name:name;
26    FUSE_RENAME Rename arg:fuse_rename_in name:name new_name:name;
27    FUSE_LINK Link arg:fuse_link_in name:name;
28    FUSE_OPEN Open arg:fuse_open_in;
29    FUSE_READ Read arg:fuse_read_in;
30    FUSE_WRITE Write arg:fuse_write_in data:[u8; arg.size];
31    FUSE_STATFS StatFs;
32    FUSE_RELEASE Release arg:fuse_release_in;
33    FUSE_FSYNC FSync arg:fuse_fsync_in;
34    FUSE_SETXATTR SetXAttr arg:fuse_setxattr_in name:str value:[u8; arg.size];
35    FUSE_GETXATTR GetXAttr arg:fuse_getxattr_in name:str;
36    FUSE_LISTXATTR ListXAttr arg:fuse_getxattr_in;
37    FUSE_REMOVEXATTR RemoveXAttr name:str;
38    FUSE_FLUSH Flush arg:fuse_flush_in;
39    FUSE_INIT Init arg:fuse_init_in;
40    FUSE_OPENDIR OpenDir arg:fuse_open_in;
41    FUSE_READDIR ReadDir arg:fuse_read_in;
42    FUSE_RELEASEDIR ReleaseDir arg:fuse_release_in;
43    FUSE_FSYNCDIR FSyncDir arg:fuse_fsync_in;
44    FUSE_GETLK GetLock arg:fuse_lk_in;
45    FUSE_SETLK SetLock arg:fuse_lk_in;
46    FUSE_SETLKW SetLockSleep arg:fuse_lk_in;
47    FUSE_ACCESS Access arg:fuse_access_in;
48    FUSE_CREATE Create arg:fuse_create_in name:str;
49    FUSE_INTERRUPT Interrupt arg:fuse_interrupt_in;
50    FUSE_BMAP BMap arg:fuse_bmap_in;
51    FUSE_DESTROY Destroy;
52    FUSE_IOCTL Ioctl arg:fuse_ioctl_in data:[u8; arg.in_size];
53    FUSE_POLL Poll arg:fuse_poll_in;
54    FUSE_NOTIFY_REPLY NotifyReply arg:fuse_notify_retrieve_in data:[u8];
55    FUSE_BATCH_FORGET BatchForget arg:fuse_batch_forget_in nodes:[u8];
56    FUSE_FALLOCATE FAllocate arg:fuse_fallocate_in;
57    FUSE_READDIRPLUS ReadDirPlus arg:fuse_read_in;
58    FUSE_RENAME2 Rename2 arg:fuse_rename2_in name:name new_name:name;
59    FUSE_LSEEK LSeek arg:fuse_lseek_in;
60    FUSE_COPY_FILE_RANGE CopyFileRange arg:fuse_copy_file_range_in;
61    FUSE_SETUPMAPPING SetupMapping arg:fuse_setupmapping_in;
62    FUSE_REMOVEMAPPING RemoveMapping arg:fuse_removemapping_in mappings:[u8];
63    FUSE_SYNCFS SyncFs _arg:fuse_syncfs_in;
64    FUSE_CANONICAL_PATH CanonicalPath;
65}
66
67/// A request received from the FUSE kernel module.
68pub struct Request {
69    header: fuse_in_header,
70    operation: FuseOperation,
71}
72
73impl Request {
74    /// Create a new request from the specified data.
75    pub fn new(mut reader: impl RequestReader) -> lx::Result<Self> {
76        let header: fuse_in_header = reader.read_type()?;
77        let operation = Self::read_operation(&header, reader);
78
79        Ok(Self { header, operation })
80    }
81
82    /// Gets the FUSE opcode for this request.
83    pub fn opcode(&self) -> u32 {
84        self.header.opcode
85    }
86
87    /// Gets the unique identifier of this request.
88    pub fn unique(&self) -> u64 {
89        self.header.unique
90    }
91
92    /// Gets the FUSE node ID of the inode that this request is for.
93    pub fn node_id(&self) -> u64 {
94        self.header.nodeid
95    }
96
97    /// Gets the user ID of the user that issued this request.
98    pub fn uid(&self) -> lx::uid_t {
99        self.header.uid
100    }
101
102    /// Gets the group ID of the user that issued this request.
103    pub fn gid(&self) -> lx::gid_t {
104        self.header.gid
105    }
106
107    /// Gets the process ID of the process that issued this request.
108    pub fn pid(&self) -> u32 {
109        self.header.pid
110    }
111
112    /// Gets the operation that this request should perform.
113    pub fn operation(&self) -> &FuseOperation {
114        &self.operation
115    }
116
117    /// Log the request.
118    pub fn log(&self) {
119        tracing::trace!(
120            unique = self.unique(),
121            node_id = self.node_id(),
122            uid = self.uid(),
123            gid = self.gid(),
124            pid = self.pid(),
125            operation = ?self.operation,
126            "Request",
127        );
128    }
129
130    fn read_operation(header: &fuse_in_header, reader: impl RequestReader) -> FuseOperation {
131        if header.len as usize > reader.remaining_len() + size_of_val(header) {
132            tracing::error!(
133                opcode = header.opcode,
134                unique = header.unique,
135                header_len = header.len,
136                len = reader.remaining_len() + size_of_val(header),
137                "Invalid message length",
138            );
139
140            return FuseOperation::Invalid;
141        }
142
143        match FuseOperation::read(header.opcode, reader) {
144            Ok(operation) => operation,
145            Err(e) => {
146                tracing::error!(
147                    opcode = header.opcode,
148                    unique = header.unique,
149                    error = &e as &dyn std::error::Error,
150                    "Invalid message payload",
151                );
152
153                FuseOperation::Invalid
154            }
155        }
156    }
157}
158
159/// Helpers to parse FUSE messages.
160pub trait RequestReader: io::Read {
161    /// Read until a matching byte is found.
162    ///
163    /// This should advance the read position beyond the matching byte, and return the data up to
164    /// (but not including) the matching byte.
165    ///
166    /// This is used to read NULL-terminated strings.
167    fn read_until(&mut self, byte: u8) -> lx::Result<Vec<u8>>;
168
169    /// Gets the remaining, unread length of the input data.
170    fn remaining_len(&self) -> usize;
171
172    /// Consume the next `count` bytes.
173    fn read_count(&mut self, count: usize) -> lx::Result<Box<[u8]>> {
174        let mut buffer = vec![0u8; count];
175        self.read_exact(&mut buffer)?;
176        Ok(buffer.into_boxed_slice())
177    }
178
179    /// Read all the remaining data.
180    fn read_all(&mut self) -> lx::Result<Box<[u8]>> {
181        self.read_count(self.remaining_len())
182    }
183
184    /// Read a struct of type `T`.
185    fn read_type<T: IntoBytes + FromBytes + Immutable + KnownLayout>(&mut self) -> lx::Result<T> {
186        let mut value: T = T::new_zeroed();
187        self.read_exact(value.as_mut_bytes())?;
188        Ok(value)
189    }
190
191    /// Read a NULL-terminated string
192    fn string(&mut self) -> lx::Result<lx::LxString> {
193        let buffer = self.read_until(b'\0')?;
194        Ok(lx::LxString::from_vec(buffer))
195    }
196
197    /// Read a NULL-terminated string and ensure it's a valid path name component.
198    fn name(&mut self) -> lx::Result<lx::LxString> {
199        let name = self.string()?;
200        if name.is_empty() || name == "." || name == ".." || name.as_bytes().contains(&b'/') {
201            return Err(lx::Error::EINVAL);
202        }
203
204        Ok(name)
205    }
206}
207
208impl RequestReader for &[u8] {
209    fn read_until(&mut self, byte: u8) -> lx::Result<Vec<u8>> {
210        let length = self
211            .iter()
212            .position(|&c| c == byte)
213            .ok_or(lx::Error::EINVAL)?;
214
215        let result = Vec::from(&self[..length]);
216        *self = &self[length + 1..];
217        Ok(result)
218    }
219
220    fn remaining_len(&self) -> usize {
221        self.len()
222    }
223}
224
225#[cfg(test)]
226pub(crate) mod tests {
227    use super::*;
228
229    #[test]
230    fn parse_init() {
231        let request = Request::new(FUSE_INIT_REQUEST).unwrap();
232        check_header(&request, 1, FUSE_INIT, 0);
233        if let FuseOperation::Init { arg } = request.operation {
234            assert_eq!(arg.major, 7);
235            assert_eq!(arg.minor, 27);
236            assert_eq!(arg.max_readahead, 131072);
237            assert_eq!(arg.flags, 0x3FFFFB);
238        } else {
239            panic!("Incorrect operation {:?}", request.operation);
240        }
241    }
242
243    #[test]
244    fn parse_get_attr() {
245        let request = Request::new(FUSE_GETATTR_REQUEST).unwrap();
246        check_header(&request, 2, FUSE_GETATTR, 1);
247        if let FuseOperation::GetAttr { arg } = request.operation {
248            assert_eq!(arg.fh, 0);
249            assert_eq!(arg.getattr_flags, 0);
250        } else {
251            panic!("Incorrect operation {:?}", request.operation);
252        }
253    }
254
255    #[test]
256    fn parse_lookup() {
257        let request = Request::new(FUSE_LOOKUP_REQUEST).unwrap();
258        check_header(&request, 3, FUSE_LOOKUP, 1);
259        if let FuseOperation::Lookup { name } = request.operation {
260            assert_eq!(name, "hello");
261        } else {
262            panic!("Incorrect operation {:?}", request.operation);
263        }
264    }
265
266    #[test]
267    fn parse_open() {
268        let request = Request::new(FUSE_OPEN_REQUEST).unwrap();
269        check_header(&request, 4, FUSE_OPEN, 2);
270        if let FuseOperation::Open { arg } = request.operation {
271            assert_eq!(arg.flags, 0x8000);
272        } else {
273            panic!("Incorrect operation {:?}", request.operation);
274        }
275    }
276
277    #[test]
278    fn parse_read() {
279        let request = Request::new(FUSE_READ_REQUEST).unwrap();
280        check_header(&request, 5, FUSE_READ, 2);
281        if let FuseOperation::Read { arg } = request.operation {
282            assert_eq!(arg.fh, 1);
283            assert_eq!(arg.offset, 0);
284            assert_eq!(arg.size, 4096);
285            assert_eq!(arg.read_flags, 0);
286            assert_eq!(arg.lock_owner, 0);
287            assert_eq!(arg.flags, 0x8000);
288        } else {
289            panic!("Incorrect operation {:?}", request.operation);
290        }
291    }
292
293    #[test]
294    fn parse_flush() {
295        let request = Request::new(FUSE_FLUSH_REQUEST).unwrap();
296        check_header(&request, 7, FUSE_FLUSH, 2);
297        if let FuseOperation::Flush { arg } = request.operation {
298            assert_eq!(arg.fh, 1);
299            // This was copied from a real fuse request; I have no idea why it sends this number
300            // for lock owner especially since locks were not being used.
301            assert_eq!(arg.lock_owner, 13021892616250331871);
302        } else {
303            panic!("Incorrect operation {:?}", request.operation);
304        }
305    }
306
307    #[test]
308    fn parse_release() {
309        let request = Request::new(FUSE_RELEASE_REQUEST).unwrap();
310        check_header(&request, 8, FUSE_RELEASE, 2);
311        if let FuseOperation::Release { arg } = request.operation {
312            assert_eq!(arg.fh, 1);
313            assert_eq!(arg.flags, 0x8000);
314            assert_eq!(arg.release_flags, 0);
315            assert_eq!(arg.lock_owner, 0);
316        } else {
317            panic!("Incorrect operation {:?}", request.operation);
318        }
319    }
320
321    #[test]
322    fn parse_opendir() {
323        let request = Request::new(FUSE_OPENDIR_REQUEST).unwrap();
324        check_header(&request, 9, FUSE_OPENDIR, 1);
325        if let FuseOperation::OpenDir { arg } = request.operation {
326            assert_eq!(arg.flags, 0x18800);
327        } else {
328            panic!("Incorrect operation {:?}", request.operation);
329        }
330    }
331
332    #[test]
333    fn parse_readdir() {
334        let request = Request::new(FUSE_READDIR_REQUEST).unwrap();
335        check_header(&request, 11, FUSE_READDIR, 1);
336        if let FuseOperation::ReadDir { arg } = request.operation {
337            assert_eq!(arg.fh, 0);
338            assert_eq!(arg.offset, 3);
339            assert_eq!(arg.size, 4096);
340            assert_eq!(arg.read_flags, 0);
341            assert_eq!(arg.lock_owner, 0);
342            assert_eq!(arg.flags, 0x18800);
343        } else {
344            panic!("Incorrect operation {:?}", request.operation);
345        }
346    }
347
348    #[test]
349    fn parse_releasedir() {
350        let request = Request::new(FUSE_RELEASEDIR_REQUEST).unwrap();
351        check_header(&request, 12, FUSE_RELEASEDIR, 1);
352        if let FuseOperation::ReleaseDir { arg } = request.operation {
353            assert_eq!(arg.fh, 0);
354            assert_eq!(arg.flags, 0x18800);
355            assert_eq!(arg.release_flags, 0);
356            assert_eq!(arg.lock_owner, 0);
357        } else {
358            panic!("Incorrect operation {:?}", request.operation);
359        }
360    }
361
362    fn check_header(request: &Request, unique: u64, opcode: u32, ino: u64) {
363        assert_eq!(request.unique(), unique);
364        assert_eq!(request.opcode(), opcode);
365        assert_eq!(request.node_id(), ino);
366        assert_eq!(request.uid(), 0);
367        assert_eq!(request.gid(), 0);
368        assert_eq!(
369            request.pid(),
370            if opcode == FUSE_INIT || opcode == FUSE_RELEASE || opcode == FUSE_RELEASEDIR {
371                0
372            } else {
373                971
374            }
375        );
376    }
377
378    pub const FUSE_INIT_REQUEST: &[u8] = &[
379        56, 0, 0, 0, 26, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
380        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 27, 0, 0, 0, 0, 0, 2, 0, 251, 255, 63, 0,
381    ];
382
383    pub const FUSE_GETATTR_REQUEST: &[u8] = &[
384        56, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385        0, 0, 203, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
386    ];
387
388    pub const FUSE_LOOKUP_REQUEST: &[u8] = &[
389        46, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
390        0, 0, 203, 3, 0, 0, 0, 0, 0, 0, 104, 101, 108, 108, 111, 0,
391    ];
392
393    const FUSE_OPEN_REQUEST: &[u8] = &[
394        48, 0, 0, 0, 14, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
395        0, 0, 203, 3, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0,
396    ];
397
398    const FUSE_READ_REQUEST: &[u8] = &[
399        80, 0, 0, 0, 15, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
400        0, 0, 203, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0,
401        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0,
402    ];
403
404    const FUSE_FLUSH_REQUEST: &[u8] = &[
405        64, 0, 0, 0, 25, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
406        0, 0, 203, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 18,
407        226, 110, 87, 14, 183, 180,
408    ];
409
410    const FUSE_RELEASE_REQUEST: &[u8] = &[
411        64, 0, 0, 0, 18, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
412        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
413        0, 0, 0, 0,
414    ];
415
416    const FUSE_OPENDIR_REQUEST: &[u8] = &[
417        48, 0, 0, 0, 27, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
418        0, 0, 203, 3, 0, 0, 0, 0, 0, 0, 0, 136, 1, 0, 0, 0, 0, 0,
419    ];
420
421    const FUSE_READDIR_REQUEST: &[u8] = &[
422        80, 0, 0, 0, 28, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
423        0, 0, 0, 203, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 16,
424        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 1, 0, 0, 0, 0, 0,
425    ];
426
427    const FUSE_RELEASEDIR_REQUEST: &[u8] = &[
428        64, 0, 0, 0, 29, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
429        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 1, 0, 0, 0, 0, 0, 0, 0, 0,
430        0, 0, 0, 0, 0,
431    ];
432}