kernel: Add support for supplementary groups (1/2)
Adds support for supplementary groups internally in the kernel. No userspace support.
This commit is contained in:
parent
e97b61ef16
commit
3ad23eab21
@ -35,9 +35,9 @@ Result<u64> ScriptLoader::load(AddressSpace* space)
|
|||||||
auto& interpreter_path = m_interpreter_cmdline[0];
|
auto& interpreter_path = m_interpreter_cmdline[0];
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
auto interpreter =
|
auto interpreter = TRY(VFS::resolve_path(interpreter_path.chars(), current->auth, ¤t->extra_groups,
|
||||||
TRY(VFS::resolve_path(interpreter_path.chars(), current->auth, current->current_directory, true));
|
current->current_directory, true));
|
||||||
if (!VFS::can_execute(interpreter, current->auth)) return err(EACCES);
|
if (!VFS::can_execute(interpreter, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
auto loader = TRY(BinaryFormat::create_loader(interpreter, m_recursion_level + 1));
|
auto loader = TRY(BinaryFormat::create_loader(interpreter, m_recursion_level + 1));
|
||||||
u64 entry = TRY(loader->load(space));
|
u64 entry = TRY(loader->load(space));
|
||||||
|
@ -20,7 +20,7 @@ void InitRD::initialize()
|
|||||||
|
|
||||||
static Result<void> vfs_create_dir_if_not_exists(const char* path, mode_t mode)
|
static Result<void> vfs_create_dir_if_not_exists(const char* path, mode_t mode)
|
||||||
{
|
{
|
||||||
auto rc = VFS::create_directory(path, mode & (mode_t)~S_IFMT, Credentials {});
|
auto rc = VFS::create_directory(path, mode & (mode_t)~S_IFMT, Credentials {}, nullptr);
|
||||||
if (rc.has_error())
|
if (rc.has_error())
|
||||||
{
|
{
|
||||||
if (rc.error() == EEXIST) return {};
|
if (rc.error() == EEXIST) return {};
|
||||||
@ -37,7 +37,8 @@ Result<void> InitRD::populate_vfs()
|
|||||||
{
|
{
|
||||||
if (entry.type == TarStream::EntryType::RegularFile)
|
if (entry.type == TarStream::EntryType::RegularFile)
|
||||||
{
|
{
|
||||||
auto file = TRY(VFS::create_file(entry.name.chars(), entry.mode & (mode_t)~S_IFMT, Credentials {}));
|
auto file =
|
||||||
|
TRY(VFS::create_file(entry.name.chars(), entry.mode & (mode_t)~S_IFMT, Credentials {}, nullptr));
|
||||||
file->write(entry.data(), 0, entry.size);
|
file->write(entry.data(), 0, entry.size);
|
||||||
}
|
}
|
||||||
else if (entry.type == TarStream::EntryType::Directory)
|
else if (entry.type == TarStream::EntryType::Directory)
|
||||||
|
@ -17,8 +17,9 @@ namespace VFS
|
|||||||
|
|
||||||
static constexpr int MAX_SYMLINKS = 8;
|
static constexpr int MAX_SYMLINKS = 8;
|
||||||
|
|
||||||
Result<SharedPtr<Inode>> resolve_path_impl(const char* path, Credentials auth, SharedPtr<Inode> current_inode,
|
Result<SharedPtr<Inode>> resolve_path_impl(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||||
bool follow_last_symlink, int& symlinks_followed)
|
SharedPtr<Inode> current_inode, bool follow_last_symlink,
|
||||||
|
int& symlinks_followed)
|
||||||
{
|
{
|
||||||
if (symlinks_followed >= MAX_SYMLINKS) return err(ELOOP);
|
if (symlinks_followed >= MAX_SYMLINKS) return err(ELOOP);
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ namespace VFS
|
|||||||
const char* section;
|
const char* section;
|
||||||
while (parser.next().try_set_value(section))
|
while (parser.next().try_set_value(section))
|
||||||
{
|
{
|
||||||
if (!can_execute(current_inode, auth)) return err(EACCES);
|
if (!can_execute(current_inode, auth, extra_groups)) return err(EACCES);
|
||||||
current_inode = TRY(current_inode->find(section));
|
current_inode = TRY(current_inode->find(section));
|
||||||
|
|
||||||
if (current_inode->type() == VFS::InodeType::Symlink && (follow_last_symlink || parser.has_next()))
|
if (current_inode->type() == VFS::InodeType::Symlink && (follow_last_symlink || parser.has_next()))
|
||||||
@ -45,7 +46,8 @@ namespace VFS
|
|||||||
symlink_root = parent_inode;
|
symlink_root = parent_inode;
|
||||||
|
|
||||||
symlinks_followed++;
|
symlinks_followed++;
|
||||||
current_inode = TRY(resolve_path_impl(link.chars(), auth, symlink_root, true, symlinks_followed));
|
current_inode =
|
||||||
|
TRY(resolve_path_impl(link.chars(), auth, extra_groups, symlink_root, true, symlinks_followed));
|
||||||
symlinks_followed--;
|
symlinks_followed--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +57,8 @@ namespace VFS
|
|||||||
return current_inode;
|
return current_inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth, SharedPtr<VFS::Inode> working_directory,
|
Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||||
bool follow_last_symlink)
|
SharedPtr<VFS::Inode> working_directory, bool follow_last_symlink)
|
||||||
{
|
{
|
||||||
SharedPtr<Inode> current_inode;
|
SharedPtr<Inode> current_inode;
|
||||||
|
|
||||||
@ -66,17 +68,17 @@ namespace VFS
|
|||||||
|
|
||||||
int symlinks_followed = 0;
|
int symlinks_followed = 0;
|
||||||
|
|
||||||
return resolve_path_impl(path, auth, current_inode, follow_last_symlink, symlinks_followed);
|
return resolve_path_impl(path, auth, extra_groups, current_inode, follow_last_symlink, symlinks_followed);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<SharedPtr<Inode>> create_directory(const char* path, mode_t mode, Credentials auth,
|
Result<SharedPtr<Inode>> create_directory(const char* path, mode_t mode, Credentials auth,
|
||||||
SharedPtr<Inode> working_directory)
|
const Vector<gid_t>* extra_groups, SharedPtr<Inode> working_directory)
|
||||||
{
|
{
|
||||||
auto parent_path = TRY(PathParser::dirname(path));
|
auto parent_path = TRY(PathParser::dirname(path));
|
||||||
|
|
||||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, working_directory));
|
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, extra_groups, working_directory));
|
||||||
|
|
||||||
if (!can_write(parent_inode, auth)) return err(EACCES);
|
if (!can_write(parent_inode, auth, extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
auto child_name = TRY(PathParser::basename(path));
|
auto child_name = TRY(PathParser::basename(path));
|
||||||
|
|
||||||
@ -86,13 +88,13 @@ namespace VFS
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result<SharedPtr<Inode>> create_file(const char* path, mode_t mode, Credentials auth,
|
Result<SharedPtr<Inode>> create_file(const char* path, mode_t mode, Credentials auth,
|
||||||
SharedPtr<Inode> working_directory)
|
const Vector<gid_t>* extra_groups, SharedPtr<Inode> working_directory)
|
||||||
{
|
{
|
||||||
auto parent_path = TRY(PathParser::dirname(path));
|
auto parent_path = TRY(PathParser::dirname(path));
|
||||||
|
|
||||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, working_directory));
|
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, extra_groups, working_directory));
|
||||||
|
|
||||||
if (!can_write(parent_inode, auth)) return err(EACCES);
|
if (!can_write(parent_inode, auth, extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
auto child_name = TRY(PathParser::basename(path));
|
auto child_name = TRY(PathParser::basename(path));
|
||||||
|
|
||||||
@ -133,7 +135,8 @@ namespace VFS
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_execute(SharedPtr<Inode> inode, Credentials auth)
|
// FIXME: Check all three permissions even if the UID or GID match.
|
||||||
|
bool can_execute(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups)
|
||||||
{
|
{
|
||||||
if (auth.euid == 0) return true;
|
if (auth.euid == 0) return true;
|
||||||
|
|
||||||
@ -142,10 +145,19 @@ namespace VFS
|
|||||||
if (metadata.uid == auth.euid) { return metadata.mode & S_IXUSR; }
|
if (metadata.uid == auth.euid) { return metadata.mode & S_IXUSR; }
|
||||||
if (metadata.gid == auth.egid) { return metadata.mode & S_IXGRP; }
|
if (metadata.gid == auth.egid) { return metadata.mode & S_IXGRP; }
|
||||||
|
|
||||||
|
if (extra_groups)
|
||||||
|
{
|
||||||
|
for (gid_t group : *extra_groups)
|
||||||
|
{
|
||||||
|
if (metadata.gid == group) return metadata.mode & S_IXGRP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return metadata.mode & S_IXOTH;
|
return metadata.mode & S_IXOTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_write(SharedPtr<Inode> inode, Credentials auth)
|
// FIXME: Check all three permissions even if the UID or GID match.
|
||||||
|
bool can_write(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups)
|
||||||
{
|
{
|
||||||
if (auth.euid == 0) return true;
|
if (auth.euid == 0) return true;
|
||||||
|
|
||||||
@ -154,10 +166,19 @@ namespace VFS
|
|||||||
if (metadata.uid == auth.euid) { return metadata.mode & S_IWUSR; }
|
if (metadata.uid == auth.euid) { return metadata.mode & S_IWUSR; }
|
||||||
if (metadata.gid == auth.egid) { return metadata.mode & S_IWGRP; }
|
if (metadata.gid == auth.egid) { return metadata.mode & S_IWGRP; }
|
||||||
|
|
||||||
|
if (extra_groups)
|
||||||
|
{
|
||||||
|
for (gid_t group : *extra_groups)
|
||||||
|
{
|
||||||
|
if (metadata.gid == group) return metadata.mode & S_IWGRP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return metadata.mode & S_IWOTH;
|
return metadata.mode & S_IWOTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_read(SharedPtr<Inode> inode, Credentials auth)
|
// FIXME: Check all three permissions even if the UID or GID match.
|
||||||
|
bool can_read(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups)
|
||||||
{
|
{
|
||||||
if (auth.euid == 0) return true;
|
if (auth.euid == 0) return true;
|
||||||
|
|
||||||
@ -166,6 +187,14 @@ namespace VFS
|
|||||||
if (metadata.uid == auth.euid) { return metadata.mode & S_IRUSR; }
|
if (metadata.uid == auth.euid) { return metadata.mode & S_IRUSR; }
|
||||||
if (metadata.gid == auth.egid) { return metadata.mode & S_IRGRP; }
|
if (metadata.gid == auth.egid) { return metadata.mode & S_IRGRP; }
|
||||||
|
|
||||||
|
if (extra_groups)
|
||||||
|
{
|
||||||
|
for (gid_t group : *extra_groups)
|
||||||
|
{
|
||||||
|
if (metadata.gid == group) return metadata.mode & S_IRGRP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return metadata.mode & S_IROTH;
|
return metadata.mode & S_IROTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +232,8 @@ namespace VFS
|
|||||||
auto new_root_parent = TRY(PathParser::dirname(new_root));
|
auto new_root_parent = TRY(PathParser::dirname(new_root));
|
||||||
auto new_root_path = TRY(PathParser::basename(new_root));
|
auto new_root_path = TRY(PathParser::basename(new_root));
|
||||||
|
|
||||||
auto new_root_parent_inode = TRY(VFS::resolve_path(new_root_parent.chars(), Credentials {}, working_directory));
|
auto new_root_parent_inode =
|
||||||
|
TRY(VFS::resolve_path(new_root_parent.chars(), Credentials {}, nullptr, working_directory));
|
||||||
auto new_root_inode = TRY(new_root_parent_inode->find(new_root_path.chars()));
|
auto new_root_inode = TRY(new_root_parent_inode->find(new_root_path.chars()));
|
||||||
|
|
||||||
if (new_root_inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
if (new_root_inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
@ -215,7 +245,7 @@ namespace VFS
|
|||||||
|
|
||||||
kdbgln("vfs: Pivoting root from / to %s, using %s as new root", put_old, new_root);
|
kdbgln("vfs: Pivoting root from / to %s, using %s as new root", put_old, new_root);
|
||||||
|
|
||||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), Credentials {}, working_directory));
|
auto parent_inode = TRY(resolve_path(parent_path.chars(), Credentials {}, nullptr, working_directory));
|
||||||
|
|
||||||
auto inode = TRY(parent_inode->find(child.chars()));
|
auto inode = TRY(parent_inode->find(child.chars()));
|
||||||
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
@ -236,7 +266,7 @@ namespace VFS
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result<void> mount(const char* path, SharedPtr<VFS::FileSystem> fs, Credentials auth,
|
Result<void> mount(const char* path, SharedPtr<VFS::FileSystem> fs, Credentials auth,
|
||||||
SharedPtr<VFS::Inode> working_directory)
|
const Vector<gid_t>* extra_groups, SharedPtr<VFS::Inode> working_directory)
|
||||||
{
|
{
|
||||||
auto parent_path = TRY(PathParser::dirname(path));
|
auto parent_path = TRY(PathParser::dirname(path));
|
||||||
auto child = TRY(PathParser::basename(path));
|
auto child = TRY(PathParser::basename(path));
|
||||||
@ -245,7 +275,7 @@ namespace VFS
|
|||||||
kdbgln("vfs: Mounting filesystem on target %s", path);
|
kdbgln("vfs: Mounting filesystem on target %s", path);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, working_directory));
|
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, extra_groups, working_directory));
|
||||||
|
|
||||||
auto inode = TRY(parent_inode->find(child.chars()));
|
auto inode = TRY(parent_inode->find(child.chars()));
|
||||||
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
@ -260,7 +290,8 @@ namespace VFS
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> umount(const char* path, Credentials auth, SharedPtr<VFS::Inode> working_directory)
|
Result<void> umount(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||||
|
SharedPtr<VFS::Inode> working_directory)
|
||||||
{
|
{
|
||||||
auto parent_path = TRY(PathParser::dirname(path));
|
auto parent_path = TRY(PathParser::dirname(path));
|
||||||
auto child = TRY(PathParser::basename(path));
|
auto child = TRY(PathParser::basename(path));
|
||||||
@ -269,7 +300,7 @@ namespace VFS
|
|||||||
|
|
||||||
kinfoln("vfs: Unmounting filesystem on target %s", path);
|
kinfoln("vfs: Unmounting filesystem on target %s", path);
|
||||||
|
|
||||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, working_directory));
|
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, extra_groups, working_directory));
|
||||||
|
|
||||||
auto inode = TRY(parent_inode->find(child.chars()));
|
auto inode = TRY(parent_inode->find(child.chars()));
|
||||||
if (!inode->is_mountpoint()) return err(EINVAL);
|
if (!inode->is_mountpoint()) return err(EINVAL);
|
||||||
|
@ -306,21 +306,23 @@ namespace VFS
|
|||||||
virtual ~DeviceInode() = default;
|
virtual ~DeviceInode() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth,
|
Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||||
SharedPtr<VFS::Inode> working_directory = {},
|
SharedPtr<VFS::Inode> working_directory = {},
|
||||||
bool follow_last_symlink = true);
|
bool follow_last_symlink = true);
|
||||||
|
|
||||||
Result<SharedPtr<Inode>> create_directory(const char* path, mode_t mode, Credentials auth,
|
Result<SharedPtr<Inode>> create_directory(const char* path, mode_t mode, Credentials auth,
|
||||||
|
const Vector<gid_t>* extra_groups,
|
||||||
SharedPtr<VFS::Inode> working_directory = {});
|
SharedPtr<VFS::Inode> working_directory = {});
|
||||||
|
|
||||||
Result<SharedPtr<Inode>> create_file(const char* path, mode_t mode, Credentials auth,
|
Result<SharedPtr<Inode>> create_file(const char* path, mode_t mode, Credentials auth,
|
||||||
|
const Vector<gid_t>* extra_groups,
|
||||||
SharedPtr<VFS::Inode> working_directory = {});
|
SharedPtr<VFS::Inode> working_directory = {});
|
||||||
|
|
||||||
Result<void> validate_filename(StringView name);
|
Result<void> validate_filename(StringView name);
|
||||||
|
|
||||||
bool can_execute(SharedPtr<Inode> inode, Credentials auth);
|
bool can_execute(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups);
|
||||||
bool can_read(SharedPtr<Inode> inode, Credentials auth);
|
bool can_read(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups);
|
||||||
bool can_write(SharedPtr<Inode> inode, Credentials auth);
|
bool can_write(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups);
|
||||||
bool is_setuid(SharedPtr<Inode> inode);
|
bool is_setuid(SharedPtr<Inode> inode);
|
||||||
bool is_setgid(SharedPtr<Inode> inode);
|
bool is_setgid(SharedPtr<Inode> inode);
|
||||||
bool is_sticky(SharedPtr<Inode> inode);
|
bool is_sticky(SharedPtr<Inode> inode);
|
||||||
@ -332,7 +334,8 @@ namespace VFS
|
|||||||
Result<void> mount_root(SharedPtr<VFS::FileSystem> fs);
|
Result<void> mount_root(SharedPtr<VFS::FileSystem> fs);
|
||||||
Result<void> pivot_root(const char* new_root, const char* put_old, SharedPtr<VFS::Inode> working_directory);
|
Result<void> pivot_root(const char* new_root, const char* put_old, SharedPtr<VFS::Inode> working_directory);
|
||||||
Result<void> mount(const char* path, SharedPtr<VFS::FileSystem> fs, Credentials auth,
|
Result<void> mount(const char* path, SharedPtr<VFS::FileSystem> fs, Credentials auth,
|
||||||
SharedPtr<Inode> working_directory = {});
|
const Vector<gid_t>* extra_groups, SharedPtr<Inode> working_directory = {});
|
||||||
|
|
||||||
Result<void> umount(const char* path, Credentials auth, SharedPtr<Inode> working_directory = {});
|
Result<void> umount(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||||
|
SharedPtr<Inode> working_directory = {});
|
||||||
}
|
}
|
||||||
|
@ -65,8 +65,8 @@ void oom_thread()
|
|||||||
mark_critical(BinaryFormat::init(), "Failed to register initial binary formats");
|
mark_critical(BinaryFormat::init(), "Failed to register initial binary formats");
|
||||||
mark_critical(FSRegistry::init(), "Failed to register initial file systems");
|
mark_critical(FSRegistry::init(), "Failed to register initial file systems");
|
||||||
|
|
||||||
auto init =
|
auto init = mark_critical(VFS::resolve_path("/bin/preinit", Credentials {}, nullptr),
|
||||||
mark_critical(VFS::resolve_path("/bin/preinit", Credentials {}), "Can't find init in the initial ramfs!");
|
"Can't find init in the initial ramfs!");
|
||||||
auto init_thread = mark_critical(Scheduler::create_init_process(init, "/bin/preinit"),
|
auto init_thread = mark_critical(Scheduler::create_init_process(init, "/bin/preinit"),
|
||||||
"Failed to create PID 1 process for init");
|
"Failed to create PID 1 process for init");
|
||||||
|
|
||||||
|
@ -52,14 +52,14 @@ Result<usize> UnixSocket::recv(u8* buf, usize length, int) const
|
|||||||
return m_data.dequeue_data(buf, length);
|
return m_data.dequeue_data(buf, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result<void> bind_socket_to_fs(const char* path, Credentials auth, SharedPtr<VFS::Inode> working_directory,
|
static Result<void> bind_socket_to_fs(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||||
SharedPtr<UnixSocket> socket)
|
SharedPtr<VFS::Inode> working_directory, SharedPtr<UnixSocket> socket)
|
||||||
{
|
{
|
||||||
auto parent_path = TRY(PathParser::dirname(path));
|
auto parent_path = TRY(PathParser::dirname(path));
|
||||||
|
|
||||||
auto parent_inode = TRY(VFS::resolve_path(parent_path.chars(), auth, working_directory));
|
auto parent_inode = TRY(VFS::resolve_path(parent_path.chars(), auth, extra_groups, working_directory));
|
||||||
|
|
||||||
if (!VFS::can_write(parent_inode, auth)) return err(EACCES);
|
if (!VFS::can_write(parent_inode, auth, extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
auto child_name = TRY(PathParser::basename(path));
|
auto child_name = TRY(PathParser::basename(path));
|
||||||
|
|
||||||
@ -91,7 +91,8 @@ Result<void> UnixSocket::bind(struct sockaddr* addr, socklen_t addrlen)
|
|||||||
m_metadata.uid = current->auth.euid;
|
m_metadata.uid = current->auth.euid;
|
||||||
m_metadata.gid = current->auth.egid;
|
m_metadata.gid = current->auth.egid;
|
||||||
|
|
||||||
auto rc = bind_socket_to_fs(path.chars(), current->auth, current->current_directory, SharedPtr<Socket> { this });
|
auto rc = bind_socket_to_fs(path.chars(), current->auth, ¤t->extra_groups, current->current_directory,
|
||||||
|
SharedPtr<Socket> { this });
|
||||||
if (rc.has_error())
|
if (rc.has_error())
|
||||||
{
|
{
|
||||||
if (rc.error() == EEXIST) return err(EADDRINUSE);
|
if (rc.error() == EEXIST) return err(EADDRINUSE);
|
||||||
@ -123,10 +124,11 @@ Result<void> UnixSocket::connect(Registers* regs, int flags, struct sockaddr* ad
|
|||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
auto inode =
|
||||||
|
TRY(VFS::resolve_path(path.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||||
if (inode->type() != VFS::InodeType::Socket)
|
if (inode->type() != VFS::InodeType::Socket)
|
||||||
return err(ENOTSOCK); // FIXME: POSIX doesn't say what error to return here?
|
return err(ENOTSOCK); // FIXME: POSIX doesn't say what error to return here?
|
||||||
if (!VFS::can_write(inode, current->auth)) return err(EACCES);
|
if (!VFS::can_write(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
auto socket = (SharedPtr<UnixSocket>)inode;
|
auto socket = (SharedPtr<UnixSocket>)inode;
|
||||||
if (socket->m_state != State::Listening) return err(ECONNREFUSED);
|
if (socket->m_state != State::Listening) return err(ECONNREFUSED);
|
||||||
|
@ -14,10 +14,10 @@ Result<u64> sys_chdir(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
if (PathParser::is_absolute(path.view()))
|
if (PathParser::is_absolute(path.view()))
|
||||||
{
|
{
|
||||||
SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth));
|
SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth, ¤t->extra_groups));
|
||||||
|
|
||||||
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
|
if (!VFS::can_execute(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
inode->add_handle();
|
inode->add_handle();
|
||||||
if (current->current_directory) current->current_directory->remove_handle();
|
if (current->current_directory) current->current_directory->remove_handle();
|
||||||
@ -29,10 +29,11 @@ Result<u64> sys_chdir(Registers*, SyscallArgs args)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
SharedPtr<VFS::Inode> inode =
|
||||||
|
TRY(VFS::resolve_path(path.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||||
|
|
||||||
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
|
if (!VFS::can_execute(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
auto old_wdir = current->current_directory_path.view();
|
auto old_wdir = current->current_directory_path.view();
|
||||||
|
|
||||||
|
@ -68,9 +68,10 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
|
|
||||||
TRY(check_pledge(current, Promise::p_exec));
|
TRY(check_pledge(current, Promise::p_exec));
|
||||||
|
|
||||||
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
auto inode =
|
||||||
|
TRY(VFS::resolve_path(path.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||||
|
|
||||||
if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
|
if (!VFS::can_execute(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
#ifdef EXEC_DEBUG
|
#ifdef EXEC_DEBUG
|
||||||
kdbgln("exec: attempting to replace current image with %s", path.chars());
|
kdbgln("exec: attempting to replace current image with %s", path.chars());
|
||||||
@ -159,6 +160,8 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
|||||||
|
|
||||||
TRY(check_pledge(current, Promise::p_proc));
|
TRY(check_pledge(current, Promise::p_proc));
|
||||||
|
|
||||||
|
auto extra_groups = TRY(current->extra_groups.shallow_copy());
|
||||||
|
|
||||||
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory()); });
|
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory()); });
|
||||||
|
|
||||||
memcpy(¤t->regs, regs, sizeof(*regs));
|
memcpy(¤t->regs, regs, sizeof(*regs));
|
||||||
@ -183,6 +186,7 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
|||||||
thread->controlling_terminal = current->controlling_terminal;
|
thread->controlling_terminal = current->controlling_terminal;
|
||||||
thread->pgid = current->pgid;
|
thread->pgid = current->pgid;
|
||||||
thread->sid = current->sid;
|
thread->sid = current->sid;
|
||||||
|
thread->extra_groups = move(extra_groups);
|
||||||
|
|
||||||
thread->virtual_clock.set_resolution(1'000'000);
|
thread->virtual_clock.set_resolution(1'000'000);
|
||||||
thread->profiling_clock.set_resolution(1'000'000);
|
thread->profiling_clock.set_resolution(1'000'000);
|
||||||
|
@ -259,9 +259,10 @@ Result<u64> sys_truncate(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
TRY(check_pledge(current, Promise::p_wpath));
|
TRY(check_pledge(current, Promise::p_wpath));
|
||||||
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
auto inode =
|
||||||
|
TRY(VFS::resolve_path(path.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||||
|
|
||||||
if (!VFS::can_write(inode, current->auth)) return err(EACCES);
|
if (!VFS::can_write(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
TRY(inode->truncate(length));
|
TRY(inode->truncate(length));
|
||||||
|
|
||||||
@ -308,8 +309,8 @@ Result<u64> sys_utimensat(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
if (allow_write_access)
|
if (allow_write_access)
|
||||||
{
|
{
|
||||||
if (!VFS::can_write(inode, current->auth) && current->auth.euid != inode->metadata().uid &&
|
if (!VFS::can_write(inode, current->auth, ¤t->extra_groups) &&
|
||||||
current->auth.euid != 0)
|
current->auth.euid != inode->metadata().uid && current->auth.euid != 0)
|
||||||
return err(EACCES);
|
return err(EACCES);
|
||||||
}
|
}
|
||||||
else if (current->auth.euid != inode->metadata().uid && current->auth.euid != 0)
|
else if (current->auth.euid != inode->metadata().uid && current->auth.euid != 0)
|
||||||
|
@ -23,7 +23,7 @@ Result<u64> sys_unlinkat(Registers*, SyscallArgs args)
|
|||||||
kinfoln("unlinkat: remove %s from directory %s, dirfd is %d", basename.chars(), dirname.chars(), dirfd);
|
kinfoln("unlinkat: remove %s from directory %s, dirfd is %d", basename.chars(), dirname.chars(), dirfd);
|
||||||
|
|
||||||
auto inode = TRY(current->resolve_atfile(dirfd, dirname, false, false));
|
auto inode = TRY(current->resolve_atfile(dirfd, dirname, false, false));
|
||||||
if (!VFS::can_write(inode, current->auth)) return err(EACCES);
|
if (!VFS::can_write(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
auto child = TRY(inode->find(basename.chars()));
|
auto child = TRY(inode->find(basename.chars()));
|
||||||
if (flags == AT_REMOVEDIR && child->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
if (flags == AT_REMOVEDIR && child->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
@ -52,7 +52,7 @@ Result<u64> sys_symlinkat(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
auto parent_inode = TRY(current->resolve_atfile(dirfd, parent, false, true));
|
auto parent_inode = TRY(current->resolve_atfile(dirfd, parent, false, true));
|
||||||
|
|
||||||
if (!VFS::can_write(parent_inode, current->auth)) return err(EACCES);
|
if (!VFS::can_write(parent_inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
auto child_name = TRY(PathParser::basename(linkpath.view()));
|
auto child_name = TRY(PathParser::basename(linkpath.view()));
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ Result<u64> sys_linkat(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
if (target->fs() != parent_inode->fs()) return err(EXDEV);
|
if (target->fs() != parent_inode->fs()) return err(EXDEV);
|
||||||
|
|
||||||
if (!VFS::can_write(parent_inode, current->auth)) return err(EACCES);
|
if (!VFS::can_write(parent_inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
auto child_name = TRY(PathParser::basename(newpath.view()));
|
auto child_name = TRY(PathParser::basename(newpath.view()));
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ Result<u64> sys_mkdir(Registers*, SyscallArgs args)
|
|||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
TRY(check_pledge(current, Promise::p_cpath));
|
TRY(check_pledge(current, Promise::p_cpath));
|
||||||
|
|
||||||
auto inode =
|
auto inode = TRY(VFS::create_directory(path.chars(), mode & ~current->umask, current->auth, ¤t->extra_groups,
|
||||||
TRY(VFS::create_directory(path.chars(), mode & ~current->umask, current->auth, current->current_directory));
|
current->current_directory));
|
||||||
auto metadata = inode->metadata();
|
auto metadata = inode->metadata();
|
||||||
metadata.uid = current->auth.euid;
|
metadata.uid = current->auth.euid;
|
||||||
metadata.gid = current->auth.egid;
|
metadata.gid = current->auth.egid;
|
||||||
|
@ -19,7 +19,8 @@ Result<u64> sys_mount(Registers*, SyscallArgs args)
|
|||||||
if (current->auth.euid != 0) return err(EPERM);
|
if (current->auth.euid != 0) return err(EPERM);
|
||||||
|
|
||||||
auto get_source = [current, &source]() -> Result<SharedPtr<Device>> {
|
auto get_source = [current, &source]() -> Result<SharedPtr<Device>> {
|
||||||
auto inode = TRY(VFS::resolve_path(source.chars(), current->auth, current->current_directory));
|
auto inode =
|
||||||
|
TRY(VFS::resolve_path(source.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||||
if (inode->type() != VFS::InodeType::BlockDevice) return err(ENOTBLK);
|
if (inode->type() != VFS::InodeType::BlockDevice) return err(ENOTBLK);
|
||||||
dev_t device_id = inode->metadata().devid;
|
dev_t device_id = inode->metadata().devid;
|
||||||
return TRY(DeviceRegistry::fetch_special_device(luna_dev_major(device_id), luna_dev_minor(device_id)));
|
return TRY(DeviceRegistry::fetch_special_device(luna_dev_major(device_id), luna_dev_minor(device_id)));
|
||||||
@ -40,7 +41,7 @@ Result<u64> sys_mount(Registers*, SyscallArgs args)
|
|||||||
fs = TRY(factory(device));
|
fs = TRY(factory(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(VFS::mount(target.chars(), fs, current->auth, current->current_directory));
|
TRY(VFS::mount(target.chars(), fs, current->auth, ¤t->extra_groups, current->current_directory));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -53,7 +54,7 @@ Result<u64> sys_umount(Registers*, SyscallArgs args)
|
|||||||
TRY(check_pledge(current, Promise::p_mount));
|
TRY(check_pledge(current, Promise::p_mount));
|
||||||
if (current->auth.euid != 0) return err(EPERM);
|
if (current->auth.euid != 0) return err(EPERM);
|
||||||
|
|
||||||
TRY(VFS::umount(target.chars(), current->auth, current->current_directory));
|
TRY(VFS::umount(target.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,8 @@ Result<u64> sys_openat(Registers*, SyscallArgs args)
|
|||||||
{
|
{
|
||||||
if (error == ENOENT && (flags & O_CREAT) && !path.is_empty())
|
if (error == ENOENT && (flags & O_CREAT) && !path.is_empty())
|
||||||
{
|
{
|
||||||
inode = TRY(VFS::create_file(path.chars(), mode & ~current->umask, current->auth, parent_inode));
|
inode = TRY(VFS::create_file(path.chars(), mode & ~current->umask, current->auth, ¤t->extra_groups,
|
||||||
|
parent_inode));
|
||||||
// FIXME: Pass these in create_file().
|
// FIXME: Pass these in create_file().
|
||||||
auto metadata = inode->metadata();
|
auto metadata = inode->metadata();
|
||||||
metadata.uid = current->auth.euid;
|
metadata.uid = current->auth.euid;
|
||||||
@ -58,8 +59,8 @@ Result<u64> sys_openat(Registers*, SyscallArgs args)
|
|||||||
return err(EEXIST);
|
return err(EEXIST);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((flags & O_RDONLY) && !VFS::can_read(inode, current->auth)) return err(EACCES);
|
if ((flags & O_RDONLY) && !VFS::can_read(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
if ((flags & O_WRONLY) && !VFS::can_write(inode, current->auth)) return err(EACCES);
|
if ((flags & O_WRONLY) && !VFS::can_write(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||||
}
|
}
|
||||||
|
|
||||||
inode = TRY(inode->open());
|
inode = TRY(inode->open());
|
||||||
|
@ -81,9 +81,9 @@ Result<u64> sys_faccessat(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
auto inode = TRY(current->resolve_atfile(dirfd, path, false, true));
|
auto inode = TRY(current->resolve_atfile(dirfd, path, false, true));
|
||||||
|
|
||||||
if ((amode & R_OK) && !VFS::can_read(inode, creds)) return err(EACCES);
|
if ((amode & R_OK) && !VFS::can_read(inode, creds, ¤t->extra_groups)) return err(EACCES);
|
||||||
if ((amode & W_OK) && !VFS::can_write(inode, creds)) return err(EACCES);
|
if ((amode & W_OK) && !VFS::can_write(inode, creds, ¤t->extra_groups)) return err(EACCES);
|
||||||
if ((amode & X_OK) && !VFS::can_execute(inode, creds)) return err(EACCES);
|
if ((amode & X_OK) && !VFS::can_execute(inode, creds, ¤t->extra_groups)) return err(EACCES);
|
||||||
|
|
||||||
// Either all checks succeeded, or amode == F_OK and the file exists, since resolve_atfile() would have failed
|
// Either all checks succeeded, or amode == F_OK and the file exists, since resolve_atfile() would have failed
|
||||||
// otherwise.
|
// otherwise.
|
||||||
|
@ -156,6 +156,7 @@ namespace Scheduler
|
|||||||
thread->pgid = 1;
|
thread->pgid = 1;
|
||||||
thread->cmdline = name;
|
thread->cmdline = name;
|
||||||
thread->auth = Credentials { .uid = 0, .euid = 0, .suid = 0, .gid = 0, .egid = 0, .sgid = 0 };
|
thread->auth = Credentials { .uid = 0, .euid = 0, .suid = 0, .gid = 0, .egid = 0, .sgid = 0 };
|
||||||
|
thread->extra_groups = {};
|
||||||
|
|
||||||
Vector<String> args;
|
Vector<String> args;
|
||||||
auto name_string = TRY(String::from_cstring(name));
|
auto name_string = TRY(String::from_cstring(name));
|
||||||
|
@ -64,10 +64,11 @@ Result<SharedPtr<VFS::Inode>> Thread::resolve_atfile(int dirfd, const String& pa
|
|||||||
if (parent_inode) *parent_inode = this->current_directory;
|
if (parent_inode) *parent_inode = this->current_directory;
|
||||||
|
|
||||||
if (PathParser::is_absolute(path.view()))
|
if (PathParser::is_absolute(path.view()))
|
||||||
return VFS::resolve_path(path.chars(), this->auth, {}, follow_last_symlink);
|
return VFS::resolve_path(path.chars(), this->auth, &this->extra_groups, {}, follow_last_symlink);
|
||||||
|
|
||||||
if (dirfd == AT_FDCWD)
|
if (dirfd == AT_FDCWD)
|
||||||
return VFS::resolve_path(path.chars(), this->auth, this->current_directory, follow_last_symlink);
|
return VFS::resolve_path(path.chars(), this->auth, &this->extra_groups, this->current_directory,
|
||||||
|
follow_last_symlink);
|
||||||
|
|
||||||
auto descriptor = TRY(resolve_fd(dirfd));
|
auto descriptor = TRY(resolve_fd(dirfd));
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ Result<SharedPtr<VFS::Inode>> Thread::resolve_atfile(int dirfd, const String& pa
|
|||||||
|
|
||||||
if (path.is_empty() && allow_empty_path) return descriptor->inode();
|
if (path.is_empty() && allow_empty_path) return descriptor->inode();
|
||||||
|
|
||||||
return VFS::resolve_path(path.chars(), this->auth, descriptor->inode(), follow_last_symlink);
|
return VFS::resolve_path(path.chars(), this->auth, &this->extra_groups, descriptor->inode(), follow_last_symlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void Thread::exit_and_signal_parent(int _status)
|
[[noreturn]] void Thread::exit_and_signal_parent(int _status)
|
||||||
|
@ -54,6 +54,7 @@ struct Thread : public LinkedListNode<Thread>
|
|||||||
pid_t sid { 0 };
|
pid_t sid { 0 };
|
||||||
|
|
||||||
Credentials auth;
|
Credentials auth;
|
||||||
|
Vector<gid_t> extra_groups;
|
||||||
|
|
||||||
u64 user_ticks_self = 0;
|
u64 user_ticks_self = 0;
|
||||||
u64 kernel_ticks_self = 0;
|
u64 kernel_ticks_self = 0;
|
||||||
|
@ -252,7 +252,7 @@ template <typename T> class Vector
|
|||||||
|
|
||||||
Result<void> resize(usize new_capacity)
|
Result<void> resize(usize new_capacity)
|
||||||
{
|
{
|
||||||
if (new_capacity < m_capacity) return {};
|
if (new_capacity <= m_capacity) return {};
|
||||||
|
|
||||||
const usize new_byte_capacity = new_capacity * sizeof(T);
|
const usize new_byte_capacity = new_capacity * sizeof(T);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user