From 098070b767db2d74595829040d8ef55bb3b81bd5 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 21 Nov 2020 22:55:20 +0300 Subject: Kernel: Add unveil('b') This is a new "browse" permission that lets you open (and subsequently list contents of) directories underneath the path, but not regular files or any other types of files. --- Base/usr/share/man/man2/unveil.md | 4 ++++ Kernel/FileSystem/ProcFS.cpp | 2 ++ Kernel/FileSystem/VirtualFileSystem.cpp | 24 +++++++++++++++++++----- Kernel/Process.h | 1 + Kernel/Syscalls/unveil.cpp | 5 ++++- 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Base/usr/share/man/man2/unveil.md b/Base/usr/share/man/man2/unveil.md index 95f3534e56..ba8c6574ba 100644 --- a/Base/usr/share/man/man2/unveil.md +++ b/Base/usr/share/man/man2/unveil.md @@ -28,6 +28,7 @@ include the following characters: * `w`: May write to a file at this path * `x`: May execute a program image at this path * `c`: May create or remove a file at this path +* `b`: May browse directories at this path A single `unveil()` call may specify multiple permission characters at once. Subsequent `unveil()` calls may take away permissions from the ones allowed @@ -78,6 +79,9 @@ unveil("/etc/WindowServer/WindowServer.ini", "rwc"); // Allow the process to execute Calendar: unveil("/bin/Calendar", "x"); +// Allow the process to browse files from /usr/share: +unveil("/usr/share", "b"); + // Disallow any further veil manipulation: unveil(nullptr, nullptr); ``` diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index 6e5996a23b..4acf07ab14 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -644,6 +644,8 @@ static Optional procfs$pid_unveil(InodeIdentifier identifier) permissions_builder.append('x'); if (unveiled_path.permissions & UnveiledPath::Access::CreateOrRemove) permissions_builder.append('c'); + if (unveiled_path.permissions & UnveiledPath::Access::Browse) + permissions_builder.append('b'); obj.add("permissions", permissions_builder.to_string()); } array.finish(); diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 54092e91c2..2ba9589dcd 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -825,7 +825,13 @@ const UnveiledPath* VFS::find_matching_unveiled_path(StringView path) for (auto& unveiled_path : Process::current()->unveiled_paths()) { if (path == unveiled_path.path) return &unveiled_path; - if (path.starts_with(unveiled_path.path) && path.length() > unveiled_path.path.length() && path[unveiled_path.path.length()] == '/') + if (!path.starts_with(unveiled_path.path)) + continue; + // /foo/ and /foo/bar + if (unveiled_path.path.ends_with('/')) + return &unveiled_path; + // /foo and /foo/bar + if (path.length() > unveiled_path.path.length() && path[unveiled_path.path.length()] == '/') return &unveiled_path; } return nullptr; @@ -863,10 +869,18 @@ KResult VFS::validate_path_against_process_veil(StringView path, int options) return KSuccess; } if (options & O_RDONLY) { - if (!(unveiled_path->permissions & UnveiledPath::Access::Read)) { - dbg() << "Rejecting path '" << path << "' since it hasn't been unveiled with 'r' permission."; - dump_backtrace(); - return KResult(-EACCES); + if (options & O_DIRECTORY) { + if (!(unveiled_path->permissions & (UnveiledPath::Access::Read | UnveiledPath::Access::Browse))) { + dbg() << "Rejecting path '" << path << "' since it hasn't been unveiled with 'r' or 'b' permissions."; + dump_backtrace(); + return KResult(-EACCES); + } + } else { + if (!(unveiled_path->permissions & UnveiledPath::Access::Read)) { + dbg() << "Rejecting path '" << path << "' since it hasn't been unveiled with 'r' permission."; + dump_backtrace(); + return KResult(-EACCES); + } } } if (options & O_WRONLY) { diff --git a/Kernel/Process.h b/Kernel/Process.h index f62671fd74..1700047d2c 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -101,6 +101,7 @@ struct UnveiledPath { Write = 2, Execute = 4, CreateOrRemove = 8, + Browse = 16, }; String path; diff --git a/Kernel/Syscalls/unveil.cpp b/Kernel/Syscalls/unveil.cpp index e2da0452cf..57807cd8e9 100644 --- a/Kernel/Syscalls/unveil.cpp +++ b/Kernel/Syscalls/unveil.cpp @@ -49,7 +49,7 @@ int Process::sys$unveil(Userspace user_params) if (!params.path.characters || !params.permissions.characters) return -EINVAL; - if (params.permissions.length > 4) + if (params.permissions.length > 5) return -EINVAL; auto path = get_syscall_path_argument(params.path); @@ -79,6 +79,9 @@ int Process::sys$unveil(Userspace user_params) case 'c': new_permissions |= UnveiledPath::Access::CreateOrRemove; break; + case 'b': + new_permissions |= UnveiledPath::Access::Browse; + break; default: return -EINVAL; } -- cgit v1.2.3