/* * Copyright (c) 2018-2020, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include namespace Kernel { constexpr size_t jail_name_max_size = 50; ErrorOr Process::sys$jail_create(Userspace user_params) { VERIFY_NO_PROCESS_BIG_LOCK(this); TRY(require_promise(Pledge::jail)); auto params = TRY(copy_typed_from_user(user_params)); auto jail_name = TRY(get_syscall_path_argument(params.name)); if (jail_name->length() > jail_name_max_size) return ENAMETOOLONG; params.index = TRY(m_attached_jail.with([&](auto& my_jail) -> ErrorOr { // Note: If we are already in a jail, don't let the process to be able to create other jails // even if it will not be able to join them later on. The reason for this is to prevent as much as possible // any info leak about the "outside world" jail metadata. if (my_jail) return Error::from_errno(EPERM); auto jail = TRY(JailManagement::the().create_jail(move(jail_name))); return jail->index().value(); })); // Note: We do the copy_to_user outside of the m_attached_jail Spinlock locked scope because // we rely on page faults to work properly. TRY(copy_to_user(user_params, ¶ms)); return 0; } ErrorOr Process::sys$jail_attach(Userspace user_params) { VERIFY_NO_PROCESS_BIG_LOCK(this); TRY(require_promise(Pledge::jail)); auto params = TRY(copy_typed_from_user(user_params)); return m_attached_jail.with([&](auto& my_jail) -> ErrorOr { // Note: If we are already in a jail, don't let the process escape it even if // it knows there are other jails. // Note: To ensure the process doesn't try to maliciously enumerate all jails // in the system, just return EPERM before doing anything else. if (my_jail) return EPERM; auto jail = JailManagement::the().find_jail_by_index(static_cast(params.index)); if (!jail) return EINVAL; my_jail = *jail; my_jail->attach_count().with([&](auto& attach_count) { attach_count++; }); return 0; }); } }