1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 06:58:11 +00:00

Kernel: Add a basic chroot() syscall :^)

The chroot() syscall now allows the superuser to isolate a process into
a specific subtree of the filesystem. This is not strictly permanent,
as it is also possible for a superuser to break *out* of a chroot, but
it is a useful mechanism for isolating unprivileged processes.

The VFS now uses the current process's root_directory() as the root for
path resolution purposes. The root directory is stored as an uncached
Custody in the Process object.
This commit is contained in:
Andreas Kling 2020-01-10 23:14:04 +01:00
parent 944fbf507a
commit ddd0b19281
7 changed files with 63 additions and 8 deletions

View file

@ -565,6 +565,7 @@ pid_t Process::sys$fork(RegisterDump& regs)
{
Thread* child_first_thread = nullptr;
auto* child = new Process(child_first_thread, m_name, m_uid, m_gid, m_pid, m_ring, m_cwd, m_executable, m_tty, this);
child->m_root_directory = m_root_directory;
#ifdef FORK_DEBUG
dbgprintf("fork: child=%p\n", child);
@ -966,15 +967,21 @@ Process* Process::create_user_process(Thread*& first_thread, const String& path,
arguments.append(parts.last());
}
RefPtr<Custody> cwd;
RefPtr<Custody> root;
{
InterruptDisabler disabler;
if (auto* parent = Process::from_pid(parent_pid))
if (auto* parent = Process::from_pid(parent_pid)) {
cwd = parent->m_cwd;
root = parent->m_root_directory;
}
}
if (!cwd)
cwd = VFS::the().root_custody();
if (!root)
root = VFS::the().root_custody();
auto* process = new Process(first_thread, parts.take_last(), uid, gid, parent_pid, Ring3, move(cwd), nullptr, tty);
error = process->exec(path, move(arguments), move(environment));
@ -2650,6 +2657,7 @@ void Process::finalize()
m_tty = nullptr;
m_executable = nullptr;
m_cwd = nullptr;
m_root_directory = nullptr;
m_elf_loader = nullptr;
disown_all_shared_buffers();
@ -4127,3 +4135,29 @@ int Process::sys$set_process_boost(pid_t pid, int amount)
process->m_priority_boost = amount;
return 0;
}
int Process::sys$chroot(const char* user_path, size_t path_length)
{
if (!is_superuser())
return -EPERM;
auto path = get_syscall_path_argument(user_path, path_length);
if (path.is_error())
return path.error();
auto directory_or_error = VFS::the().open_directory(path.value(), current_directory());
if (directory_or_error.is_error())
return directory_or_error.error();
set_root_directory(Custody::create(nullptr, "", directory_or_error.value()->inode()));
return 0;
}
Custody& Process::root_directory()
{
if (!m_root_directory)
m_root_directory = VFS::the().root_custody();
return *m_root_directory;
}
void Process::set_root_directory(const Custody& root)
{
m_root_directory = root;
}