1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-16 17:55:06 +00:00

Kernel/VFS: Ensure Custodies' absolute path don't match before mounting

This ensures that the host mount point custody path is not the same like
the new to-be-mounted custody.

A scenario that could happen before adding this check is:
```
mkdir -p /tmp2
mount /dev/hda /tmp2/
mount /dev/hda /tmp2/
mount /dev/hda /tmp2/ # this will fail here
```

and after adding this check, the following scenario is now this:
```
mkdir -p /tmp2
mount /dev/hda /tmp2/
mount /dev/hda /tmp2/ # this will fail here
mount /dev/hda /tmp2/ # this will fail here too
```
This commit is contained in:
Liav A 2023-08-04 14:54:52 +03:00 committed by Jelle Raaijmakers
parent 8da7d84512
commit debbfe07fb
2 changed files with 30 additions and 9 deletions

View file

@ -100,11 +100,31 @@ InodeIdentifier VirtualFileSystem::root_inode_id() const
return m_root_inode->identifier(); return m_root_inode->identifier();
} }
bool VirtualFileSystem::mount_point_exists_at_inode(InodeIdentifier inode_identifier) bool VirtualFileSystem::check_matching_absolute_path_hierarchy(Custody const& first_custody, Custody const& second_custody)
{
// Are both custodies the root mount?
if (!first_custody.parent() && !second_custody.parent())
return true;
if (first_custody.name() != second_custody.name())
return false;
auto const* custody1 = &first_custody;
auto const* custody2 = &second_custody;
while (custody1->parent()) {
if (!custody2->parent())
return false;
if (custody1->parent().ptr() != custody2->parent().ptr())
return false;
custody1 = custody1->parent();
custody2 = custody2->parent();
}
return true;
}
bool VirtualFileSystem::mount_point_exists_at_custody(Custody& mount_point)
{ {
return m_mounts.with([&](auto& mounts) -> bool { return m_mounts.with([&](auto& mounts) -> bool {
return any_of(mounts, [&inode_identifier](auto const& existing_mount) { return any_of(mounts, [&mount_point](auto const& existing_mount) {
return existing_mount.host() && existing_mount.host()->identifier() == inode_identifier; return existing_mount.host_custody() && check_matching_absolute_path_hierarchy(*existing_mount.host_custody(), mount_point);
}); });
}); });
} }
@ -113,14 +133,14 @@ ErrorOr<void> VirtualFileSystem::add_file_system_to_mount_table(FileSystem& file
{ {
auto new_mount = TRY(adopt_nonnull_own_or_enomem(new (nothrow) Mount(file_system, &mount_point, flags))); auto new_mount = TRY(adopt_nonnull_own_or_enomem(new (nothrow) Mount(file_system, &mount_point, flags)));
return m_mounts.with([&](auto& mounts) -> ErrorOr<void> { return m_mounts.with([&](auto& mounts) -> ErrorOr<void> {
auto& inode = mount_point.inode(); auto& mount_point_inode = mount_point.inode();
dbgln("VirtualFileSystem: FileSystemID {}, Mounting {} at inode {} with flags {}", dbgln("VirtualFileSystem: FileSystemID {}, Mounting {} at inode {} with flags {}",
file_system.fsid(), file_system.fsid(),
file_system.class_name(), file_system.class_name(),
inode.identifier(), mount_point_inode.identifier(),
flags); flags);
if (mount_point_exists_at_inode(inode.identifier())) { if (mount_point_exists_at_custody(mount_point)) {
dbgln("VirtualFileSystem: Mounting unsuccessful - inode {} is already a mount-point.", inode.identifier()); dbgln("VirtualFileSystem: Mounting unsuccessful - inode {} is already a mount-point.", mount_point_inode.identifier());
return EBUSY; return EBUSY;
} }
// Note: Actually add a mount for the filesystem and increment the filesystem mounted count // Note: Actually add a mount for the filesystem and increment the filesystem mounted count
@ -211,7 +231,7 @@ ErrorOr<void> VirtualFileSystem::bind_mount(Custody& source, Custody& mount_poin
return m_mounts.with([&](auto& mounts) -> ErrorOr<void> { return m_mounts.with([&](auto& mounts) -> ErrorOr<void> {
auto& inode = mount_point.inode(); auto& inode = mount_point.inode();
dbgln("VirtualFileSystem: Bind-mounting inode {} at inode {}", source.inode().identifier(), inode.identifier()); dbgln("VirtualFileSystem: Bind-mounting inode {} at inode {}", source.inode().identifier(), inode.identifier());
if (mount_point_exists_at_inode(inode.identifier())) { if (mount_point_exists_at_custody(mount_point)) {
dbgln("VirtualFileSystem: Bind-mounting unsuccessful - inode {} is already a mount-point.", dbgln("VirtualFileSystem: Bind-mounting unsuccessful - inode {} is already a mount-point.",
mount_point.inode().identifier()); mount_point.inode().identifier());
return EBUSY; return EBUSY;

View file

@ -115,7 +115,8 @@ private:
ErrorOr<void> traverse_directory_inode(Inode&, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>); ErrorOr<void> traverse_directory_inode(Inode&, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>);
bool mount_point_exists_at_inode(InodeIdentifier inode); static bool check_matching_absolute_path_hierarchy(Custody const& first_custody, Custody const& second_custody);
bool mount_point_exists_at_custody(Custody& mount_point);
// FIXME: These functions are totally unsafe as someone could unmount the returned Mount underneath us. // FIXME: These functions are totally unsafe as someone could unmount the returned Mount underneath us.
Mount* find_mount_for_host(InodeIdentifier); Mount* find_mount_for_host(InodeIdentifier);