Kernel: Handle mmap requests on zero-length data file inodes safely

This commit is contained in:
Liav A 2022-08-06 21:05:48 +03:00 committed by Idan Horowitz
parent c88cc8557f
commit 3ad0e1a1d5
5 changed files with 28 additions and 5 deletions

View file

@ -80,11 +80,11 @@ ErrorOr<void> InodeFile::ioctl(OpenFileDescription& description, unsigned reques
}
}
ErrorOr<NonnullLockRefPtr<Memory::VMObject>> InodeFile::vmobject_for_mmap(Process&, Memory::VirtualRange const&, u64&, bool shared)
ErrorOr<NonnullLockRefPtr<Memory::VMObject>> InodeFile::vmobject_for_mmap(Process&, Memory::VirtualRange const& range, u64& offset, bool shared)
{
if (shared)
return TRY(Memory::SharedInodeVMObject::try_create_with_inode(inode()));
return TRY(Memory::PrivateInodeVMObject::try_create_with_inode(inode()));
return TRY(Memory::SharedInodeVMObject::try_create_with_inode_and_range(inode(), offset, range.size()));
return TRY(Memory::PrivateInodeVMObject::try_create_with_inode_and_range(inode(), offset, range.size()));
}
ErrorOr<NonnullOwnPtr<KString>> InodeFile::pseudo_path(OpenFileDescription const&) const

View file

@ -11,7 +11,18 @@ namespace Kernel::Memory {
ErrorOr<NonnullLockRefPtr<PrivateInodeVMObject>> PrivateInodeVMObject::try_create_with_inode(Inode& inode)
{
auto new_physical_pages = TRY(VMObject::try_create_physical_pages(inode.size()));
if (inode.size() == 0)
return EINVAL;
return try_create_with_inode_and_range(inode, 0, inode.size());
}
ErrorOr<NonnullLockRefPtr<PrivateInodeVMObject>> PrivateInodeVMObject::try_create_with_inode_and_range(Inode& inode, u64 offset, size_t range_size)
{
// Note: To ensure further allocation of a Region with this VMObject will not complain
// on "smaller" VMObject than the requested Region, we simply take the max size between both values.
auto size = max(inode.size(), (offset + range_size));
VERIFY(size > 0);
auto new_physical_pages = TRY(VMObject::try_create_physical_pages(size));
auto dirty_pages = TRY(Bitmap::try_create(new_physical_pages.size(), false));
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) PrivateInodeVMObject(inode, move(new_physical_pages), move(dirty_pages)));
}

View file

@ -18,6 +18,7 @@ public:
virtual ~PrivateInodeVMObject() override;
static ErrorOr<NonnullLockRefPtr<PrivateInodeVMObject>> try_create_with_inode(Inode&);
static ErrorOr<NonnullLockRefPtr<PrivateInodeVMObject>> try_create_with_inode_and_range(Inode&, u64 offset, size_t range_size);
virtual ErrorOr<NonnullLockRefPtr<VMObject>> try_clone() override;
private:

View file

@ -12,7 +12,17 @@ namespace Kernel::Memory {
ErrorOr<NonnullLockRefPtr<SharedInodeVMObject>> SharedInodeVMObject::try_create_with_inode(Inode& inode)
{
size_t size = inode.size();
if (inode.size() == 0)
return EINVAL;
return try_create_with_inode_and_range(inode, 0, inode.size());
}
ErrorOr<NonnullLockRefPtr<SharedInodeVMObject>> SharedInodeVMObject::try_create_with_inode_and_range(Inode& inode, u64 offset, size_t range_size)
{
// Note: To ensure further allocation of a Region with this VMObject will not complain
// on "smaller" VMObject than the requested Region, we simply take the max size between both values.
auto size = max(inode.size(), (offset + range_size));
VERIFY(size > 0);
if (auto shared_vmobject = inode.shared_vmobject())
return shared_vmobject.release_nonnull();
auto new_physical_pages = TRY(VMObject::try_create_physical_pages(size));

View file

@ -16,6 +16,7 @@ class SharedInodeVMObject final : public InodeVMObject {
public:
static ErrorOr<NonnullLockRefPtr<SharedInodeVMObject>> try_create_with_inode(Inode&);
static ErrorOr<NonnullLockRefPtr<SharedInodeVMObject>> try_create_with_inode_and_range(Inode&, u64 offset, size_t range_size);
virtual ErrorOr<NonnullLockRefPtr<VMObject>> try_clone() override;
ErrorOr<void> sync(off_t offset_in_pages = 0, size_t pages = -1);