Kernel: Fix TOCTOU in fstatvfs
In particular, fstatvfs used to assume that a file that was earlier opened using some path will forever be at that path. This is wrong, and in the meantime new mounts and new filesystems could take up the filename or directories, leading to a completely inaccurate result. This commit improves the situation: - All filesystem information is now always accurate. - The mount flags *might* be erroneously zero, if the custody for the open file is not available. I don't know when that might happen, but it is definitely not the typical case.
This commit is contained in:
parent
26a48f3516
commit
631447da57
Notes:
sideshowbarker
2024-07-18 01:18:55 +09:00
Author: https://github.com/BenWiederhake Commit: https://github.com/SerenityOS/serenity/commit/631447da574 Pull-request: https://github.com/SerenityOS/serenity/pull/10831
2 changed files with 16 additions and 33 deletions
|
@ -535,7 +535,7 @@ private:
|
|||
ErrorOr<void> do_exec(NonnullRefPtr<OpenFileDescription> main_program_description, NonnullOwnPtrVector<KString> arguments, NonnullOwnPtrVector<KString> environment, RefPtr<OpenFileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags, const ElfW(Ehdr) & main_program_header);
|
||||
ErrorOr<FlatPtr> do_write(OpenFileDescription&, const UserOrKernelBuffer&, size_t);
|
||||
|
||||
ErrorOr<FlatPtr> do_statvfs(StringView path, statvfs* buf);
|
||||
ErrorOr<FlatPtr> do_statvfs(FileSystem const& path, Custody const*, statvfs* buf);
|
||||
|
||||
ErrorOr<RefPtr<OpenFileDescription>> find_elf_interpreter_for_executable(StringView path, ElfW(Ehdr) const& main_executable_header, size_t main_executable_header_size, size_t file_size);
|
||||
|
||||
|
|
|
@ -10,12 +10,8 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
ErrorOr<FlatPtr> Process::do_statvfs(StringView path, statvfs* buf)
|
||||
ErrorOr<FlatPtr> Process::do_statvfs(FileSystem const& fs, Custody const* custody, statvfs* buf)
|
||||
{
|
||||
auto custody = TRY(VirtualFileSystem::the().resolve_path(path, current_directory(), nullptr, 0));
|
||||
auto& inode = custody->inode();
|
||||
auto& fs = inode.fs();
|
||||
|
||||
statvfs kernelbuf = {};
|
||||
|
||||
kernelbuf.f_bsize = static_cast<u64>(fs.block_size());
|
||||
|
@ -34,29 +30,8 @@ ErrorOr<FlatPtr> Process::do_statvfs(StringView path, statvfs* buf)
|
|||
|
||||
kernelbuf.f_namemax = 255;
|
||||
|
||||
Custody* current_custody = custody;
|
||||
|
||||
while (current_custody) {
|
||||
VirtualFileSystem::the().for_each_mount([&kernelbuf, ¤t_custody](auto& mount) {
|
||||
if (¤t_custody->inode() == &mount.guest()) {
|
||||
int mountflags = mount.flags();
|
||||
int flags = 0;
|
||||
if (mountflags & MS_RDONLY)
|
||||
flags = flags | ST_RDONLY;
|
||||
if (mountflags & MS_NOSUID)
|
||||
flags = flags | ST_NOSUID;
|
||||
|
||||
kernelbuf.f_flag = flags;
|
||||
current_custody = nullptr;
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
if (current_custody) {
|
||||
current_custody = current_custody->parent();
|
||||
}
|
||||
}
|
||||
if (custody)
|
||||
kernelbuf.f_flag = custody->mount_flags();
|
||||
|
||||
TRY(copy_to_user(buf, &kernelbuf));
|
||||
return 0;
|
||||
|
@ -69,7 +44,12 @@ ErrorOr<FlatPtr> Process::sys$statvfs(Userspace<const Syscall::SC_statvfs_params
|
|||
auto params = TRY(copy_typed_from_user(user_params));
|
||||
|
||||
auto path = TRY(get_syscall_path_argument(params.path));
|
||||
return do_statvfs(path->view(), params.buf);
|
||||
|
||||
auto custody = TRY(VirtualFileSystem::the().resolve_path(path->view(), current_directory(), nullptr, 0));
|
||||
auto& inode = custody->inode();
|
||||
auto const& fs = inode.fs();
|
||||
|
||||
return do_statvfs(fs, custody, params.buf);
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$fstatvfs(int fd, statvfs* buf)
|
||||
|
@ -78,9 +58,12 @@ ErrorOr<FlatPtr> Process::sys$fstatvfs(int fd, statvfs* buf)
|
|||
REQUIRE_PROMISE(stdio);
|
||||
|
||||
auto description = TRY(fds().open_file_description(fd));
|
||||
auto absolute_path = TRY(description->original_absolute_path());
|
||||
// FIXME: TOCTOU bug! The file connected to the fd may or may not have been moved, and the name possibly taken by a different file.
|
||||
return do_statvfs(absolute_path->view(), buf);
|
||||
auto inode = description->inode();
|
||||
if (inode == nullptr)
|
||||
return ENOENT;
|
||||
|
||||
// FIXME: The custody that we pass in might be outdated. However, this only affects the mount flags.
|
||||
return do_statvfs(inode->fs(), description->custody(), buf);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue