summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Bugaev <bugaevc@serenityos.org>2020-11-21 22:55:20 +0300
committerAndreas Kling <kling@serenityos.org>2020-11-23 18:37:40 +0100
commit098070b767db2d74595829040d8ef55bb3b81bd5 (patch)
tree3b1bbda527a0afa75401f850adcef403a17f250b
parent23dc3ff0c2dc703f2d0649177cf30ab2b8b1e57d (diff)
downloadserenity-098070b767db2d74595829040d8ef55bb3b81bd5.zip
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.
-rw-r--r--Base/usr/share/man/man2/unveil.md4
-rw-r--r--Kernel/FileSystem/ProcFS.cpp2
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.cpp24
-rw-r--r--Kernel/Process.h1
-rw-r--r--Kernel/Syscalls/unveil.cpp5
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<KBuffer> 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<const Syscall::SC_unveil_params*> 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<const Syscall::SC_unveil_params*> user_params)
case 'c':
new_permissions |= UnveiledPath::Access::CreateOrRemove;
break;
+ case 'b':
+ new_permissions |= UnveiledPath::Access::Browse;
+ break;
default:
return -EINVAL;
}