Merge "Fix race between read/write" into main
diff --git a/authfs/src/fusefs.rs b/authfs/src/fusefs.rs
index bddf2c3..64b340a 100644
--- a/authfs/src/fusefs.rs
+++ b/authfs/src/fusefs.rs
@@ -993,8 +993,8 @@
     fn statfs(&self, _ctx: Context, _inode: Self::Inode) -> io::Result<libc::statvfs64> {
         let remote_stat = self.remote_fs_stats_reader.statfs()?;
 
-        // Safe because we are zero-initializing a struct with only POD fields. Not all fields
-        // matter to FUSE. See also:
+        // SAFETY: We are zero-initializing a struct with only POD fields. Not all fields matter to
+        // FUSE. See also:
         // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/fuse/inode.c?h=v5.15#n460
         let mut st: libc::statvfs64 = unsafe { zeroed() };
 
diff --git a/compos/composd/src/fd_server_helper.rs b/compos/composd/src/fd_server_helper.rs
index 777ec27..24371b5 100644
--- a/compos/composd/src/fd_server_helper.rs
+++ b/compos/composd/src/fd_server_helper.rs
@@ -107,8 +107,9 @@
 
 fn create_pipe() -> Result<(File, File)> {
     let (raw_read, raw_write) = pipe2(OFlag::O_CLOEXEC)?;
-    // SAFETY: We are the sole owners of these fds as they were just created.
+    // SAFETY: We are the sole owner of raw_read and it is valid as it was just created.
     let read_fd = unsafe { File::from_raw_fd(raw_read) };
+    // SAFETY: We are the sole owner of raw_write and it is valid as it was just created.
     let write_fd = unsafe { File::from_raw_fd(raw_write) };
     Ok((read_fd, write_fd))
 }
diff --git a/compos/src/compsvc_main.rs b/compos/src/compsvc_main.rs
index 77e2daa..b0fc323 100644
--- a/compos/src/compsvc_main.rs
+++ b/compos/src/compsvc_main.rs
@@ -50,11 +50,11 @@
     debug!("compsvc is starting as a rpc service.");
     let param = ptr::null_mut();
     let mut service = compsvc::new_binder()?.as_binder();
+    let service = service.as_native_mut() as *mut AIBinder;
+    // SAFETY: We hold a strong pointer, so the raw pointer remains valid. The bindgen AIBinder
+    // is the same type as sys::AIBinder. It is safe for on_ready to be invoked at any time, with
+    // any parameter.
     unsafe {
-        // SAFETY: We hold a strong pointer, so the raw pointer remains valid. The bindgen AIBinder
-        // is the same type as sys::AIBinder.
-        let service = service.as_native_mut() as *mut AIBinder;
-        // SAFETY: It is safe for on_ready to be invoked at any time, with any parameter.
         AVmPayload_runVsockRpcServer(service, COMPOS_VSOCK_PORT, Some(on_ready), param);
     }
     Ok(())
diff --git a/encryptedstore/src/main.rs b/encryptedstore/src/main.rs
index 86fa6da..1a16f49 100644
--- a/encryptedstore/src/main.rs
+++ b/encryptedstore/src/main.rs
@@ -153,6 +153,9 @@
     let mountpoint = CString::new(mountpoint.as_os_str().as_bytes())?;
     let fstype = CString::new("ext4").unwrap();
 
+    // SAFETY: The source, target and filesystemtype are valid C strings. For ext4, data is expected
+    // to be a C string as well, which it is. None of these pointers are retained after mount
+    // returns.
     let ret = unsafe {
         libc::mount(
             source.as_ptr(),
diff --git a/libs/capabilities/src/caps.rs b/libs/capabilities/src/caps.rs
index 1f44a34..bc17fa8 100644
--- a/libs/capabilities/src/caps.rs
+++ b/libs/capabilities/src/caps.rs
@@ -26,8 +26,8 @@
 /// Removes inheritable capabilities set for this process.
 /// See: https://man7.org/linux/man-pages/man7/capabilities.7.html
 pub fn drop_inheritable_caps() -> Result<()> {
+    // SAFETY: we do not manipulate memory handled by libcap.
     unsafe {
-        // SAFETY: we do not manipulate memory handled by libcap.
         let caps = cap_get_proc();
         scopeguard::defer! {
             cap_free(caps as *mut std::os::raw::c_void);
@@ -49,8 +49,8 @@
 pub fn drop_bounding_set() -> Result<()> {
     let mut cap_id: cap_value_t = 0;
     while cap_id <= CAP_LAST_CAP.try_into().unwrap() {
+        // SAFETY: we do not manipulate memory handled by libcap.
         unsafe {
-            // SAFETY: we do not manipulate memory handled by libcap.
             if cap_drop_bound(cap_id) == -1 {
                 let e = Errno::last();
                 bail!("cap_drop_bound failed for {}: {:?}", cap_id, e);
diff --git a/microdroid_manager/src/dice.rs b/microdroid_manager/src/dice.rs
index bacefcd..8e078ea 100644
--- a/microdroid_manager/src/dice.rs
+++ b/microdroid_manager/src/dice.rs
@@ -78,7 +78,7 @@
         let mmap_size =
             file.read_u64::<NativeEndian>()
                 .map_err(|error| Error::new(error).context("Reading driver"))? as usize;
-        // It's safe to map the driver as the service will only create a single
+        // SAFETY: It's safe to map the driver as the service will only create a single
         // mapping per process.
         let mmap_addr = unsafe {
             let fd = file.as_raw_fd();
@@ -87,10 +87,10 @@
         if mmap_addr == MAP_FAILED {
             bail!("Failed to mmap {:?}", driver_path);
         }
-        // The slice is created for the region of memory that was just
+        let mmap_buf =
+        // SAFETY: The slice is created for the region of memory that was just
         // successfully mapped into the process address space so it will be
         // accessible and not referenced from anywhere else.
-        let mmap_buf =
             unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
         let bcc_handover =
             bcc_handover_parse(mmap_buf).map_err(|_| anyhow!("Failed to parse Bcc Handover"))?;
@@ -149,9 +149,9 @@
 impl Drop for DiceDriver<'_> {
     fn drop(&mut self) {
         if let &mut Self::Real { mmap_addr, mmap_size, .. } = self {
-            // All references to the mapped region have the same lifetime as self. Since self is
-            // being dropped, so are all the references to the mapped region meaning its safe to
-            // unmap.
+            // SAFETY: All references to the mapped region have the same lifetime as self. Since
+            // self is being dropped, so are all the references to the mapped region meaning it's
+            // safe to unmap.
             let ret = unsafe { munmap(mmap_addr, mmap_size) };
             if ret != 0 {
                 log::warn!("Failed to munmap ({})", ret);
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 1cdcde1..319d2df 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -193,7 +193,7 @@
 
 /// Prepares a socket file descriptor for the vm payload service.
 ///
-/// # Safety requirement
+/// # Safety
 ///
 /// The caller must ensure that this function is the only place that claims ownership
 /// of the file descriptor and it is called only once.
@@ -267,6 +267,8 @@
     if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
         let mountpoint = CString::new(ENCRYPTEDSTORE_MOUNTPOINT).unwrap();
 
+        // SAFETY: `mountpoint` is a valid C string. `syncfs` and `close` are safe for any parameter
+        // values.
         let ret = unsafe {
             let dirfd = libc::open(
                 mountpoint.as_ptr(),
@@ -856,19 +858,15 @@
         }
     };
 
+    // SAFETY: We are not accessing any resource of the parent process. This means we can't make any
+    // log calls inside the closure.
     unsafe {
-        // SAFETY: we are not accessing any resource of the parent process.
         command.pre_exec(|| {
-            info!("dropping capabilities before executing payload");
             // It is OK to continue with payload execution even if the calls below fail, since
             // whether process can use a capability is controlled by the SELinux. Dropping the
             // capabilities here is just another defense-in-depth layer.
-            if let Err(e) = cap::drop_inheritable_caps() {
-                error!("failed to drop inheritable capabilities: {:?}", e);
-            }
-            if let Err(e) = cap::drop_bounding_set() {
-                error!("failed to drop bounding set: {:?}", e);
-            }
+            let _ = cap::drop_inheritable_caps();
+            let _ = cap::drop_bounding_set();
             Ok(())
         });
     }
diff --git a/microdroid_manager/src/swap.rs b/microdroid_manager/src/swap.rs
index 2f4d176..c2b20ac 100644
--- a/microdroid_manager/src/swap.rs
+++ b/microdroid_manager/src/swap.rs
@@ -48,7 +48,7 @@
         .checked_mul(512)
         .ok_or_else(|| anyhow!("sysfs_size too large"))?;
 
-    // safe because we give a constant and known-valid sysconf parameter
+    // SAFETY: We give a constant and known-valid sysconf parameter.
     let pagesize = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) as u64 };
 
     let mut f = OpenOptions::new().read(false).write(true).open(format!("/dev/{}", dev))?;
@@ -75,7 +75,7 @@
 /// Simple "swapon", using libc:: wrapper.
 fn swapon(dev: &str) -> Result<()> {
     let swapon_arg = std::ffi::CString::new(format!("/dev/{}", dev))?;
-    // safe because we give a nul-terminated string and check the result
+    // SAFETY: We give a nul-terminated string and check the result.
     let res = unsafe { libc::swapon(swapon_arg.as_ptr(), 0) };
     if res != 0 {
         return Err(anyhow!("Failed to swapon: {}", Error::last_os_error()));
diff --git a/pvmfw/avb/tests/api_test.rs b/pvmfw/avb/tests/api_test.rs
index aa9ed36..2f45d77 100644
--- a/pvmfw/avb/tests/api_test.rs
+++ b/pvmfw/avb/tests/api_test.rs
@@ -243,10 +243,15 @@
     let total_len = kernel.len() as u64;
     let footer = extract_avb_footer(&kernel)?;
     assert!(footer.vbmeta_offset < total_len);
+    // TODO: use core::mem::offset_of once stable.
+    let footer_addr = ptr::addr_of!(footer) as *const u8;
     let vbmeta_offset_addr = ptr::addr_of!(footer.vbmeta_offset) as *const u8;
-    // SAFETY: It is safe as both raw pointers `vbmeta_offset_addr` and `footer` are not null.
     let vbmeta_offset_start =
-        unsafe { vbmeta_offset_addr.offset_from(ptr::addr_of!(footer) as *const u8) };
+        // SAFETY:
+        // - both raw pointers `vbmeta_offset_addr` and `footer_addr` are not null;
+        // - they are both derived from the `footer` object;
+        // - the offset is known from the struct definition to be a small positive number of bytes.
+        unsafe { vbmeta_offset_addr.offset_from(footer_addr) };
     let footer_start = kernel.len() - size_of::<AvbFooter>();
     let vbmeta_offset_start = footer_start + usize::try_from(vbmeta_offset_start)?;
 
diff --git a/rialto/Android.bp b/rialto/Android.bp
index 1840278..ed9a284 100644
--- a/rialto/Android.bp
+++ b/rialto/Android.bp
@@ -101,6 +101,7 @@
         "liblog_rust",
         "libnix",
         "libvmclient",
+        "libvsock",
     ],
     data: [
         ":rialto_bin",
diff --git a/rialto/AndroidTest.xml b/rialto/AndroidTest.xml
new file mode 100644
index 0000000..43c4c90
--- /dev/null
+++ b/rialto/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<configuration description="Config for rialto_test">
+  <!--
+    We need root privilege to bypass selinux because shell cannot create socket.
+    Otherwise, we hit the following errors:
+
+    avc:  denied  { create } for  scontext=u:r:shell:s0 tcontext=u:r:shell:s0
+     tclass=vsock_socket permissive=0
+  -->
+  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="push-file" key="rialto_test" value="/data/local/tmp/rialto_test" />
+  </target_preparer>
+
+  <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+    <option name="test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="rialto_test" />
+  </test>
+</configuration>
\ No newline at end of file
diff --git a/rialto/src/communication.rs b/rialto/src/communication.rs
new file mode 100644
index 0000000..f00393d
--- /dev/null
+++ b/rialto/src/communication.rs
@@ -0,0 +1,85 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Supports for the communication between rialto and host.
+
+use crate::error::{Error, Result};
+use log::info;
+use virtio_drivers::{
+    self,
+    device::socket::{
+        SingleConnectionManager, SocketError, VirtIOSocket, VsockAddr, VsockEventType,
+    },
+    transport::Transport,
+    Hal,
+};
+
+const MAX_RECV_BUFFER_SIZE_BYTES: usize = 64;
+
+pub struct DataChannel<H: Hal, T: Transport> {
+    connection_manager: SingleConnectionManager<H, T>,
+}
+
+impl<H: Hal, T: Transport> From<VirtIOSocket<H, T>> for DataChannel<H, T> {
+    fn from(socket_device_driver: VirtIOSocket<H, T>) -> Self {
+        Self { connection_manager: SingleConnectionManager::new(socket_device_driver) }
+    }
+}
+
+impl<H: Hal, T: Transport> DataChannel<H, T> {
+    /// Connects to the given destination.
+    pub fn connect(&mut self, destination: VsockAddr) -> virtio_drivers::Result {
+        // Use the same port on rialto and host for convenience.
+        self.connection_manager.connect(destination, destination.port)?;
+        self.connection_manager.wait_for_connect()?;
+        info!("Connected to the destination {destination:?}");
+        Ok(())
+    }
+
+    /// Processes the received requests and sends back a reply.
+    pub fn handle_incoming_request(&mut self) -> Result<()> {
+        let mut buffer = [0u8; MAX_RECV_BUFFER_SIZE_BYTES];
+
+        // TODO(b/274441673): Handle the scenario when the given buffer is too short.
+        let len = self.wait_for_recv(&mut buffer).map_err(Error::ReceivingDataFailed)?;
+
+        // TODO(b/291732060): Implement the communication protocol.
+        // Just reverse the received message for now.
+        buffer[..len].reverse();
+        self.connection_manager.send(&buffer[..len])?;
+        Ok(())
+    }
+
+    fn wait_for_recv(&mut self, buffer: &mut [u8]) -> virtio_drivers::Result<usize> {
+        loop {
+            match self.connection_manager.wait_for_recv(buffer)?.event_type {
+                VsockEventType::Disconnected { .. } => {
+                    return Err(SocketError::ConnectionFailed.into())
+                }
+                VsockEventType::Received { length, .. } => return Ok(length),
+                VsockEventType::Connected
+                | VsockEventType::ConnectionRequest
+                | VsockEventType::CreditRequest
+                | VsockEventType::CreditUpdate => {}
+            }
+        }
+    }
+
+    /// Shuts down the data channel.
+    pub fn force_close(&mut self) -> virtio_drivers::Result {
+        self.connection_manager.force_close()?;
+        info!("Connection shutdown.");
+        Ok(())
+    }
+}
diff --git a/rialto/src/error.rs b/rialto/src/error.rs
index 0c1e25d..461870b 100644
--- a/rialto/src/error.rs
+++ b/rialto/src/error.rs
@@ -41,6 +41,10 @@
     VirtIOSocketCreationFailed(virtio_drivers::Error),
     /// Missing socket device.
     MissingVirtIOSocketDevice,
+    /// Failed VirtIO driver operation.
+    VirtIODriverOperationFailed(virtio_drivers::Error),
+    /// Failed to receive data.
+    ReceivingDataFailed(virtio_drivers::Error),
 }
 
 impl fmt::Display for Error {
@@ -58,6 +62,10 @@
                 write!(f, "Failed to create VirtIO Socket device: {e}")
             }
             Self::MissingVirtIOSocketDevice => write!(f, "Missing VirtIO Socket device."),
+            Self::VirtIODriverOperationFailed(e) => {
+                write!(f, "Failed VirtIO driver operation: {e}")
+            }
+            Self::ReceivingDataFailed(e) => write!(f, "Failed to receive data: {e}"),
         }
     }
 }
@@ -91,3 +99,9 @@
         Self::MemoryOperationFailed(e)
     }
 }
+
+impl From<virtio_drivers::Error> for Error {
+    fn from(e: virtio_drivers::Error) -> Self {
+        Self::VirtIODriverOperationFailed(e)
+    }
+}
diff --git a/rialto/src/main.rs b/rialto/src/main.rs
index bbc9997..5c6649a 100644
--- a/rialto/src/main.rs
+++ b/rialto/src/main.rs
@@ -17,11 +17,13 @@
 #![no_main]
 #![no_std]
 
+mod communication;
 mod error;
 mod exceptions;
 
 extern crate alloc;
 
+use crate::communication::DataChannel;
 use crate::error::{Error, Result};
 use core::num::NonZeroUsize;
 use core::slice;
@@ -30,6 +32,7 @@
 use libfdt::FdtError;
 use log::{debug, error, info};
 use virtio_drivers::{
+    device::socket::VsockAddr,
     transport::{pci::bus::PciRoot, DeviceType, Transport},
     Hal,
 };
@@ -46,6 +49,20 @@
     },
 };
 
+fn host_addr() -> VsockAddr {
+    const PROTECTED_VM_PORT: u32 = 5679;
+    const NON_PROTECTED_VM_PORT: u32 = 5680;
+    const VMADDR_CID_HOST: u64 = 2;
+
+    let port = if is_protected_vm() { PROTECTED_VM_PORT } else { NON_PROTECTED_VM_PORT };
+    VsockAddr { cid: VMADDR_CID_HOST, port }
+}
+
+fn is_protected_vm() -> bool {
+    // Use MMIO support to determine whether the VM is protected.
+    get_mmio_guard().is_some()
+}
+
 fn new_page_table() -> Result<PageTable> {
     let mut page_table = PageTable::default();
 
@@ -119,6 +136,12 @@
     debug!("PCI root: {pci_root:#x?}");
     let socket_device = find_socket_device::<HalImpl>(&mut pci_root)?;
     debug!("Found socket device: guest cid = {:?}", socket_device.guest_cid());
+
+    let mut data_channel = DataChannel::from(socket_device);
+    data_channel.connect(host_addr())?;
+    data_channel.handle_incoming_request()?;
+    data_channel.force_close()?;
+
     Ok(())
 }
 
diff --git a/rialto/tests/test.rs b/rialto/tests/test.rs
index 98c935d..4ad8eb8 100644
--- a/rialto/tests/test.rs
+++ b/rialto/tests/test.rs
@@ -22,15 +22,21 @@
     },
     binder::{ParcelFileDescriptor, ProcessState},
 };
-use anyhow::{anyhow, Context, Error};
+use anyhow::{anyhow, bail, Context, Error};
 use log::info;
 use std::fs::File;
-use std::io::{self, BufRead, BufReader};
+use std::io::{self, BufRead, BufReader, Read, Write};
 use std::os::unix::io::FromRawFd;
 use std::panic;
 use std::thread;
 use std::time::Duration;
 use vmclient::{DeathReason, VmInstance};
+use vsock::{VsockListener, VMADDR_CID_HOST};
+
+// TODO(b/291732060): Move the port numbers to the common library shared between the host
+// and rialto.
+const PROTECTED_VM_PORT: u32 = 5679;
+const NON_PROTECTED_VM_PORT: u32 = 5680;
 
 const SIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto.bin";
 const UNSIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto_unsigned.bin";
@@ -124,6 +130,9 @@
     )
     .context("Failed to create VM")?;
 
+    let port = if protected_vm { PROTECTED_VM_PORT } else { NON_PROTECTED_VM_PORT };
+    let check_socket_handle = thread::spawn(move || try_check_socket_connection(port).unwrap());
+
     vm.start().context("Failed to start VM")?;
 
     // Wait for VM to finish, and check that it shut down cleanly.
@@ -132,6 +141,15 @@
         .ok_or_else(|| anyhow!("Timed out waiting for VM exit"))?;
     assert_eq!(death_reason, DeathReason::Shutdown);
 
+    match check_socket_handle.join() {
+        Ok(_) => {
+            info!(
+                "Received the echoed message. \
+                   The socket connection between the host and the service VM works correctly."
+            )
+        }
+        Err(_) => bail!("The socket connection check failed."),
+    }
     Ok(())
 }
 
@@ -140,6 +158,7 @@
 
     // SAFETY: These are new FDs with no previous owner.
     let reader = unsafe { File::from_raw_fd(reader_fd) };
+    // SAFETY: These are new FDs with no previous owner.
     let writer = unsafe { File::from_raw_fd(writer_fd) };
 
     thread::spawn(|| {
@@ -149,3 +168,28 @@
     });
     Ok(writer)
 }
+
+fn try_check_socket_connection(port: u32) -> Result<(), Error> {
+    info!("Setting up the listening socket on port {port}...");
+    let listener = VsockListener::bind_with_cid_port(VMADDR_CID_HOST, port)?;
+    info!("Listening on port {port}...");
+
+    let Some(Ok(mut vsock_stream)) = listener.incoming().next() else {
+        bail!("Failed to get vsock_stream");
+    };
+    info!("Accepted connection {:?}", vsock_stream);
+
+    let message = "Hello from host";
+    vsock_stream.write_all(message.as_bytes())?;
+    vsock_stream.flush()?;
+    info!("Sent message: {:?}.", message);
+
+    let mut buffer = vec![0u8; 30];
+    vsock_stream.set_read_timeout(Some(Duration::from_millis(1_000)))?;
+    let len = vsock_stream.read(&mut buffer)?;
+
+    assert_eq!(message.len(), len);
+    buffer[..len].reverse();
+    assert_eq!(message.as_bytes(), &buffer[..len]);
+    Ok(())
+}
diff --git a/vmbase/example/tests/test.rs b/vmbase/example/tests/test.rs
index 3594523..2b6dfbc 100644
--- a/vmbase/example/tests/test.rs
+++ b/vmbase/example/tests/test.rs
@@ -143,6 +143,7 @@
 
     // SAFETY: These are new FDs with no previous owner.
     let reader = unsafe { File::from_raw_fd(reader_fd) };
+    // SAFETY: These are new FDs with no previous owner.
     let writer = unsafe { File::from_raw_fd(writer_fd) };
 
     Ok((reader, writer))
diff --git a/vmbase/src/memory/shared.rs b/vmbase/src/memory/shared.rs
index dfa29e4..f4c9f72 100644
--- a/vmbase/src/memory/shared.rs
+++ b/vmbase/src/memory/shared.rs
@@ -341,7 +341,11 @@
 /// Allocates a memory range of at least the given size and alignment that is shared with the host.
 /// Returns a pointer to the buffer.
 pub(crate) fn alloc_shared(layout: Layout) -> hyp::Result<NonNull<u8>> {
-    assert_ne!(layout.size(), 0);
+    // TODO(b/291586508): We have temporarily removed the non-zero check for layout.size() to
+    // enable the Rialto socket device to connect or shut down, as the socket driver adds empty
+    // buffers in these scenarios.
+    // We will add the check back once this issue is fixed in the driver.
+
     let Some(buffer) = try_shared_alloc(layout) else {
         handle_alloc_error(layout);
     };
diff --git a/zipfuse/src/main.rs b/zipfuse/src/main.rs
index 20d6fd6..e8be42c 100644
--- a/zipfuse/src/main.rs
+++ b/zipfuse/src/main.rs
@@ -31,7 +31,7 @@
 use std::fs::{File, OpenOptions};
 use std::io;
 use std::io::Read;
-use std::mem::size_of;
+use std::mem::{size_of, MaybeUninit};
 use std::os::unix::io::AsRawFd;
 use std::path::Path;
 use std::path::PathBuf;
@@ -192,7 +192,8 @@
     #[allow(clippy::useless_conversion)]
     fn stat_from(&self, inode: Inode) -> io::Result<libc::stat64> {
         let inode_data = self.find_inode(inode)?;
-        let mut st = unsafe { std::mem::MaybeUninit::<libc::stat64>::zeroed().assume_init() };
+        // SAFETY: All fields of stat64 are valid for zero byte patterns.
+        let mut st = unsafe { MaybeUninit::<libc::stat64>::zeroed().assume_init() };
         st.st_dev = 0;
         st.st_nlink = if let Some(directory) = inode_data.get_directory() {
             (2 + directory.len() as libc::nlink_t).into()