From 8601108e2117a4d1d5bbc2a1c5510b1c49920889 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 19 Jan 2021 18:12:09 +0100 Subject: [PATCH] Kernel: Implement the same symlink protection as Linux Path resolution will now refuse to follow symlinks in some cases where you don't own the symlink, or when it's in a sticky world-writable directory and the link has a different owner than the directory. The point of all this is to prevent classic TOCTOU bugs in /tmp etc. Fixes #4934 --- Kernel/FileSystem/VirtualFileSystem.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 3e7ef942d5..30c3e3009c 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -952,6 +952,21 @@ KResultOr> VFS::resolve_path(StringView path, Custody& ba return custody; } +static bool safe_to_follow_symlink(const Inode& inode, const InodeMetadata& parent_metadata) +{ + auto metadata = inode.metadata(); + if (Process::current()->euid() == metadata.uid) + return true; + + if (!(parent_metadata.is_sticky() && parent_metadata.mode & S_IWOTH)) + return true; + + if (metadata.uid == parent_metadata.uid) + return true; + + return false; +} + KResultOr> VFS::resolve_path_without_veil(StringView path, Custody& base, RefPtr* out_parent, int options, int symlink_recursion_level) { if (symlink_recursion_level >= symlink_recursion_limit) @@ -1017,6 +1032,10 @@ KResultOr> VFS::resolve_path_without_veil(StringView path if (options & O_NOFOLLOW_NOERROR) break; } + + if (!safe_to_follow_symlink(*child_inode, parent_metadata)) + return KResult(-EACCES); + auto symlink_target = child_inode->resolve_as_link(parent, out_parent, options, symlink_recursion_level + 1); if (symlink_target.is_error() || !have_more_parts) return symlink_target;