Kernel/VFS: Check matching absolute path when jump to mount guest inode

We could easily encounter a case where we do the following:

```
mkdir -p /tmp2
mount /dev/hda /tmp2
```

would produce a bug that doing `ls /tmp2/tmp2` will give the contents
on `/dev/hda` ext2 root directory and also on `/tmp2/tmp2/tmp2` and so
on.
To prevent this, we must compare the current custody against each mount
entry's custody to ensure their paths match.
This commit is contained in:
Liav A 2023-08-04 22:03:24 +03:00 committed by Jelle Raaijmakers
parent 80f400a150
commit e5c7662638
2 changed files with 22 additions and 8 deletions

View file

@ -378,12 +378,23 @@ ErrorOr<void> VirtualFileSystem::mount_root(FileSystem& fs)
return {};
}
auto VirtualFileSystem::find_mount_for_host(InodeIdentifier id) -> Mount*
auto VirtualFileSystem::find_mount_for_host_custody(Custody const& current_custody) -> Mount*
{
return m_mounts.with([&](auto& mounts) -> Mount* {
for (auto& mount : mounts) {
if (mount.host() && mount.host()->identifier() == id)
return &mount;
// NOTE: We either search for the root mount or for a mount that has a parent custody!
if (!current_custody.parent()) {
for (auto& mount : mounts) {
if (!mount.host_custody())
return &mount;
}
// NOTE: There must be a root mount entry, so fail if we don't find it.
VERIFY_NOT_REACHED();
} else {
for (auto& mount : mounts) {
if (mount.host_custody() && check_matching_absolute_path_hierarchy(*mount.host_custody(), current_custody)) {
return &mount;
}
}
}
return nullptr;
});
@ -1232,15 +1243,18 @@ ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::resolve_path_without_veil(Cre
int mount_flags_for_child = parent.mount_flags();
auto current_custody = TRY(Custody::try_create(&parent, part, *child_inode, mount_flags_for_child));
// See if there's something mounted on the child; in that case
// we would need to return the guest inode, not the host inode.
if (auto mount = find_mount_for_host(child_inode->identifier())) {
if (auto mount = find_mount_for_host_custody(current_custody)) {
child_inode = mount->guest();
mount_flags_for_child = mount->flags();
custody = TRY(Custody::try_create(&parent, part, *child_inode, mount_flags_for_child));
} else {
custody = current_custody;
}
custody = TRY(Custody::try_create(&parent, part, *child_inode, mount_flags_for_child));
if (child_inode->metadata().is_symlink()) {
if (!have_more_parts) {
if (options & O_NOFOLLOW)

View file

@ -119,7 +119,7 @@ private:
bool mount_point_exists_at_custody(Custody& mount_point);
// 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_custody(Custody const& current_custody);
Mount* find_mount_for_guest(InodeIdentifier);
RefPtr<Inode> m_root_inode;