Skip to content

Commit 557efb9

Browse files
committed
“extend the lseek on dir”
1 parent 6d72896 commit 557efb9

File tree

2 files changed

+115
-22
lines changed

2 files changed

+115
-22
lines changed

project/libfuse-fs/src/overlayfs/async_io.rs

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -908,8 +908,6 @@ impl Filesystem for OverlayFs {
908908
offset: u64,
909909
whence: u32,
910910
) -> Result<ReplyLSeek> {
911-
// can this be on dir? FIXME: assume file for now
912-
// we need special process if it can be called on dir
913911
let node = self.lookup_node(req, inode, "").await?;
914912

915913
if node.whiteout.load(Ordering::Relaxed) {
@@ -918,14 +916,73 @@ impl Filesystem for OverlayFs {
918916

919917
let st = node.stat64(req).await?;
920918
if utils::is_dir(&st.attr.kind) {
921-
error!("lseek on directory");
922-
return Err(Error::from_raw_os_error(libc::EINVAL).into());
923-
}
919+
// Special handling and security restrictions for directory operations
920+
let handles = self.handles.lock().await;
921+
let handle_data = handles.get(&fh).ok_or_else(|| {
922+
Error::new(ErrorKind::InvalidInput, "Invalid directory handle")
923+
})?;
924+
925+
// Verify handle type and permissions
926+
if let Some(ref rh) = handle_data.real_handle {
927+
// Verify that this handle is indeed a directory handle
928+
let handle_stat = if let Ok(stat) = rh.layer
929+
.getattr(req, rh.inode, Some(rh.handle.load(Ordering::Relaxed)), 0)
930+
.await
931+
{
932+
stat
933+
} else {
934+
return Err(Error::from_raw_os_error(libc::EBADF).into());
935+
};
924936

925-
let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
926-
layer
927-
.lseek(req, real_inode, real_handle, offset, whence)
928-
.await
937+
if !utils::is_dir(&handle_stat.attr.kind) {
938+
return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
939+
}
940+
941+
match whence {
942+
libc::SEEK_SET => {
943+
// Validate offset bounds
944+
if offset > i64::MAX as u64 {
945+
return Err(Error::from_raw_os_error(libc::EINVAL).into());
946+
}
947+
948+
// Perform the seek operation
949+
rh.layer
950+
.lseek(req, rh.inode, rh.handle.load(Ordering::Relaxed), offset, whence)
951+
.await
952+
},
953+
libc::SEEK_CUR => {
954+
// Get current position
955+
let current = if let Ok(reply) = rh.layer
956+
.lseek(req, rh.inode, rh.handle.load(Ordering::Relaxed), 0, libc::SEEK_CUR)
957+
.await
958+
{
959+
reply.offset
960+
} else {
961+
return Err(Error::from_raw_os_error(libc::EINVAL).into());
962+
};
963+
964+
// Check for potential overflow
965+
if let Some(new_offset) = current.checked_add(offset) {
966+
if new_offset > i64::MAX as u64 {
967+
return Err(Error::from_raw_os_error(libc::EINVAL).into());
968+
}
969+
Ok(ReplyLSeek { offset: new_offset })
970+
} else {
971+
Err(Error::from_raw_os_error(libc::EINVAL).into())
972+
}
973+
},
974+
_ => Err(Error::from_raw_os_error(libc::EINVAL).into()),
975+
}
976+
} else {
977+
Err(Error::new(ErrorKind::InvalidInput, "Invalid directory handle").into())
978+
}
979+
} else {
980+
// Keep the original lseek behavior for regular files
981+
let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
982+
layer
983+
.lseek(req, real_inode, real_handle, offset, whence)
984+
.await
985+
}
929986
}
930987

931988
async fn interrupt(&self, _req: Request, _unique: u64) -> Result<()> {

project/libfuse-fs/src/passthrough/async_io.rs

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,21 +1794,57 @@ impl Filesystem for PassthroughFs {
17941794
// Let the Arc<HandleData> in scope, otherwise fd may get invalid.
17951795
let data = self.handle_map.get(fh, inode).await?;
17961796

1797-
// Acquire the lock to get exclusive access, otherwise it may break do_readdir().
1798-
let (_guard, file) = data.get_file_mut().await;
1797+
// 检查文件类型
1798+
let st = stat_fd(data.get_file(), None)?;
1799+
let is_dir = (st.st_mode & libc::S_IFMT) == libc::S_IFDIR;
1800+
1801+
if is_dir {
1802+
match whence {
1803+
// 目录只支持 SEEK_SET
1804+
libc::SEEK_SET => {
1805+
// 检查目录offset的有效性
1806+
if offset > i64::MAX as u64 {
1807+
return Err(io::Error::from_raw_os_error(libc::EINVAL).into());
1808+
}
17991809

1800-
// Safe because this doesn't modify any memory and we check the return value.
1801-
let res = unsafe {
1802-
libc::lseek(
1803-
file.as_raw_fd(),
1804-
offset as libc::off64_t,
1805-
whence as libc::c_int,
1806-
)
1807-
};
1808-
if res < 0 {
1809-
Err(io::Error::last_os_error().into())
1810+
// Acquire the lock to get exclusive access
1811+
let (_guard, file) = data.get_file_mut().await;
1812+
1813+
// 对目录的seek操作,特别注意安全边界
1814+
let res = unsafe {
1815+
libc::lseek64(
1816+
file.as_raw_fd(),
1817+
offset as libc::off64_t,
1818+
libc::SEEK_SET,
1819+
)
1820+
};
1821+
1822+
if res < 0 {
1823+
return Err(io::Error::last_os_error().into());
1824+
}
1825+
Ok(ReplyLSeek { offset: res as u64 })
1826+
}
1827+
// 目录不支持其他seek类型
1828+
_ => Err(io::Error::from_raw_os_error(libc::EINVAL).into()),
1829+
}
18101830
} else {
1811-
Ok(ReplyLSeek { offset: res as u64 })
1831+
// 文件的seek操作
1832+
// Acquire the lock to get exclusive access, otherwise it may break do_readdir().
1833+
let (_guard, file) = data.get_file_mut().await;
1834+
1835+
// Safe because this doesn't modify any memory and we check the return value.
1836+
let res = unsafe {
1837+
libc::lseek(
1838+
file.as_raw_fd(),
1839+
offset as libc::off64_t,
1840+
whence as libc::c_int,
1841+
)
1842+
};
1843+
if res < 0 {
1844+
Err(io::Error::last_os_error().into())
1845+
} else {
1846+
Ok(ReplyLSeek { offset: res as u64 })
1847+
}
18121848
}
18131849
}
18141850
}

0 commit comments

Comments
 (0)