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