Kernel: Make VirtualFileSystem functions take credentials as input

Instead of getting credentials from Process::current(), we now require
that they be provided as input to the various VFS functions.

This ensures that an atomic set of credentials is used throughout an
entire VFS operation.
This commit is contained in:
Andreas Kling 2022-08-21 16:02:24 +02:00
parent 9744dedb50
commit c3351d4b9f
33 changed files with 159 additions and 165 deletions

View file

@ -62,19 +62,21 @@ Coredump::Coredump(NonnullLockRefPtr<Process> process, NonnullLockRefPtr<OpenFil
ErrorOr<NonnullLockRefPtr<OpenFileDescription>> Coredump::try_create_target_file(Process const& process, StringView output_path) ErrorOr<NonnullLockRefPtr<OpenFileDescription>> Coredump::try_create_target_file(Process const& process, StringView output_path)
{ {
auto output_directory = KLexicalPath::dirname(output_path); auto output_directory = KLexicalPath::dirname(output_path);
auto dump_directory = TRY(VirtualFileSystem::the().open_directory(output_directory, VirtualFileSystem::the().root_custody())); auto dump_directory = TRY(VirtualFileSystem::the().open_directory(Process::current().credentials(), output_directory, VirtualFileSystem::the().root_custody()));
auto dump_directory_metadata = dump_directory->inode().metadata(); auto dump_directory_metadata = dump_directory->inode().metadata();
if (dump_directory_metadata.uid != 0 || dump_directory_metadata.gid != 0 || dump_directory_metadata.mode != 040777) { if (dump_directory_metadata.uid != 0 || dump_directory_metadata.gid != 0 || dump_directory_metadata.mode != 040777) {
dbgln("Refusing to put coredump in sketchy directory '{}'", output_directory); dbgln("Refusing to put coredump in sketchy directory '{}'", output_directory);
return EINVAL; return EINVAL;
} }
auto credentials = process.credentials();
auto process_credentials = process.credentials();
return TRY(VirtualFileSystem::the().open( return TRY(VirtualFileSystem::the().open(
Process::current().credentials(),
KLexicalPath::basename(output_path), KLexicalPath::basename(output_path),
O_CREAT | O_WRONLY | O_EXCL, O_CREAT | O_WRONLY | O_EXCL,
S_IFREG, // We will enable reading from userspace when we finish generating the coredump file S_IFREG, // We will enable reading from userspace when we finish generating the coredump file
*dump_directory, *dump_directory,
UidAndGid { credentials->uid(), credentials->gid() })); UidAndGid { process_credentials->uid(), process_credentials->gid() }));
} }
ErrorOr<void> Coredump::write_elf_header() ErrorOr<void> Coredump::write_elf_header()

View file

@ -29,4 +29,9 @@ Credentials::Credentials(UserID uid, GroupID gid, UserID euid, GroupID egid, Use
Credentials::~Credentials() = default; Credentials::~Credentials() = default;
bool Credentials::in_group(Kernel::GroupID gid) const
{
return m_gid == gid || m_extra_gids.contains_slow(gid);
}
} }

View file

@ -27,6 +27,8 @@ public:
GroupID sgid() const { return m_sgid; } GroupID sgid() const { return m_sgid; }
Span<GroupID const> extra_gids() const { return m_extra_gids.span(); } Span<GroupID const> extra_gids() const { return m_extra_gids.span(); }
bool in_group(GroupID) const;
private: private:
Credentials(UserID uid, GroupID gid, UserID euid, GroupID egid, UserID suid, GroupID sgid, FixedArray<GroupID> extra_gids); Credentials(UserID uid, GroupID gid, UserID euid, GroupID egid, UserID suid, GroupID sgid, FixedArray<GroupID> extra_gids);

View file

@ -82,7 +82,7 @@ ErrorOr<NonnullRefPtr<Custody>> Inode::resolve_as_link(Custody& base, RefPtr<Cus
// contents as a path and resolves that. That is, it // contents as a path and resolves that. That is, it
// behaves exactly how you would expect a symlink to work. // behaves exactly how you would expect a symlink to work.
auto contents = TRY(read_entire()); auto contents = TRY(read_entire());
return VirtualFileSystem::the().resolve_path(StringView { contents->bytes() }, base, out_parent, options, symlink_recursion_level); return VirtualFileSystem::the().resolve_path(Process::current().credentials(), StringView { contents->bytes() }, base, out_parent, options, symlink_recursion_level);
} }
Inode::Inode(FileSystem& fs, InodeIndex index) Inode::Inode(FileSystem& fs, InodeIndex index)

View file

@ -119,14 +119,14 @@ ErrorOr<void> InodeFile::chown(OpenFileDescription& description, UserID uid, Gro
{ {
VERIFY(description.inode() == m_inode); VERIFY(description.inode() == m_inode);
VERIFY(description.custody()); VERIFY(description.custody());
return VirtualFileSystem::the().chown(*description.custody(), uid, gid); return VirtualFileSystem::the().chown(Process::current().credentials(), *description.custody(), uid, gid);
} }
ErrorOr<void> InodeFile::chmod(OpenFileDescription& description, mode_t mode) ErrorOr<void> InodeFile::chmod(OpenFileDescription& description, mode_t mode)
{ {
VERIFY(description.inode() == m_inode); VERIFY(description.inode() == m_inode);
VERIFY(description.custody()); VERIFY(description.custody());
return VirtualFileSystem::the().chmod(*description.custody(), mode); return VirtualFileSystem::the().chmod(Process::current().credentials(), *description.custody(), mode);
} }
} }

View file

@ -9,22 +9,19 @@
namespace Kernel { namespace Kernel {
bool InodeMetadata::may_read(Process const& process) const bool InodeMetadata::may_read(Credentials const& credentials) const
{ {
auto credentials = process.credentials(); return may_read(credentials.euid(), credentials.egid(), credentials.extra_gids());
return may_read(credentials->euid(), credentials->egid(), credentials->extra_gids());
} }
bool InodeMetadata::may_write(Process const& process) const bool InodeMetadata::may_write(Credentials const& credentials) const
{ {
auto credentials = process.credentials(); return may_write(credentials.euid(), credentials.egid(), credentials.extra_gids());
return may_write(credentials->euid(), credentials->egid(), credentials->extra_gids());
} }
bool InodeMetadata::may_execute(Process const& process) const bool InodeMetadata::may_execute(Credentials const& credentials) const
{ {
auto credentials = process.credentials(); return may_execute(credentials.euid(), credentials.egid(), credentials.extra_gids());
return may_execute(credentials->euid(), credentials->egid(), credentials->extra_gids());
} }
} }

View file

@ -42,6 +42,10 @@ struct InodeMetadata {
bool may_write(Process const&) const; bool may_write(Process const&) const;
bool may_execute(Process const&) const; bool may_execute(Process const&) const;
bool may_read(Credentials const&) const;
bool may_write(Credentials const&) const;
bool may_execute(Credentials const&) const;
bool may_read(UserID u, GroupID g, Span<GroupID const> eg) const bool may_read(UserID u, GroupID g, Span<GroupID const> eg) const
{ {
if (u == 0) if (u == 0)

View file

@ -204,12 +204,11 @@ ErrorOr<void> VirtualFileSystem::traverse_directory_inode(Inode& dir_inode, Func
}); });
} }
ErrorOr<void> VirtualFileSystem::utime(StringView path, Custody& base, time_t atime, time_t mtime) ErrorOr<void> VirtualFileSystem::utime(Credentials const& credentials, StringView path, Custody& base, time_t atime, time_t mtime)
{ {
auto custody = TRY(resolve_path(path, base)); auto custody = TRY(resolve_path(credentials, path, base));
auto& inode = custody->inode(); auto& inode = custody->inode();
auto& current_process = Process::current(); if (!credentials.is_superuser() && inode.metadata().uid != credentials.euid())
if (!current_process.is_superuser() && inode.metadata().uid != current_process.euid())
return EACCES; return EACCES;
if (custody->is_readonly()) if (custody->is_readonly())
return EROFS; return EROFS;
@ -219,12 +218,11 @@ ErrorOr<void> VirtualFileSystem::utime(StringView path, Custody& base, time_t at
return {}; return {};
} }
ErrorOr<void> VirtualFileSystem::utimensat(StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options) ErrorOr<void> VirtualFileSystem::utimensat(Credentials const& credentials, StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options)
{ {
auto custody = TRY(resolve_path(path, base, nullptr, options)); auto custody = TRY(resolve_path(credentials, path, base, nullptr, options));
auto& inode = custody->inode(); auto& inode = custody->inode();
auto& current_process = Process::current(); if (!credentials.is_superuser() && inode.metadata().uid != credentials.euid())
if (!current_process.is_superuser() && inode.metadata().uid != current_process.euid())
return EACCES; return EACCES;
if (custody->is_readonly()) if (custody->is_readonly())
return EROFS; return EROFS;
@ -238,24 +236,24 @@ ErrorOr<void> VirtualFileSystem::utimensat(StringView path, Custody& base, times
return {}; return {};
} }
ErrorOr<InodeMetadata> VirtualFileSystem::lookup_metadata(StringView path, Custody& base, int options) ErrorOr<InodeMetadata> VirtualFileSystem::lookup_metadata(Credentials const& credentials, StringView path, Custody& base, int options)
{ {
auto custody = TRY(resolve_path(path, base, nullptr, options)); auto custody = TRY(resolve_path(credentials, path, base, nullptr, options));
return custody->inode().metadata(); return custody->inode().metadata();
} }
ErrorOr<NonnullLockRefPtr<OpenFileDescription>> VirtualFileSystem::open(StringView path, int options, mode_t mode, Custody& base, Optional<UidAndGid> owner) ErrorOr<NonnullLockRefPtr<OpenFileDescription>> VirtualFileSystem::open(Credentials const& credentials, StringView path, int options, mode_t mode, Custody& base, Optional<UidAndGid> owner)
{ {
if ((options & O_CREAT) && (options & O_DIRECTORY)) if ((options & O_CREAT) && (options & O_DIRECTORY))
return EINVAL; return EINVAL;
RefPtr<Custody> parent_custody; RefPtr<Custody> parent_custody;
auto custody_or_error = resolve_path(path, base, &parent_custody, options); auto custody_or_error = resolve_path(credentials, path, base, &parent_custody, options);
if (custody_or_error.is_error()) { if (custody_or_error.is_error()) {
// NOTE: ENOENT with a non-null parent custody signals us that the immediate parent // NOTE: ENOENT with a non-null parent custody signals us that the immediate parent
// of the file exists, but the file itself does not. // of the file exists, but the file itself does not.
if ((options & O_CREAT) && custody_or_error.error().code() == ENOENT && parent_custody) if ((options & O_CREAT) && custody_or_error.error().code() == ENOENT && parent_custody)
return create(path, options, mode, *parent_custody, move(owner)); return create(credentials, path, options, mode, *parent_custody, move(owner));
return custody_or_error.release_error(); return custody_or_error.release_error();
} }
@ -271,19 +269,18 @@ ErrorOr<NonnullLockRefPtr<OpenFileDescription>> VirtualFileSystem::open(StringVi
bool should_truncate_file = false; bool should_truncate_file = false;
auto& current_process = Process::current(); if ((options & O_RDONLY) && !metadata.may_read(credentials))
if ((options & O_RDONLY) && !metadata.may_read(current_process))
return EACCES; return EACCES;
if (options & O_WRONLY) { if (options & O_WRONLY) {
if (!metadata.may_write(current_process)) if (!metadata.may_write(credentials))
return EACCES; return EACCES;
if (metadata.is_directory()) if (metadata.is_directory())
return EISDIR; return EISDIR;
should_truncate_file = options & O_TRUNC; should_truncate_file = options & O_TRUNC;
} }
if (options & O_EXEC) { if (options & O_EXEC) {
if (!metadata.may_execute(current_process) || (custody.mount_flags() & MS_NOEXEC)) if (!metadata.may_execute(credentials) || (custody.mount_flags() & MS_NOEXEC))
return EACCES; return EACCES;
} }
@ -332,13 +329,13 @@ ErrorOr<NonnullLockRefPtr<OpenFileDescription>> VirtualFileSystem::open(StringVi
return description; return description;
} }
ErrorOr<void> VirtualFileSystem::mknod(StringView path, mode_t mode, dev_t dev, Custody& base) ErrorOr<void> VirtualFileSystem::mknod(Credentials const& credentials, StringView path, mode_t mode, dev_t dev, Custody& base)
{ {
if (!is_regular_file(mode) && !is_block_device(mode) && !is_character_device(mode) && !is_fifo(mode) && !is_socket(mode)) if (!is_regular_file(mode) && !is_block_device(mode) && !is_character_device(mode) && !is_fifo(mode) && !is_socket(mode))
return EINVAL; return EINVAL;
RefPtr<Custody> parent_custody; RefPtr<Custody> parent_custody;
auto existing_file_or_error = resolve_path(path, base, &parent_custody); auto existing_file_or_error = resolve_path(credentials, path, base, &parent_custody);
if (!existing_file_or_error.is_error()) if (!existing_file_or_error.is_error())
return EEXIST; return EEXIST;
if (!parent_custody) if (!parent_custody)
@ -346,20 +343,18 @@ ErrorOr<void> VirtualFileSystem::mknod(StringView path, mode_t mode, dev_t dev,
if (existing_file_or_error.error().code() != ENOENT) if (existing_file_or_error.error().code() != ENOENT)
return existing_file_or_error.release_error(); return existing_file_or_error.release_error();
auto& parent_inode = parent_custody->inode(); auto& parent_inode = parent_custody->inode();
auto& current_process = Process::current(); if (!parent_inode.metadata().may_write(credentials))
auto current_process_credentials = current_process.credentials();
if (!parent_inode.metadata().may_write(current_process))
return EACCES; return EACCES;
if (parent_custody->is_readonly()) if (parent_custody->is_readonly())
return EROFS; return EROFS;
auto basename = KLexicalPath::basename(path); auto basename = KLexicalPath::basename(path);
dbgln_if(VFS_DEBUG, "VirtualFileSystem::mknod: '{}' mode={} dev={} in {}", basename, mode, dev, parent_inode.identifier()); dbgln_if(VFS_DEBUG, "VirtualFileSystem::mknod: '{}' mode={} dev={} in {}", basename, mode, dev, parent_inode.identifier());
(void)TRY(parent_inode.create_child(basename, mode, dev, current_process_credentials->euid(), current_process_credentials->egid())); (void)TRY(parent_inode.create_child(basename, mode, dev, credentials.euid(), credentials.egid()));
return {}; return {};
} }
ErrorOr<NonnullLockRefPtr<OpenFileDescription>> VirtualFileSystem::create(StringView path, int options, mode_t mode, Custody& parent_custody, Optional<UidAndGid> owner) ErrorOr<NonnullLockRefPtr<OpenFileDescription>> VirtualFileSystem::create(Credentials const& credentials, StringView path, int options, mode_t mode, Custody& parent_custody, Optional<UidAndGid> owner)
{ {
auto basename = KLexicalPath::basename(path); auto basename = KLexicalPath::basename(path);
auto parent_path = TRY(parent_custody.try_serialize_absolute_path()); auto parent_path = TRY(parent_custody.try_serialize_absolute_path());
@ -372,16 +367,14 @@ ErrorOr<NonnullLockRefPtr<OpenFileDescription>> VirtualFileSystem::create(String
} }
auto& parent_inode = parent_custody.inode(); auto& parent_inode = parent_custody.inode();
auto& current_process = Process::current(); if (!parent_inode.metadata().may_write(credentials))
auto current_process_credentials = current_process.credentials();
if (!parent_inode.metadata().may_write(current_process))
return EACCES; return EACCES;
if (parent_custody.is_readonly()) if (parent_custody.is_readonly())
return EROFS; return EROFS;
dbgln_if(VFS_DEBUG, "VirtualFileSystem::create: '{}' in {}", basename, parent_inode.identifier()); dbgln_if(VFS_DEBUG, "VirtualFileSystem::create: '{}' in {}", basename, parent_inode.identifier());
auto uid = owner.has_value() ? owner.value().uid : current_process_credentials->euid(); auto uid = owner.has_value() ? owner.value().uid : credentials.euid();
auto gid = owner.has_value() ? owner.value().gid : current_process_credentials->egid(); auto gid = owner.has_value() ? owner.value().gid : credentials.egid();
auto inode = TRY(parent_inode.create_child(basename, mode, 0, uid, gid)); auto inode = TRY(parent_inode.create_child(basename, mode, 0, uid, gid));
auto custody = TRY(Custody::try_create(&parent_custody, basename, inode, parent_custody.mount_flags())); auto custody = TRY(Custody::try_create(&parent_custody, basename, inode, parent_custody.mount_flags()));
@ -392,7 +385,7 @@ ErrorOr<NonnullLockRefPtr<OpenFileDescription>> VirtualFileSystem::create(String
return description; return description;
} }
ErrorOr<void> VirtualFileSystem::mkdir(StringView path, mode_t mode, Custody& base) ErrorOr<void> VirtualFileSystem::mkdir(Credentials const& credentials, StringView path, mode_t mode, Custody& base)
{ {
// Unlike in basically every other case, where it's only the last // Unlike in basically every other case, where it's only the last
// path component (the one being created) that is allowed not to // path component (the one being created) that is allowed not to
@ -407,7 +400,7 @@ ErrorOr<void> VirtualFileSystem::mkdir(StringView path, mode_t mode, Custody& ba
RefPtr<Custody> parent_custody; RefPtr<Custody> parent_custody;
// FIXME: The errors returned by resolve_path_without_veil can leak information about paths that are not unveiled, // FIXME: The errors returned by resolve_path_without_veil can leak information about paths that are not unveiled,
// e.g. when the error is EACCESS or similar. // e.g. when the error is EACCESS or similar.
auto result = resolve_path_without_veil(path, base, &parent_custody); auto result = resolve_path_without_veil(credentials, path, base, &parent_custody);
if (!result.is_error()) if (!result.is_error())
return EEXIST; return EEXIST;
else if (!parent_custody) else if (!parent_custody)
@ -417,60 +410,56 @@ ErrorOr<void> VirtualFileSystem::mkdir(StringView path, mode_t mode, Custody& ba
TRY(validate_path_against_process_veil(*parent_custody, O_CREAT)); TRY(validate_path_against_process_veil(*parent_custody, O_CREAT));
auto& parent_inode = parent_custody->inode(); auto& parent_inode = parent_custody->inode();
auto& current_process = Process::current(); if (!parent_inode.metadata().may_write(credentials))
auto current_process_credentials = current_process.credentials();
if (!parent_inode.metadata().may_write(current_process))
return EACCES; return EACCES;
if (parent_custody->is_readonly()) if (parent_custody->is_readonly())
return EROFS; return EROFS;
auto basename = KLexicalPath::basename(path); auto basename = KLexicalPath::basename(path);
dbgln_if(VFS_DEBUG, "VirtualFileSystem::mkdir: '{}' in {}", basename, parent_inode.identifier()); dbgln_if(VFS_DEBUG, "VirtualFileSystem::mkdir: '{}' in {}", basename, parent_inode.identifier());
(void)TRY(parent_inode.create_child(basename, S_IFDIR | mode, 0, current_process_credentials->euid(), current_process_credentials->egid())); (void)TRY(parent_inode.create_child(basename, S_IFDIR | mode, 0, credentials.euid(), credentials.egid()));
return {}; return {};
} }
ErrorOr<void> VirtualFileSystem::access(StringView path, int mode, Custody& base) ErrorOr<void> VirtualFileSystem::access(Credentials const& credentials, StringView path, int mode, Custody& base)
{ {
auto custody = TRY(resolve_path(path, base)); auto custody = TRY(resolve_path(credentials, path, base));
auto& inode = custody->inode(); auto& inode = custody->inode();
auto metadata = inode.metadata(); auto metadata = inode.metadata();
auto& current_process = Process::current();
if (mode & R_OK) { if (mode & R_OK) {
if (!metadata.may_read(current_process)) if (!metadata.may_read(credentials))
return EACCES; return EACCES;
} }
if (mode & W_OK) { if (mode & W_OK) {
if (!metadata.may_write(current_process)) if (!metadata.may_write(credentials))
return EACCES; return EACCES;
if (custody->is_readonly()) if (custody->is_readonly())
return EROFS; return EROFS;
} }
if (mode & X_OK) { if (mode & X_OK) {
if (!metadata.may_execute(current_process)) if (!metadata.may_execute(credentials))
return EACCES; return EACCES;
} }
return {}; return {};
} }
ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::open_directory(StringView path, Custody& base) ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::open_directory(Credentials const& credentials, StringView path, Custody& base)
{ {
auto custody = TRY(resolve_path(path, base)); auto custody = TRY(resolve_path(credentials, path, base));
auto& inode = custody->inode(); auto& inode = custody->inode();
if (!inode.is_directory()) if (!inode.is_directory())
return ENOTDIR; return ENOTDIR;
if (!inode.metadata().may_execute(Process::current())) if (!inode.metadata().may_execute(credentials))
return EACCES; return EACCES;
return custody; return custody;
} }
ErrorOr<void> VirtualFileSystem::chmod(Custody& custody, mode_t mode) ErrorOr<void> VirtualFileSystem::chmod(Credentials const& credentials, Custody& custody, mode_t mode)
{ {
auto& inode = custody.inode(); auto& inode = custody.inode();
auto& current_process = Process::current(); if (credentials.euid() != inode.metadata().uid && !credentials.is_superuser())
if (current_process.euid() != inode.metadata().uid && !current_process.is_superuser())
return EPERM; return EPERM;
if (custody.is_readonly()) if (custody.is_readonly())
return EROFS; return EROFS;
@ -480,20 +469,20 @@ ErrorOr<void> VirtualFileSystem::chmod(Custody& custody, mode_t mode)
return inode.chmod(mode); return inode.chmod(mode);
} }
ErrorOr<void> VirtualFileSystem::chmod(StringView path, mode_t mode, Custody& base, int options) ErrorOr<void> VirtualFileSystem::chmod(Credentials const& credentials, StringView path, mode_t mode, Custody& base, int options)
{ {
auto custody = TRY(resolve_path(path, base, nullptr, options)); auto custody = TRY(resolve_path(credentials, path, base, nullptr, options));
return chmod(custody, mode); return chmod(credentials, custody, mode);
} }
ErrorOr<void> VirtualFileSystem::rename(StringView old_path, StringView new_path, Custody& base) ErrorOr<void> VirtualFileSystem::rename(Credentials const& credentials, StringView old_path, StringView new_path, Custody& base)
{ {
RefPtr<Custody> old_parent_custody; RefPtr<Custody> old_parent_custody;
auto old_custody = TRY(resolve_path(old_path, base, &old_parent_custody, O_NOFOLLOW_NOERROR)); auto old_custody = TRY(resolve_path(credentials, old_path, base, &old_parent_custody, O_NOFOLLOW_NOERROR));
auto& old_inode = old_custody->inode(); auto& old_inode = old_custody->inode();
RefPtr<Custody> new_parent_custody; RefPtr<Custody> new_parent_custody;
auto new_custody_or_error = resolve_path(new_path, base, &new_parent_custody); auto new_custody_or_error = resolve_path(credentials, new_path, base, &new_parent_custody);
if (new_custody_or_error.is_error()) { if (new_custody_or_error.is_error()) {
if (new_custody_or_error.error().code() != ENOENT || !new_parent_custody) if (new_custody_or_error.error().code() != ENOENT || !new_parent_custody)
return new_custody_or_error.release_error(); return new_custody_or_error.release_error();
@ -528,15 +517,14 @@ ErrorOr<void> VirtualFileSystem::rename(StringView old_path, StringView new_path
return EDIRINTOSELF; return EDIRINTOSELF;
} }
auto& current_process = Process::current(); if (!new_parent_inode.metadata().may_write(credentials))
if (!new_parent_inode.metadata().may_write(current_process))
return EACCES; return EACCES;
if (!old_parent_inode.metadata().may_write(current_process)) if (!old_parent_inode.metadata().may_write(credentials))
return EACCES; return EACCES;
if (old_parent_inode.metadata().is_sticky()) { if (old_parent_inode.metadata().is_sticky()) {
if (!current_process.is_superuser() && old_inode.metadata().uid != current_process.euid()) if (!credentials.is_superuser() && old_inode.metadata().uid != credentials.euid())
return EACCES; return EACCES;
} }
@ -561,7 +549,7 @@ ErrorOr<void> VirtualFileSystem::rename(StringView old_path, StringView new_path
if (&new_inode == &old_inode) if (&new_inode == &old_inode)
return {}; return {};
if (new_parent_inode.metadata().is_sticky()) { if (new_parent_inode.metadata().is_sticky()) {
if (!current_process.is_superuser() && new_inode.metadata().uid != current_process.euid()) if (!credentials.is_superuser() && new_inode.metadata().uid != credentials.euid())
return EACCES; return EACCES;
} }
if (new_inode.is_directory() && !old_inode.is_directory()) if (new_inode.is_directory() && !old_inode.is_directory())
@ -574,25 +562,24 @@ ErrorOr<void> VirtualFileSystem::rename(StringView old_path, StringView new_path
return {}; return {};
} }
ErrorOr<void> VirtualFileSystem::chown(Custody& custody, UserID a_uid, GroupID a_gid) ErrorOr<void> VirtualFileSystem::chown(Credentials const& credentials, Custody& custody, UserID a_uid, GroupID a_gid)
{ {
auto& inode = custody.inode(); auto& inode = custody.inode();
auto metadata = inode.metadata(); auto metadata = inode.metadata();
auto& current_process = Process::current(); if (credentials.euid() != metadata.uid && !credentials.is_superuser())
if (current_process.euid() != metadata.uid && !current_process.is_superuser())
return EPERM; return EPERM;
UserID new_uid = metadata.uid; UserID new_uid = metadata.uid;
GroupID new_gid = metadata.gid; GroupID new_gid = metadata.gid;
if (a_uid != (uid_t)-1) { if (a_uid != (uid_t)-1) {
if (current_process.euid() != a_uid && !current_process.is_superuser()) if (credentials.euid() != a_uid && !credentials.is_superuser())
return EPERM; return EPERM;
new_uid = a_uid; new_uid = a_uid;
} }
if (a_gid != (gid_t)-1) { if (a_gid != (gid_t)-1) {
if (!current_process.in_group(a_gid) && !current_process.is_superuser()) if (!credentials.in_group(a_gid) && !credentials.is_superuser())
return EPERM; return EPERM;
new_gid = a_gid; new_gid = a_gid;
} }
@ -610,36 +597,36 @@ ErrorOr<void> VirtualFileSystem::chown(Custody& custody, UserID a_uid, GroupID a
return inode.chown(new_uid, new_gid); return inode.chown(new_uid, new_gid);
} }
ErrorOr<void> VirtualFileSystem::chown(StringView path, UserID a_uid, GroupID a_gid, Custody& base, int options) ErrorOr<void> VirtualFileSystem::chown(Credentials const& credentials, StringView path, UserID a_uid, GroupID a_gid, Custody& base, int options)
{ {
auto custody = TRY(resolve_path(path, base, nullptr, options)); auto custody = TRY(resolve_path(credentials, path, base, nullptr, options));
return chown(custody, a_uid, a_gid); return chown(credentials, custody, a_uid, a_gid);
} }
static bool hard_link_allowed(Inode const& inode) static bool hard_link_allowed(Credentials const& credentials, Inode const& inode)
{ {
auto metadata = inode.metadata(); auto metadata = inode.metadata();
if (Process::current().euid() == metadata.uid) if (credentials.euid() == metadata.uid)
return true; return true;
if (metadata.is_regular_file() if (metadata.is_regular_file()
&& !metadata.is_setuid() && !metadata.is_setuid()
&& !(metadata.is_setgid() && metadata.mode & S_IXGRP) && !(metadata.is_setgid() && metadata.mode & S_IXGRP)
&& metadata.may_write(Process::current())) { && metadata.may_write(credentials)) {
return true; return true;
} }
return false; return false;
} }
ErrorOr<void> VirtualFileSystem::link(StringView old_path, StringView new_path, Custody& base) ErrorOr<void> VirtualFileSystem::link(Credentials const& credentials, StringView old_path, StringView new_path, Custody& base)
{ {
auto old_custody = TRY(resolve_path(old_path, base)); auto old_custody = TRY(resolve_path(credentials, old_path, base));
auto& old_inode = old_custody->inode(); auto& old_inode = old_custody->inode();
RefPtr<Custody> parent_custody; RefPtr<Custody> parent_custody;
auto new_custody_or_error = resolve_path(new_path, base, &parent_custody); auto new_custody_or_error = resolve_path(credentials, new_path, base, &parent_custody);
if (!new_custody_or_error.is_error()) if (!new_custody_or_error.is_error())
return EEXIST; return EEXIST;
@ -651,7 +638,7 @@ ErrorOr<void> VirtualFileSystem::link(StringView old_path, StringView new_path,
if (parent_inode.fsid() != old_inode.fsid()) if (parent_inode.fsid() != old_inode.fsid())
return EXDEV; return EXDEV;
if (!parent_inode.metadata().may_write(Process::current())) if (!parent_inode.metadata().may_write(credentials))
return EACCES; return EACCES;
if (old_inode.is_directory()) if (old_inode.is_directory())
@ -660,16 +647,16 @@ ErrorOr<void> VirtualFileSystem::link(StringView old_path, StringView new_path,
if (parent_custody->is_readonly()) if (parent_custody->is_readonly())
return EROFS; return EROFS;
if (!hard_link_allowed(old_inode)) if (!hard_link_allowed(credentials, old_inode))
return EPERM; return EPERM;
return parent_inode.add_child(old_inode, KLexicalPath::basename(new_path), old_inode.mode()); return parent_inode.add_child(old_inode, KLexicalPath::basename(new_path), old_inode.mode());
} }
ErrorOr<void> VirtualFileSystem::unlink(StringView path, Custody& base) ErrorOr<void> VirtualFileSystem::unlink(Credentials const& credentials, StringView path, Custody& base)
{ {
RefPtr<Custody> parent_custody; RefPtr<Custody> parent_custody;
auto custody = TRY(resolve_path(path, base, &parent_custody, O_NOFOLLOW_NOERROR | O_UNLINK_INTERNAL)); auto custody = TRY(resolve_path(credentials, path, base, &parent_custody, O_NOFOLLOW_NOERROR | O_UNLINK_INTERNAL));
auto& inode = custody->inode(); auto& inode = custody->inode();
if (inode.is_directory()) if (inode.is_directory())
@ -681,12 +668,11 @@ ErrorOr<void> VirtualFileSystem::unlink(StringView path, Custody& base)
VERIFY(parent_custody); VERIFY(parent_custody);
auto& parent_inode = parent_custody->inode(); auto& parent_inode = parent_custody->inode();
auto& current_process = Process::current(); if (!parent_inode.metadata().may_write(credentials))
if (!parent_inode.metadata().may_write(current_process))
return EACCES; return EACCES;
if (parent_inode.metadata().is_sticky()) { if (parent_inode.metadata().is_sticky()) {
if (!current_process.is_superuser() && inode.metadata().uid != current_process.euid()) if (!credentials.is_superuser() && inode.metadata().uid != credentials.euid())
return EACCES; return EACCES;
} }
@ -696,10 +682,10 @@ ErrorOr<void> VirtualFileSystem::unlink(StringView path, Custody& base)
return parent_inode.remove_child(KLexicalPath::basename(path)); return parent_inode.remove_child(KLexicalPath::basename(path));
} }
ErrorOr<void> VirtualFileSystem::symlink(StringView target, StringView linkpath, Custody& base) ErrorOr<void> VirtualFileSystem::symlink(Credentials const& credentials, StringView target, StringView linkpath, Custody& base)
{ {
RefPtr<Custody> parent_custody; RefPtr<Custody> parent_custody;
auto existing_custody_or_error = resolve_path(linkpath, base, &parent_custody); auto existing_custody_or_error = resolve_path(credentials, linkpath, base, &parent_custody);
if (!existing_custody_or_error.is_error()) if (!existing_custody_or_error.is_error())
return EEXIST; return EEXIST;
if (!parent_custody) if (!parent_custody)
@ -707,9 +693,7 @@ ErrorOr<void> VirtualFileSystem::symlink(StringView target, StringView linkpath,
if (existing_custody_or_error.is_error() && existing_custody_or_error.error().code() != ENOENT) if (existing_custody_or_error.is_error() && existing_custody_or_error.error().code() != ENOENT)
return existing_custody_or_error.release_error(); return existing_custody_or_error.release_error();
auto& parent_inode = parent_custody->inode(); auto& parent_inode = parent_custody->inode();
auto& current_process = Process::current(); if (!parent_inode.metadata().may_write(credentials))
auto current_process_credentials = current_process.credentials();
if (!parent_inode.metadata().may_write(current_process))
return EACCES; return EACCES;
if (parent_custody->is_readonly()) if (parent_custody->is_readonly())
return EROFS; return EROFS;
@ -717,7 +701,7 @@ ErrorOr<void> VirtualFileSystem::symlink(StringView target, StringView linkpath,
auto basename = KLexicalPath::basename(linkpath); auto basename = KLexicalPath::basename(linkpath);
dbgln_if(VFS_DEBUG, "VirtualFileSystem::symlink: '{}' (-> '{}') in {}", basename, target, parent_inode.identifier()); dbgln_if(VFS_DEBUG, "VirtualFileSystem::symlink: '{}' (-> '{}') in {}", basename, target, parent_inode.identifier());
auto inode = TRY(parent_inode.create_child(basename, S_IFLNK | 0644, 0, current_process_credentials->euid(), current_process_credentials->egid())); auto inode = TRY(parent_inode.create_child(basename, S_IFLNK | 0644, 0, credentials.euid(), credentials.egid()));
auto target_buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>((u8 const*)target.characters_without_null_termination())); auto target_buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>((u8 const*)target.characters_without_null_termination()));
MutexLocker locker(inode->m_inode_lock); MutexLocker locker(inode->m_inode_lock);
@ -726,10 +710,10 @@ ErrorOr<void> VirtualFileSystem::symlink(StringView target, StringView linkpath,
return {}; return {};
} }
ErrorOr<void> VirtualFileSystem::rmdir(StringView path, Custody& base) ErrorOr<void> VirtualFileSystem::rmdir(Credentials const& credentials, StringView path, Custody& base)
{ {
RefPtr<Custody> parent_custody; RefPtr<Custody> parent_custody;
auto custody = TRY(resolve_path(path, base, &parent_custody)); auto custody = TRY(resolve_path(credentials, path, base, &parent_custody));
auto& inode = custody->inode(); auto& inode = custody->inode();
// FIXME: We should return EINVAL if the last component of the path is "." // FIXME: We should return EINVAL if the last component of the path is "."
@ -744,12 +728,11 @@ ErrorOr<void> VirtualFileSystem::rmdir(StringView path, Custody& base)
auto& parent_inode = parent_custody->inode(); auto& parent_inode = parent_custody->inode();
auto parent_metadata = parent_inode.metadata(); auto parent_metadata = parent_inode.metadata();
auto& current_process = Process::current(); if (!parent_metadata.may_write(credentials))
if (!parent_metadata.may_write(current_process))
return EACCES; return EACCES;
if (parent_metadata.is_sticky()) { if (parent_metadata.is_sticky()) {
if (!current_process.is_superuser() && inode.metadata().uid != current_process.euid()) if (!credentials.is_superuser() && inode.metadata().uid != credentials.euid())
return EACCES; return EACCES;
} }
@ -880,11 +863,11 @@ ErrorOr<void> VirtualFileSystem::validate_path_against_process_veil(StringView p
return {}; return {};
} }
ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::resolve_path(StringView path, NonnullRefPtr<Custody> base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::resolve_path(Credentials const& credentials, StringView path, NonnullRefPtr<Custody> base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level)
{ {
// FIXME: The errors returned by resolve_path_without_veil can leak information about paths that are not unveiled, // FIXME: The errors returned by resolve_path_without_veil can leak information about paths that are not unveiled,
// e.g. when the error is EACCESS or similar. // e.g. when the error is EACCESS or similar.
auto custody = TRY(resolve_path_without_veil(path, base, out_parent, options, symlink_recursion_level)); auto custody = TRY(resolve_path_without_veil(credentials, path, base, out_parent, options, symlink_recursion_level));
if (auto result = validate_path_against_process_veil(*custody, options); result.is_error()) { if (auto result = validate_path_against_process_veil(*custody, options); result.is_error()) {
if (out_parent) if (out_parent)
out_parent->clear(); out_parent->clear();
@ -893,10 +876,10 @@ ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::resolve_path(StringView path,
return custody; return custody;
} }
static bool safe_to_follow_symlink(Inode const& inode, InodeMetadata const& parent_metadata) static bool safe_to_follow_symlink(Credentials const& credentials, Inode const& inode, InodeMetadata const& parent_metadata)
{ {
auto metadata = inode.metadata(); auto metadata = inode.metadata();
if (Process::current().euid() == metadata.uid) if (credentials.euid() == metadata.uid)
return true; return true;
if (!(parent_metadata.is_sticky() && parent_metadata.mode & S_IWOTH)) if (!(parent_metadata.is_sticky() && parent_metadata.mode & S_IWOTH))
@ -908,7 +891,7 @@ static bool safe_to_follow_symlink(Inode const& inode, InodeMetadata const& pare
return false; return false;
} }
ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::resolve_path_without_veil(StringView path, NonnullRefPtr<Custody> base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::resolve_path_without_veil(Credentials const& credentials, StringView path, NonnullRefPtr<Custody> base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level)
{ {
if (symlink_recursion_level >= symlink_recursion_limit) if (symlink_recursion_level >= symlink_recursion_limit)
return ELOOP; return ELOOP;
@ -917,7 +900,6 @@ ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::resolve_path_without_veil(Str
return EINVAL; return EINVAL;
GenericLexer path_lexer(path); GenericLexer path_lexer(path);
auto& current_process = Process::current();
NonnullRefPtr<Custody> custody = path[0] == '/' ? root_custody() : base; NonnullRefPtr<Custody> custody = path[0] == '/' ? root_custody() : base;
bool extra_iteration = path[path.length() - 1] == '/'; bool extra_iteration = path[path.length() - 1] == '/';
@ -933,7 +915,7 @@ ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::resolve_path_without_veil(Str
if (!parent_metadata.is_directory()) if (!parent_metadata.is_directory())
return ENOTDIR; return ENOTDIR;
// Ensure the current user is allowed to resolve paths inside this directory. // Ensure the current user is allowed to resolve paths inside this directory.
if (!parent_metadata.may_execute(current_process)) if (!parent_metadata.may_execute(credentials))
return EACCES; return EACCES;
bool have_more_parts = !path_lexer.is_eof() || extra_iteration; bool have_more_parts = !path_lexer.is_eof() || extra_iteration;
@ -979,7 +961,7 @@ ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::resolve_path_without_veil(Str
break; break;
} }
if (!safe_to_follow_symlink(*child_inode, parent_metadata)) if (!safe_to_follow_symlink(credentials, *child_inode, parent_metadata))
return EACCES; return EACCES;
TRY(validate_path_against_process_veil(*custody, options)); TRY(validate_path_against_process_veil(*custody, options));
@ -995,7 +977,7 @@ ErrorOr<NonnullRefPtr<Custody>> VirtualFileSystem::resolve_path_without_veil(Str
TRY(remaining_path.try_append('.')); TRY(remaining_path.try_append('.'));
TRY(remaining_path.try_append(path.substring_view_starting_after_substring(part))); TRY(remaining_path.try_append(path.substring_view_starting_after_substring(part)));
return resolve_path_without_veil(remaining_path.string_view(), symlink_target, out_parent, options, symlink_recursion_level + 1); return resolve_path_without_veil(credentials, remaining_path.string_view(), symlink_target, out_parent, options, symlink_recursion_level + 1);
} }
} }

View file

@ -50,24 +50,24 @@ public:
ErrorOr<void> remount(Custody& mount_point, int new_flags); ErrorOr<void> remount(Custody& mount_point, int new_flags);
ErrorOr<void> unmount(Inode& guest_inode); ErrorOr<void> unmount(Inode& guest_inode);
ErrorOr<NonnullLockRefPtr<OpenFileDescription>> open(StringView path, int options, mode_t mode, Custody& base, Optional<UidAndGid> = {}); ErrorOr<NonnullLockRefPtr<OpenFileDescription>> open(Credentials const&, StringView path, int options, mode_t mode, Custody& base, Optional<UidAndGid> = {});
ErrorOr<NonnullLockRefPtr<OpenFileDescription>> create(StringView path, int options, mode_t mode, Custody& parent_custody, Optional<UidAndGid> = {}); ErrorOr<NonnullLockRefPtr<OpenFileDescription>> create(Credentials const&, StringView path, int options, mode_t mode, Custody& parent_custody, Optional<UidAndGid> = {});
ErrorOr<void> mkdir(StringView path, mode_t mode, Custody& base); ErrorOr<void> mkdir(Credentials const&, StringView path, mode_t mode, Custody& base);
ErrorOr<void> link(StringView old_path, StringView new_path, Custody& base); ErrorOr<void> link(Credentials const&, StringView old_path, StringView new_path, Custody& base);
ErrorOr<void> unlink(StringView path, Custody& base); ErrorOr<void> unlink(Credentials const&, StringView path, Custody& base);
ErrorOr<void> symlink(StringView target, StringView linkpath, Custody& base); ErrorOr<void> symlink(Credentials const&, StringView target, StringView linkpath, Custody& base);
ErrorOr<void> rmdir(StringView path, Custody& base); ErrorOr<void> rmdir(Credentials const&, StringView path, Custody& base);
ErrorOr<void> chmod(StringView path, mode_t, Custody& base, int options = 0); ErrorOr<void> chmod(Credentials const&, StringView path, mode_t, Custody& base, int options = 0);
ErrorOr<void> chmod(Custody&, mode_t); ErrorOr<void> chmod(Credentials const&, Custody&, mode_t);
ErrorOr<void> chown(StringView path, UserID, GroupID, Custody& base, int options); ErrorOr<void> chown(Credentials const&, StringView path, UserID, GroupID, Custody& base, int options);
ErrorOr<void> chown(Custody&, UserID, GroupID); ErrorOr<void> chown(Credentials const&, Custody&, UserID, GroupID);
ErrorOr<void> access(StringView path, int mode, Custody& base); ErrorOr<void> access(Credentials const&, StringView path, int mode, Custody& base);
ErrorOr<InodeMetadata> lookup_metadata(StringView path, Custody& base, int options = 0); ErrorOr<InodeMetadata> lookup_metadata(Credentials const&, StringView path, Custody& base, int options = 0);
ErrorOr<void> utime(StringView path, Custody& base, time_t atime, time_t mtime); ErrorOr<void> utime(Credentials const&, StringView path, Custody& base, time_t atime, time_t mtime);
ErrorOr<void> utimensat(StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options = 0); ErrorOr<void> utimensat(Credentials const&, StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options = 0);
ErrorOr<void> rename(StringView oldpath, StringView newpath, Custody& base); ErrorOr<void> rename(Credentials const&, StringView oldpath, StringView newpath, Custody& base);
ErrorOr<void> mknod(StringView path, mode_t, dev_t, Custody& base); ErrorOr<void> mknod(Credentials const&, StringView path, mode_t, dev_t, Custody& base);
ErrorOr<NonnullRefPtr<Custody>> open_directory(StringView path, Custody& base); ErrorOr<NonnullRefPtr<Custody>> open_directory(Credentials const&, StringView path, Custody& base);
ErrorOr<void> for_each_mount(Function<ErrorOr<void>(Mount const&)>) const; ErrorOr<void> for_each_mount(Function<ErrorOr<void>(Mount const&)>) const;
@ -76,8 +76,8 @@ public:
static void sync(); static void sync();
NonnullRefPtr<Custody> root_custody(); NonnullRefPtr<Custody> root_custody();
ErrorOr<NonnullRefPtr<Custody>> resolve_path(StringView path, NonnullRefPtr<Custody> base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0); ErrorOr<NonnullRefPtr<Custody>> resolve_path(Credentials const&, StringView path, NonnullRefPtr<Custody> base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0);
ErrorOr<NonnullRefPtr<Custody>> resolve_path_without_veil(StringView path, NonnullRefPtr<Custody> base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0); ErrorOr<NonnullRefPtr<Custody>> resolve_path_without_veil(Credentials const&, StringView path, NonnullRefPtr<Custody> base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0);
private: private:
friend class OpenFileDescription; friend class OpenFileDescription;

View file

@ -139,7 +139,7 @@ ErrorOr<void> LocalSocket::bind(Userspace<sockaddr const*> user_address, socklen
mode_t mode = S_IFSOCK | (m_prebind_mode & 0777); mode_t mode = S_IFSOCK | (m_prebind_mode & 0777);
UidAndGid owner { m_prebind_uid, m_prebind_gid }; UidAndGid owner { m_prebind_uid, m_prebind_gid };
auto result = VirtualFileSystem::the().open(path->view(), O_CREAT | O_EXCL | O_NOFOLLOW_NOERROR, mode, Process::current().current_directory(), owner); auto result = VirtualFileSystem::the().open(Process::current().credentials(), path->view(), O_CREAT | O_EXCL | O_NOFOLLOW_NOERROR, mode, Process::current().current_directory(), owner);
if (result.is_error()) { if (result.is_error()) {
if (result.error().code() == EEXIST) if (result.error().code() == EEXIST)
return set_so_error(EADDRINUSE); return set_so_error(EADDRINUSE);
@ -179,7 +179,7 @@ ErrorOr<void> LocalSocket::connect(OpenFileDescription& description, Userspace<s
auto path = SOCKET_TRY(KString::try_create(StringView { address.sun_path, strnlen(address.sun_path, sizeof(address.sun_path)) })); auto path = SOCKET_TRY(KString::try_create(StringView { address.sun_path, strnlen(address.sun_path, sizeof(address.sun_path)) }));
dbgln_if(LOCAL_SOCKET_DEBUG, "LocalSocket({}) connect({})", this, *path); dbgln_if(LOCAL_SOCKET_DEBUG, "LocalSocket({}) connect({})", this, *path);
auto file = SOCKET_TRY(VirtualFileSystem::the().open(path->view(), O_RDWR, 0, Process::current().current_directory())); auto file = SOCKET_TRY(VirtualFileSystem::the().open(Process::current().credentials(), path->view(), O_RDWR, 0, Process::current().current_directory()));
auto inode = file->inode(); auto inode = file->inode();
m_inode = inode; m_inode = inode;

View file

@ -583,8 +583,9 @@ ErrorOr<void> Process::dump_perfcore()
auto base_filename = TRY(KString::formatted("{}_{}", name(), pid().value())); auto base_filename = TRY(KString::formatted("{}_{}", name(), pid().value()));
auto perfcore_filename = TRY(KString::formatted("{}.profile", base_filename)); auto perfcore_filename = TRY(KString::formatted("{}.profile", base_filename));
LockRefPtr<OpenFileDescription> description; LockRefPtr<OpenFileDescription> description;
auto credentials = this->credentials();
for (size_t attempt = 1; attempt <= 10; ++attempt) { for (size_t attempt = 1; attempt <= 10; ++attempt) {
auto description_or_error = VirtualFileSystem::the().open(perfcore_filename->view(), O_CREAT | O_EXCL, 0400, current_directory(), UidAndGid { 0, 0 }); auto description_or_error = VirtualFileSystem::the().open(credentials, perfcore_filename->view(), O_CREAT | O_EXCL, 0400, current_directory(), UidAndGid { 0, 0 });
if (!description_or_error.is_error()) { if (!description_or_error.is_error()) {
description = description_or_error.release_value(); description = description_or_error.release_value();
break; break;

View file

@ -15,7 +15,7 @@ ErrorOr<FlatPtr> Process::sys$access(Userspace<char const*> user_path, size_t pa
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
TRY(require_promise(Pledge::rpath)); TRY(require_promise(Pledge::rpath));
auto path = TRY(get_syscall_path_argument(user_path, path_length)); auto path = TRY(get_syscall_path_argument(user_path, path_length));
TRY(VirtualFileSystem::the().access(path->view(), mode, current_directory())); TRY(VirtualFileSystem::the().access(credentials(), path->view(), mode, current_directory()));
return 0; return 0;
} }

View file

@ -19,7 +19,7 @@ ErrorOr<FlatPtr> Process::sys$chdir(Userspace<char const*> user_path, size_t pat
auto current_directory = m_current_directory.with([](auto& current_directory) -> NonnullRefPtr<Custody> { auto current_directory = m_current_directory.with([](auto& current_directory) -> NonnullRefPtr<Custody> {
return *current_directory; return *current_directory;
}); });
RefPtr<Custody> new_directory = TRY(VirtualFileSystem::the().open_directory(path->view(), *current_directory)); RefPtr<Custody> new_directory = TRY(VirtualFileSystem::the().open_directory(credentials(), path->view(), *current_directory));
m_current_directory.with([&](auto& current_directory) { m_current_directory.with([&](auto& current_directory) {
// NOTE: We use swap() here to avoid manipulating the ref counts while holding the lock. // NOTE: We use swap() here to avoid manipulating the ref counts while holding the lock.
swap(current_directory, new_directory); swap(current_directory, new_directory);
@ -34,7 +34,7 @@ ErrorOr<FlatPtr> Process::sys$fchdir(int fd)
auto description = TRY(open_file_description(fd)); auto description = TRY(open_file_description(fd));
if (!description->is_directory()) if (!description->is_directory())
return ENOTDIR; return ENOTDIR;
if (!description->metadata().may_execute(*this)) if (!description->metadata().may_execute(credentials()))
return EACCES; return EACCES;
m_current_directory.with([&](auto& current_directory) { m_current_directory.with([&](auto& current_directory) {
current_directory = description->custody(); current_directory = description->custody();

View file

@ -28,7 +28,7 @@ ErrorOr<FlatPtr> Process::sys$chmod(Userspace<Syscall::SC_chmod_params const*> u
base = base_description->custody(); base = base_description->custody();
} }
TRY(VirtualFileSystem::the().chmod(path->view(), params.mode, *base, params.follow_symlinks ? 0 : O_NOFOLLOW_NOERROR)); TRY(VirtualFileSystem::the().chmod(credentials(), path->view(), params.mode, *base, params.follow_symlinks ? 0 : O_NOFOLLOW_NOERROR));
return 0; return 0;
} }

View file

@ -38,7 +38,7 @@ ErrorOr<FlatPtr> Process::sys$chown(Userspace<Syscall::SC_chown_params const*> u
base = base_description->custody(); base = base_description->custody();
} }
TRY(VirtualFileSystem::the().chown(path->view(), params.uid, params.gid, *base, params.follow_symlinks ? 0 : O_NOFOLLOW_NOERROR)); TRY(VirtualFileSystem::the().chown(credentials(), path->view(), params.uid, params.gid, *base, params.follow_symlinks ? 0 : O_NOFOLLOW_NOERROR));
return 0; return 0;
} }

View file

@ -758,7 +758,7 @@ ErrorOr<LockRefPtr<OpenFileDescription>> Process::find_elf_interpreter_for_execu
if (!interpreter_path.is_empty()) { if (!interpreter_path.is_empty()) {
dbgln_if(EXEC_DEBUG, "exec({}): Using program interpreter {}", path, interpreter_path); dbgln_if(EXEC_DEBUG, "exec({}): Using program interpreter {}", path, interpreter_path);
auto interpreter_description = TRY(VirtualFileSystem::the().open(interpreter_path, O_EXEC, 0, current_directory())); auto interpreter_description = TRY(VirtualFileSystem::the().open(credentials(), interpreter_path, O_EXEC, 0, current_directory()));
auto interp_metadata = interpreter_description->metadata(); auto interp_metadata = interpreter_description->metadata();
VERIFY(interpreter_description->inode()); VERIFY(interpreter_description->inode());
@ -827,7 +827,7 @@ ErrorOr<void> Process::exec(NonnullOwnPtr<KString> path, NonnullOwnPtrVector<KSt
// * ET_EXEC binary that just gets loaded // * ET_EXEC binary that just gets loaded
// * ET_DYN binary that requires a program interpreter // * ET_DYN binary that requires a program interpreter
// //
auto description = TRY(VirtualFileSystem::the().open(path->view(), O_EXEC, 0, current_directory())); auto description = TRY(VirtualFileSystem::the().open(credentials(), path->view(), O_EXEC, 0, current_directory()));
auto metadata = description->metadata(); auto metadata = description->metadata();
if (!metadata.is_regular_file()) if (!metadata.is_regular_file())

View file

@ -47,7 +47,7 @@ ErrorOr<FlatPtr> Process::sys$inode_watcher_add_watch(Userspace<Syscall::SC_inod
return EBADF; return EBADF;
auto* inode_watcher = description->inode_watcher(); auto* inode_watcher = description->inode_watcher();
auto path = TRY(get_syscall_path_argument(params.user_path)); auto path = TRY(get_syscall_path_argument(params.user_path));
auto custody = TRY(VirtualFileSystem::the().resolve_path(path->view(), current_directory())); auto custody = TRY(VirtualFileSystem::the().resolve_path(credentials(), path->view(), current_directory()));
if (!custody->inode().fs().supports_watchers()) if (!custody->inode().fs().supports_watchers())
return ENOTSUP; return ENOTSUP;

View file

@ -17,7 +17,7 @@ ErrorOr<FlatPtr> Process::sys$link(Userspace<Syscall::SC_link_params const*> use
auto params = TRY(copy_typed_from_user(user_params)); auto params = TRY(copy_typed_from_user(user_params));
auto old_path = TRY(try_copy_kstring_from_user(params.old_path)); auto old_path = TRY(try_copy_kstring_from_user(params.old_path));
auto new_path = TRY(try_copy_kstring_from_user(params.new_path)); auto new_path = TRY(try_copy_kstring_from_user(params.new_path));
TRY(VirtualFileSystem::the().link(old_path->view(), new_path->view(), current_directory())); TRY(VirtualFileSystem::the().link(credentials(), old_path->view(), new_path->view(), current_directory()));
return 0; return 0;
} }
@ -29,7 +29,7 @@ ErrorOr<FlatPtr> Process::sys$symlink(Userspace<Syscall::SC_symlink_params const
auto target = TRY(get_syscall_path_argument(params.target)); auto target = TRY(get_syscall_path_argument(params.target));
auto linkpath = TRY(get_syscall_path_argument(params.linkpath)); auto linkpath = TRY(get_syscall_path_argument(params.linkpath));
TRY(VirtualFileSystem::the().symlink(target->view(), linkpath->view(), current_directory())); TRY(VirtualFileSystem::the().symlink(credentials(), target->view(), linkpath->view(), current_directory()));
return 0; return 0;
} }

View file

@ -15,7 +15,7 @@ ErrorOr<FlatPtr> Process::sys$mkdir(Userspace<char const*> user_path, size_t pat
VERIFY_NO_PROCESS_BIG_LOCK(this); VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::cpath)); TRY(require_promise(Pledge::cpath));
auto path = TRY(get_syscall_path_argument(user_path, path_length)); auto path = TRY(get_syscall_path_argument(user_path, path_length));
TRY(VirtualFileSystem::the().mkdir(path->view(), mode & ~umask(), current_directory())); TRY(VirtualFileSystem::the().mkdir(credentials(), path->view(), mode & ~umask(), current_directory()));
return 0; return 0;
} }
} }

View file

@ -19,7 +19,7 @@ ErrorOr<FlatPtr> Process::sys$mknod(Userspace<Syscall::SC_mknod_params const*> u
if (!is_superuser() && !is_regular_file(params.mode) && !is_fifo(params.mode) && !is_socket(params.mode)) if (!is_superuser() && !is_regular_file(params.mode) && !is_fifo(params.mode) && !is_socket(params.mode))
return EPERM; return EPERM;
auto path = TRY(get_syscall_path_argument(params.path)); auto path = TRY(get_syscall_path_argument(params.path));
TRY(VirtualFileSystem::the().mknod(path->view(), params.mode & ~umask(), params.dev, current_directory())); TRY(VirtualFileSystem::the().mknod(credentials(), path->view(), params.mode & ~umask(), params.dev, current_directory()));
return 0; return 0;
} }

View file

@ -105,15 +105,16 @@ ErrorOr<void> Process::validate_mmap_prot(int prot, bool map_stack, bool map_ano
ErrorOr<void> Process::validate_inode_mmap_prot(int prot, Inode const& inode, bool map_shared) const ErrorOr<void> Process::validate_inode_mmap_prot(int prot, Inode const& inode, bool map_shared) const
{ {
auto credentials = this->credentials();
auto metadata = inode.metadata(); auto metadata = inode.metadata();
if ((prot & PROT_READ) && !metadata.may_read(*this)) if ((prot & PROT_READ) && !metadata.may_read(credentials))
return EACCES; return EACCES;
if (map_shared) { if (map_shared) {
// FIXME: What about readonly filesystem mounts? We cannot make a // FIXME: What about readonly filesystem mounts? We cannot make a
// decision here without knowing the mount flags, so we would need to // decision here without knowing the mount flags, so we would need to
// keep a Custody or something from mmap time. // keep a Custody or something from mmap time.
if ((prot & PROT_WRITE) && !metadata.may_write(*this)) if ((prot & PROT_WRITE) && !metadata.may_write(credentials))
return EACCES; return EACCES;
if (auto shared_vmobject = inode.shared_vmobject()) { if (auto shared_vmobject = inode.shared_vmobject()) {
if ((prot & PROT_EXEC) && shared_vmobject->writable_mappings()) if ((prot & PROT_EXEC) && shared_vmobject->writable_mappings())

View file

@ -86,7 +86,7 @@ ErrorOr<FlatPtr> Process::sys$mount(Userspace<Syscall::SC_mount_params const*> u
else else
dbgln("mount {} @ {}", fs_type, target); dbgln("mount {} @ {}", fs_type, target);
auto target_custody = TRY(VirtualFileSystem::the().resolve_path(target->view(), current_directory())); auto target_custody = TRY(VirtualFileSystem::the().resolve_path(credentials(), target->view(), current_directory()));
if (params.flags & MS_REMOUNT) { if (params.flags & MS_REMOUNT) {
// We're not creating a new mount, we're updating an existing one! // We're not creating a new mount, we're updating an existing one!
@ -132,7 +132,7 @@ ErrorOr<FlatPtr> Process::sys$umount(Userspace<char const*> user_mountpoint, siz
TRY(require_no_promises()); TRY(require_no_promises());
auto mountpoint = TRY(get_syscall_path_argument(user_mountpoint, mountpoint_length)); auto mountpoint = TRY(get_syscall_path_argument(user_mountpoint, mountpoint_length));
auto custody = TRY(VirtualFileSystem::the().resolve_path(mountpoint->view(), current_directory())); auto custody = TRY(VirtualFileSystem::the().resolve_path(credentials(), mountpoint->view(), current_directory()));
auto& guest_inode = custody->inode(); auto& guest_inode = custody->inode();
TRY(VirtualFileSystem::the().unmount(guest_inode)); TRY(VirtualFileSystem::the().unmount(guest_inode));
return 0; return 0;

View file

@ -67,7 +67,7 @@ ErrorOr<FlatPtr> Process::sys$open(Userspace<Syscall::SC_open_params const*> use
base = base_description->custody(); base = base_description->custody();
} }
auto description = TRY(VirtualFileSystem::the().open(path->view(), options, mode & ~umask(), *base)); auto description = TRY(VirtualFileSystem::the().open(credentials(), path->view(), options, mode & ~umask(), *base));
if (description->inode() && description->inode()->bound_socket()) if (description->inode() && description->inode()->bound_socket())
return ENXIO; return ENXIO;

View file

@ -17,7 +17,7 @@ ErrorOr<FlatPtr> Process::sys$readlink(Userspace<Syscall::SC_readlink_params con
auto params = TRY(copy_typed_from_user(user_params)); auto params = TRY(copy_typed_from_user(user_params));
auto path = TRY(get_syscall_path_argument(params.path)); auto path = TRY(get_syscall_path_argument(params.path));
auto description = TRY(VirtualFileSystem::the().open(path->view(), O_RDONLY | O_NOFOLLOW_NOERROR, 0, current_directory())); auto description = TRY(VirtualFileSystem::the().open(credentials(), path->view(), O_RDONLY | O_NOFOLLOW_NOERROR, 0, current_directory()));
if (!description->metadata().is_symlink()) if (!description->metadata().is_symlink())
return EINVAL; return EINVAL;

View file

@ -18,7 +18,7 @@ ErrorOr<FlatPtr> Process::sys$realpath(Userspace<Syscall::SC_realpath_params con
auto params = TRY(copy_typed_from_user(user_params)); auto params = TRY(copy_typed_from_user(user_params));
auto path = TRY(get_syscall_path_argument(params.path)); auto path = TRY(get_syscall_path_argument(params.path));
auto custody = TRY(VirtualFileSystem::the().resolve_path(path->view(), current_directory())); auto custody = TRY(VirtualFileSystem::the().resolve_path(credentials(), path->view(), current_directory()));
auto absolute_path = TRY(custody->try_serialize_absolute_path()); auto absolute_path = TRY(custody->try_serialize_absolute_path());
size_t ideal_size = absolute_path->length() + 1; size_t ideal_size = absolute_path->length() + 1;

View file

@ -17,7 +17,7 @@ ErrorOr<FlatPtr> Process::sys$rename(Userspace<Syscall::SC_rename_params const*>
auto params = TRY(copy_typed_from_user(user_params)); auto params = TRY(copy_typed_from_user(user_params));
auto old_path = TRY(get_syscall_path_argument(params.old_path)); auto old_path = TRY(get_syscall_path_argument(params.old_path));
auto new_path = TRY(get_syscall_path_argument(params.new_path)); auto new_path = TRY(get_syscall_path_argument(params.new_path));
TRY(VirtualFileSystem::the().rename(old_path->view(), new_path->view(), current_directory())); TRY(VirtualFileSystem::the().rename(credentials(), old_path->view(), new_path->view(), current_directory()));
return 0; return 0;
} }

View file

@ -15,7 +15,7 @@ ErrorOr<FlatPtr> Process::sys$rmdir(Userspace<char const*> user_path, size_t pat
VERIFY_NO_PROCESS_BIG_LOCK(this); VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::cpath)); TRY(require_promise(Pledge::cpath));
auto path = TRY(get_syscall_path_argument(user_path, path_length)); auto path = TRY(get_syscall_path_argument(user_path, path_length));
TRY(VirtualFileSystem::the().rmdir(path->view(), current_directory())); TRY(VirtualFileSystem::the().rmdir(credentials(), path->view(), current_directory()));
return 0; return 0;
} }

View file

@ -41,7 +41,7 @@ ErrorOr<FlatPtr> Process::sys$stat(Userspace<Syscall::SC_stat_params const*> use
return EINVAL; return EINVAL;
base = base_description->custody(); base = base_description->custody();
} }
auto metadata = TRY(VirtualFileSystem::the().lookup_metadata(path->view(), *base, params.follow_symlinks ? 0 : O_NOFOLLOW_NOERROR)); auto metadata = TRY(VirtualFileSystem::the().lookup_metadata(credentials(), path->view(), *base, params.follow_symlinks ? 0 : O_NOFOLLOW_NOERROR));
auto statbuf = TRY(metadata.stat()); auto statbuf = TRY(metadata.stat());
TRY(copy_to_user(params.statbuf, &statbuf)); TRY(copy_to_user(params.statbuf, &statbuf));
return 0; return 0;

View file

@ -47,7 +47,7 @@ ErrorOr<FlatPtr> Process::sys$statvfs(Userspace<Syscall::SC_statvfs_params const
auto path = TRY(get_syscall_path_argument(params.path)); auto path = TRY(get_syscall_path_argument(params.path));
auto custody = TRY(VirtualFileSystem::the().resolve_path(path->view(), current_directory(), nullptr, 0)); auto custody = TRY(VirtualFileSystem::the().resolve_path(credentials(), path->view(), current_directory(), nullptr, 0));
auto& inode = custody->inode(); auto& inode = custody->inode();
auto const& fs = inode.fs(); auto const& fs = inode.fs();

View file

@ -30,9 +30,9 @@ ErrorOr<FlatPtr> Process::sys$unlink(int dirfd, Userspace<char const*> user_path
} }
if (flags & AT_REMOVEDIR) if (flags & AT_REMOVEDIR)
TRY(VirtualFileSystem::the().rmdir(path->view(), *base)); TRY(VirtualFileSystem::the().rmdir(credentials(), path->view(), *base));
else else
TRY(VirtualFileSystem::the().unlink(path->view(), *base)); TRY(VirtualFileSystem::the().unlink(credentials(), path->view(), *base));
return 0; return 0;
} }

View file

@ -82,7 +82,7 @@ ErrorOr<FlatPtr> Process::sys$unveil(Userspace<Syscall::SC_unveil_params const*>
// If this case is encountered, the parent node of the path is returned and the custody of that inode is used instead. // If this case is encountered, the parent node of the path is returned and the custody of that inode is used instead.
RefPtr<Custody> parent_custody; // Parent inode in case of ENOENT RefPtr<Custody> parent_custody; // Parent inode in case of ENOENT
OwnPtr<KString> new_unveiled_path; OwnPtr<KString> new_unveiled_path;
auto custody_or_error = VirtualFileSystem::the().resolve_path_without_veil(path->view(), VirtualFileSystem::the().root_custody(), &parent_custody); auto custody_or_error = VirtualFileSystem::the().resolve_path_without_veil(credentials(), path->view(), VirtualFileSystem::the().root_custody(), &parent_custody);
if (!custody_or_error.is_error()) { if (!custody_or_error.is_error()) {
new_unveiled_path = TRY(custody_or_error.value()->try_serialize_absolute_path()); new_unveiled_path = TRY(custody_or_error.value()->try_serialize_absolute_path());
} else if (custody_or_error.error().code() == ENOENT && parent_custody && (new_permissions & UnveilAccess::CreateOrRemove)) { } else if (custody_or_error.error().code() == ENOENT && parent_custody && (new_permissions & UnveilAccess::CreateOrRemove)) {

View file

@ -23,7 +23,7 @@ ErrorOr<FlatPtr> Process::sys$utime(Userspace<char const*> user_path, size_t pat
// Not a bug! // Not a bug!
buf = { now, now }; buf = { now, now };
} }
TRY(VirtualFileSystem::the().utime(path->view(), current_directory(), buf.actime, buf.modtime)); TRY(VirtualFileSystem::the().utime(credentials(), path->view(), current_directory(), buf.actime, buf.modtime));
return 0; return 0;
} }

View file

@ -71,7 +71,7 @@ ErrorOr<FlatPtr> Process::sys$utimensat(Userspace<Syscall::SC_utimensat_params c
auto& atime = times[0]; auto& atime = times[0];
auto& mtime = times[1]; auto& mtime = times[1];
TRY(VirtualFileSystem::the().utimensat(path->view(), *base, atime, mtime, follow_symlink)); TRY(VirtualFileSystem::the().utimensat(credentials(), path->view(), *base, atime, mtime, follow_symlink));
return 0; return 0;
} }