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.
This commit is contained in:
Sergey Bugaev 2020-11-21 22:55:20 +03:00 committed by Andreas Kling
commit 098070b767
Notes: sideshowbarker 2024-07-19 01:17:40 +09:00
5 changed files with 30 additions and 6 deletions

View file

@ -28,6 +28,7 @@ include the following characters:
* `w`: May write to a file at this path * `w`: May write to a file at this path
* `x`: May execute a program image at this path * `x`: May execute a program image at this path
* `c`: May create or remove a file 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. A single `unveil()` call may specify multiple permission characters at once.
Subsequent `unveil()` calls may take away permissions from the ones allowed 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: // Allow the process to execute Calendar:
unveil("/bin/Calendar", "x"); unveil("/bin/Calendar", "x");
// Allow the process to browse files from /usr/share:
unveil("/usr/share", "b");
// Disallow any further veil manipulation: // Disallow any further veil manipulation:
unveil(nullptr, nullptr); unveil(nullptr, nullptr);
``` ```

View file

@ -644,6 +644,8 @@ static Optional<KBuffer> procfs$pid_unveil(InodeIdentifier identifier)
permissions_builder.append('x'); permissions_builder.append('x');
if (unveiled_path.permissions & UnveiledPath::Access::CreateOrRemove) if (unveiled_path.permissions & UnveiledPath::Access::CreateOrRemove)
permissions_builder.append('c'); permissions_builder.append('c');
if (unveiled_path.permissions & UnveiledPath::Access::Browse)
permissions_builder.append('b');
obj.add("permissions", permissions_builder.to_string()); obj.add("permissions", permissions_builder.to_string());
} }
array.finish(); array.finish();

View file

@ -825,7 +825,13 @@ const UnveiledPath* VFS::find_matching_unveiled_path(StringView path)
for (auto& unveiled_path : Process::current()->unveiled_paths()) { for (auto& unveiled_path : Process::current()->unveiled_paths()) {
if (path == unveiled_path.path) if (path == unveiled_path.path)
return &unveiled_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 &unveiled_path;
} }
return nullptr; return nullptr;
@ -863,10 +869,18 @@ KResult VFS::validate_path_against_process_veil(StringView path, int options)
return KSuccess; return KSuccess;
} }
if (options & O_RDONLY) { if (options & O_RDONLY) {
if (!(unveiled_path->permissions & UnveiledPath::Access::Read)) { if (options & O_DIRECTORY) {
dbg() << "Rejecting path '" << path << "' since it hasn't been unveiled with 'r' permission."; if (!(unveiled_path->permissions & (UnveiledPath::Access::Read | UnveiledPath::Access::Browse))) {
dump_backtrace(); dbg() << "Rejecting path '" << path << "' since it hasn't been unveiled with 'r' or 'b' permissions.";
return KResult(-EACCES); 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) { if (options & O_WRONLY) {

View file

@ -101,6 +101,7 @@ struct UnveiledPath {
Write = 2, Write = 2,
Execute = 4, Execute = 4,
CreateOrRemove = 8, CreateOrRemove = 8,
Browse = 16,
}; };
String path; String path;

View file

@ -49,7 +49,7 @@ int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
if (!params.path.characters || !params.permissions.characters) if (!params.path.characters || !params.permissions.characters)
return -EINVAL; return -EINVAL;
if (params.permissions.length > 4) if (params.permissions.length > 5)
return -EINVAL; return -EINVAL;
auto path = get_syscall_path_argument(params.path); 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': case 'c':
new_permissions |= UnveiledPath::Access::CreateOrRemove; new_permissions |= UnveiledPath::Access::CreateOrRemove;
break; break;
case 'b':
new_permissions |= UnveiledPath::Access::Browse;
break;
default: default:
return -EINVAL; return -EINVAL;
} }