mirror of
https://github.com/libfuse/libfuse.git
synced 2026-07-07 14:47:41 +08:00
memfs_ll: reject out-of-range read and write offsets
memfs_write passed offset and size straight to Inode::write_content, which computes offset + size to size the content vector. A negative offset converts to a huge unsigned value in that expression and aborts the resize; an end position past the vector's index ceiling truncates on the resize/iterator arithmetic (size_t/ptrdiff_t), which on a 32-bit build is below the off_t range the kernel can hand us. memfs_read only guarded offset >= content_size(). On a 64-bit build the unsigned compare incidentally rejects a negative offset, but on 32-bit the comparison is signed, so a negative offset slips through, truncates in (size_t)offset, and indexes before the content buffer. Validate at both handlers before touching the content store: reject a negative offset with EINVAL, and in write reject an end position past PTRDIFF_MAX (the std::vector size/index limit on both 32- and 64-bit builds) with EFBIG. Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
This commit is contained in:
@@ -665,6 +665,19 @@ static void memfs_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
|
||||
return;
|
||||
}
|
||||
|
||||
// A negative offset, or an end position past the content vector's index
|
||||
// type, would convert to a huge value in write_content and abort the
|
||||
// resize. PTRDIFF_MAX is the std::vector size/index ceiling on both 32-
|
||||
// and 64-bit builds.
|
||||
if (offset < 0) {
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
if ((uint64_t)offset > (uint64_t)PTRDIFF_MAX - size) {
|
||||
fuse_reply_err(req, EFBIG);
|
||||
return;
|
||||
}
|
||||
|
||||
inode->write_content(buf, size, offset);
|
||||
fuse_reply_write(req, size);
|
||||
}
|
||||
@@ -686,6 +699,13 @@ static void memfs_read(fuse_req_t req, fuse_ino_t ino, size_t size,
|
||||
return;
|
||||
}
|
||||
|
||||
// A negative offset would slip past the offset >= content_size() guard
|
||||
// on a 32-bit build (signed compare) and index before the buffer.
|
||||
if (offset < 0) {
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
inode->lock();
|
||||
|
||||
if (offset >= inode->content_size()) {
|
||||
|
||||
Reference in New Issue
Block a user