From 3a46eb51619f242fea44dd5978fca33aee31d714 Mon Sep 17 00:00:00 2001 From: Kandelo Agent Date: Tue, 16 Jun 2026 02:00:02 +0000 Subject: [PATCH] fix: preserve unix socket path ownership in stat (cherry picked from commit 80396cd2653afe67160cecd1c2fbb1348725b9e6) (cherry picked from commit c40c493e708a84cbfe1e8d2cbbf4f0032f4e8bec) --- crates/kernel/src/syscalls.rs | 105 ++++++++++++++-------------------- 1 file changed, 43 insertions(+), 62 deletions(-) diff --git a/crates/kernel/src/syscalls.rs b/crates/kernel/src/syscalls.rs index 0a727d567..8c6bab5bc 100644 --- a/crates/kernel/src/syscalls.rs +++ b/crates/kernel/src/syscalls.rs @@ -4010,6 +4010,34 @@ fn match_pty_stat(resolved: &[u8], uid: u32, gid: u32) -> Option { } } +fn unix_socket_path_stat( + proc: &Process, + host: &mut dyn HostIO, + resolved: &[u8], + follow: bool, +) -> Result, Errno> { + let registry = unsafe { crate::unix_socket::global_unix_socket_registry() }; + if !registry.contains(resolved) { + return Ok(None); + } + + // Filesystem-backed AF_UNIX sockets have ordinary path metadata. The + // socket registry tells Kandelo that the path should report S_IFSOCK, but + // uid/gid/mode/timestamps still come from the underlying VFS inode so + // chown(2), chmod(2), and stat(2) round-trip like a POSIX socket node. + check_search_path(proc, host, resolved)?; + let mut st = if follow { + host.host_stat(resolved)? + } else { + host.host_lstat(resolved)? + }; + st.st_mode = wasm_posix_shared::mode::S_IFSOCK | (st.st_mode & 0o7777); + if st.st_nlink == 0 { + st.st_nlink = 1; + } + Ok(Some(st)) +} + pub fn sys_stat(proc: &mut Process, host: &mut dyn HostIO, path: &[u8]) -> Result { let resolved = resolve_path(path, &proc.cwd); if let Some(dev) = match_virtual_device(&resolved) { @@ -4046,27 +4074,8 @@ pub fn sys_stat(proc: &mut Process, host: &mut dyn HostIO, path: &[u8]) -> Resul if let Some(st) = synthetic_file_stat(&resolved, proc.euid, proc.egid) { return Ok(st); } - // Check Unix socket registry - { - let registry = unsafe { crate::unix_socket::global_unix_socket_registry() }; - if registry.contains(&resolved) { - return Ok(WasmStat { - st_dev: 0, - st_ino: 0x554E5800, // "UNX\0" - st_mode: wasm_posix_shared::mode::S_IFSOCK | 0o755, - st_nlink: 1, - st_uid: proc.euid, - st_gid: proc.egid, - st_size: 0, - st_atime_sec: 0, - st_atime_nsec: 0, - st_mtime_sec: 0, - st_mtime_nsec: 0, - st_ctime_sec: 0, - st_ctime_nsec: 0, - _pad: 0, - }); - } + if let Some(st) = unix_socket_path_stat(proc, host, &resolved, true)? { + return Ok(st); } // VFS is the source of truth for ownership: host_stat already returns the // file's real uid/gid, so just propagate. @@ -4114,27 +4123,8 @@ pub fn sys_lstat( if let Some(st) = synthetic_file_stat(&resolved, proc.euid, proc.egid) { return Ok(st); } - // Check Unix socket registry - { - let registry = unsafe { crate::unix_socket::global_unix_socket_registry() }; - if registry.contains(&resolved) { - return Ok(WasmStat { - st_dev: 0, - st_ino: 0x554E5800, // "UNX\0" - st_mode: wasm_posix_shared::mode::S_IFSOCK | 0o755, - st_nlink: 1, - st_uid: proc.euid, - st_gid: proc.egid, - st_size: 0, - st_atime_sec: 0, - st_atime_nsec: 0, - st_mtime_sec: 0, - st_mtime_nsec: 0, - st_ctime_sec: 0, - st_ctime_nsec: 0, - _pad: 0, - }); - } + if let Some(st) = unix_socket_path_stat(proc, host, &resolved, false)? { + return Ok(st); } // VFS is the source of truth for ownership: host_lstat already returns the // link's real uid/gid, so just propagate. @@ -8255,27 +8245,10 @@ pub fn sys_fstatat( if let Some(st) = synthetic_file_stat(&resolved, proc.euid, proc.egid) { return Ok(st); } - // Check Unix socket registry + if let Some(st) = + unix_socket_path_stat(proc, host, &resolved, flags & AT_SYMLINK_NOFOLLOW == 0)? { - let registry = unsafe { crate::unix_socket::global_unix_socket_registry() }; - if registry.contains(&resolved) { - return Ok(WasmStat { - st_dev: 0, - st_ino: 0x554E5800, // "UNX\0" - st_mode: wasm_posix_shared::mode::S_IFSOCK | 0o755, - st_nlink: 1, - st_uid: proc.euid, - st_gid: proc.egid, - st_size: 0, - st_atime_sec: 0, - st_atime_nsec: 0, - st_mtime_sec: 0, - st_mtime_nsec: 0, - st_ctime_sec: 0, - st_ctime_nsec: 0, - _pad: 0, - }); - } + return Ok(st); } // VFS is the source of truth for ownership: host_stat / host_lstat // already return the real uid/gid, so just propagate. @@ -16661,6 +16634,14 @@ mod tests { st.st_mode & wasm_posix_shared::mode::S_IFMT, wasm_posix_shared::mode::S_IFSOCK ); + sys_chown(&mut proc, &mut host, b"/tmp/stat.sock", 1234, 5678).unwrap(); + let st = sys_stat(&mut proc, &mut host, b"/tmp/stat.sock").unwrap(); + assert_eq!(st.st_uid, 1234); + assert_eq!(st.st_gid, 5678); + assert_eq!( + st.st_mode & wasm_posix_shared::mode::S_IFMT, + wasm_posix_shared::mode::S_IFSOCK + ); // Cleanup let registry = unsafe { crate::unix_socket::global_unix_socket_registry() };