From 9681e3eca0c983b0203e7c84c5fb0549c10f29bc Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 19 Jan 2021 17:59:32 +0100 Subject: [PATCH] Kernel: Implement the same hard link protection as Linux sys$link() will now fail to create hard links in some cases where you don't own or have write access to the link target. Work towards #4934 --- Kernel/FileSystem/VirtualFileSystem.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 12020f291a..3e7ef942d5 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -634,6 +634,23 @@ KResult VFS::chown(StringView path, uid_t a_uid, gid_t a_gid, Custody& base) return chown(custody, a_uid, a_gid); } +static bool hard_link_allowed(const Inode& inode) +{ + auto metadata = inode.metadata(); + + if (Process::current()->euid() == metadata.uid) + return true; + + if (metadata.is_regular_file() + && !metadata.is_setuid() + && !(metadata.is_setgid() && metadata.mode & S_IXGRP) + && metadata.may_write(*Process::current())) { + return true; + } + + return false; +} + KResult VFS::link(StringView old_path, StringView new_path, Custody& base) { auto old_custody_or_error = resolve_path(old_path, base); @@ -664,6 +681,9 @@ KResult VFS::link(StringView old_path, StringView new_path, Custody& base) if (parent_custody->is_readonly()) return KResult(-EROFS); + if (!hard_link_allowed(old_inode)) + return KResult(-EPERM); + return parent_inode.add_child(old_inode, LexicalPath(new_path).basename(), old_inode.mode()); }