fs: Include Inode in ioctl parameters

When the file system implements zero message open support, the file
handle is meaningless and it needs to know the inode of the
file/directory on which the ioctl was called.

BUG=b:180565632
TEST=lsattr, chattr, both work when zero message open is enabled.
     Android's FileBasedEncryptionPolicyTest[0] gets ENOTTY as an error
     instead of EBADF

[0]: https://android.googlesource.com/platform/cts/+/bfbc00c20d0c3f659c16b8df652155df0e7a229a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp

Change-Id: Ic55ee95df928d645874dd8a9c7dc579b708927fa
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2706370
Tested-by: Chirantan Ekbote <chirantan@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Auto-Submit: Chirantan Ekbote <chirantan@chromium.org>
Commit-Queue: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: kokoro <noreply+kokoro@google.com>
diff --git a/devices/src/virtio/fs/passthrough.rs b/devices/src/virtio/fs/passthrough.rs
index 925bc34..2bf9150 100644
--- a/devices/src/virtio/fs/passthrough.rs
+++ b/devices/src/virtio/fs/passthrough.rs
@@ -885,15 +885,15 @@
 
     fn get_encryption_policy_ex<R: io::Read>(
         &self,
+        inode: Inode,
         handle: Handle,
         mut r: R,
     ) -> io::Result<IoctlReply> {
-        let data = self
-            .handles
-            .lock()
-            .get(&handle)
-            .map(Arc::clone)
-            .ok_or_else(ebadf)?;
+        let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
+            self.find_inode(inode)?
+        } else {
+            self.find_handle(handle, inode)?
+        };
 
         // Safe because this only has integer fields.
         let mut arg = unsafe { MaybeUninit::<fscrypt_get_policy_ex_arg>::zeroed().assume_init() };
@@ -902,10 +902,9 @@
         let policy_size = cmp::min(arg.policy_size, size_of::<fscrypt_policy>() as u64);
         arg.policy_size = policy_size;
 
-        let file = data.file.lock();
         // Safe because the kernel will only write to `arg` and we check the return value.
         let res =
-            unsafe { ioctl_with_mut_ptr(&*file, FS_IOC_GET_ENCRYPTION_POLICY_EX(), &mut arg) };
+            unsafe { ioctl_with_mut_ptr(&*data, FS_IOC_GET_ENCRYPTION_POLICY_EX(), &mut arg) };
         if res < 0 {
             Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
         } else {
@@ -914,19 +913,17 @@
         }
     }
 
-    fn get_fsxattr(&self, handle: Handle) -> io::Result<IoctlReply> {
-        let data = self
-            .handles
-            .lock()
-            .get(&handle)
-            .map(Arc::clone)
-            .ok_or_else(ebadf)?;
+    fn get_fsxattr(&self, inode: Inode, handle: Handle) -> io::Result<IoctlReply> {
+        let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
+            self.find_inode(inode)?
+        } else {
+            self.find_handle(handle, inode)?
+        };
 
         let mut buf = MaybeUninit::<fsxattr>::zeroed();
-        let file = data.file.lock();
 
         // Safe because the kernel will only write to `buf` and we check the return value.
-        let res = unsafe { ioctl_with_mut_ptr(&*file, FS_IOC_FSGETXATTR(), buf.as_mut_ptr()) };
+        let res = unsafe { ioctl_with_mut_ptr(&*data, FS_IOC_FSGETXATTR(), buf.as_mut_ptr()) };
         if res < 0 {
             Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
         } else {
@@ -936,19 +933,22 @@
         }
     }
 
-    fn set_fsxattr<R: io::Read>(&self, handle: Handle, r: R) -> io::Result<IoctlReply> {
-        let data = self
-            .handles
-            .lock()
-            .get(&handle)
-            .map(Arc::clone)
-            .ok_or_else(ebadf)?;
+    fn set_fsxattr<R: io::Read>(
+        &self,
+        inode: Inode,
+        handle: Handle,
+        r: R,
+    ) -> io::Result<IoctlReply> {
+        let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
+            self.find_inode(inode)?
+        } else {
+            self.find_handle(handle, inode)?
+        };
 
         let attr = fsxattr::from_reader(r)?;
-        let file = data.file.lock();
 
         //  Safe because this doesn't modify any memory and we check the return value.
-        let res = unsafe { ioctl_with_ptr(&*file, FS_IOC_FSSETXATTR(), &attr) };
+        let res = unsafe { ioctl_with_ptr(&*data, FS_IOC_FSSETXATTR(), &attr) };
         if res < 0 {
             Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
         } else {
@@ -956,20 +956,18 @@
         }
     }
 
-    fn get_flags(&self, handle: Handle) -> io::Result<IoctlReply> {
-        let data = self
-            .handles
-            .lock()
-            .get(&handle)
-            .map(Arc::clone)
-            .ok_or_else(ebadf)?;
+    fn get_flags(&self, inode: Inode, handle: Handle) -> io::Result<IoctlReply> {
+        let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
+            self.find_inode(inode)?
+        } else {
+            self.find_handle(handle, inode)?
+        };
 
         // The ioctl encoding is a long but the parameter is actually an int.
         let mut flags: c_int = 0;
-        let file = data.file.lock();
 
         // Safe because the kernel will only write to `flags` and we check the return value.
-        let res = unsafe { ioctl_with_mut_ptr(&*file, FS_IOC_GETFLAGS(), &mut flags) };
+        let res = unsafe { ioctl_with_mut_ptr(&*data, FS_IOC_GETFLAGS(), &mut flags) };
         if res < 0 {
             Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
         } else {
@@ -977,20 +975,18 @@
         }
     }
 
-    fn set_flags<R: io::Read>(&self, handle: Handle, r: R) -> io::Result<IoctlReply> {
-        let data = self
-            .handles
-            .lock()
-            .get(&handle)
-            .map(Arc::clone)
-            .ok_or_else(ebadf)?;
+    fn set_flags<R: io::Read>(&self, inode: Inode, handle: Handle, r: R) -> io::Result<IoctlReply> {
+        let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
+            self.find_inode(inode)?
+        } else {
+            self.find_handle(handle, inode)?
+        };
 
         // The ioctl encoding is a long but the parameter is actually an int.
         let flags = c_int::from_reader(r)?;
-        let file = data.file.lock();
 
         // Safe because this doesn't modify any memory and we check the return value.
-        let res = unsafe { ioctl_with_ptr(&*file, FS_IOC_SETFLAGS(), &flags) };
+        let res = unsafe { ioctl_with_ptr(&*data, FS_IOC_SETFLAGS(), &flags) };
         if res < 0 {
             Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
         } else {
@@ -2203,6 +2199,7 @@
     fn ioctl<R: io::Read>(
         &self,
         _ctx: Context,
+        inode: Inode,
         handle: Handle,
         _flags: IoctlFlags,
         cmd: u32,
@@ -2220,33 +2217,33 @@
         const SET_FLAGS64: u32 = FS_IOC64_SETFLAGS() as u32;
 
         match cmd {
-            GET_ENCRYPTION_POLICY_EX => self.get_encryption_policy_ex(handle, r),
+            GET_ENCRYPTION_POLICY_EX => self.get_encryption_policy_ex(inode, handle, r),
             GET_FSXATTR => {
                 if out_size < size_of::<fsxattr>() as u32 {
                     Err(io::Error::from_raw_os_error(libc::ENOMEM))
                 } else {
-                    self.get_fsxattr(handle)
+                    self.get_fsxattr(inode, handle)
                 }
             }
             SET_FSXATTR => {
                 if in_size < size_of::<fsxattr>() as u32 {
                     Err(io::Error::from_raw_os_error(libc::EINVAL))
                 } else {
-                    self.set_fsxattr(handle, r)
+                    self.set_fsxattr(inode, handle, r)
                 }
             }
             GET_FLAGS32 | GET_FLAGS64 => {
                 if out_size < size_of::<c_int>() as u32 {
                     Err(io::Error::from_raw_os_error(libc::ENOMEM))
                 } else {
-                    self.get_flags(handle)
+                    self.get_flags(inode, handle)
                 }
             }
             SET_FLAGS32 | SET_FLAGS64 => {
                 if in_size < size_of::<c_int>() as u32 {
                     Err(io::Error::from_raw_os_error(libc::ENOMEM))
                 } else {
-                    self.set_flags(handle, r)
+                    self.set_flags(inode, handle, r)
                 }
             }
             _ => Err(io::Error::from_raw_os_error(libc::ENOTTY)),
diff --git a/fuse/src/filesystem.rs b/fuse/src/filesystem.rs
index c465ca6..8050309 100644
--- a/fuse/src/filesystem.rs
+++ b/fuse/src/filesystem.rs
@@ -1081,6 +1081,7 @@
     fn ioctl<R: io::Read>(
         &self,
         ctx: Context,
+        inode: Self::Inode,
         handle: Self::Handle,
         flags: IoctlFlags,
         cmd: u32,
diff --git a/fuse/src/server.rs b/fuse/src/server.rs
index bfd0c0d..0c62896 100644
--- a/fuse/src/server.rs
+++ b/fuse/src/server.rs
@@ -1329,6 +1329,7 @@
 
         let res = self.fs.ioctl(
             in_header.into(),
+            in_header.nodeid.into(),
             fh.into(),
             IoctlFlags::from_bits_truncate(flags),
             cmd,