Serenity Operating System
1/*
2 * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/Userspace.h>
8#include <Kernel/API/Ioctl.h>
9#include <Kernel/Jail.h>
10#include <Kernel/Process.h>
11#include <Kernel/StdLib.h>
12
13namespace Kernel {
14
15constexpr size_t jail_name_max_size = 50;
16
17ErrorOr<FlatPtr> Process::sys$jail_create(Userspace<Syscall::SC_jail_create_params*> user_params)
18{
19 VERIFY_NO_PROCESS_BIG_LOCK(this);
20 TRY(require_promise(Pledge::jail));
21
22 auto params = TRY(copy_typed_from_user(user_params));
23 auto jail_name = TRY(get_syscall_path_argument(params.name));
24 if (jail_name->length() > jail_name_max_size)
25 return ENAMETOOLONG;
26
27 params.index = TRY(m_attached_jail.with([&](auto& my_jail) -> ErrorOr<u64> {
28 // Note: If we are already in a jail, don't let the process to be able to create other jails
29 // even if it will not be able to join them later on. The reason for this is to prevent as much as possible
30 // any info leak about the "outside world" jail metadata.
31 if (my_jail)
32 return Error::from_errno(EPERM);
33 auto jail = TRY(Jail::create(move(jail_name)));
34 return jail->index().value();
35 }));
36 // Note: We do the copy_to_user outside of the m_attached_jail Spinlock locked scope because
37 // we rely on page faults to work properly.
38 TRY(copy_to_user(user_params, ¶ms));
39 return 0;
40}
41
42ErrorOr<FlatPtr> Process::sys$jail_attach(Userspace<Syscall::SC_jail_attach_params const*> user_params)
43{
44 VERIFY_NO_PROCESS_BIG_LOCK(this);
45 TRY(require_promise(Pledge::jail));
46
47 // NOTE: Because the user might run a binary that is using this syscall and
48 // that binary was marked as SUID, then the user might be unaware of the
49 // fact that while no new setuid binaries might be executed, he is already
50 // running within such binary so for the sake of completeness and preventing
51 // naive sense of being secure, we should block that.
52 TRY(with_protected_data([&](auto& protected_data) -> ErrorOr<void> {
53 if (protected_data.executable_is_setid)
54 return EPERM;
55 return {};
56 }));
57
58 auto params = TRY(copy_typed_from_user(user_params));
59 return m_attached_jail.with([&](auto& my_jail) -> ErrorOr<FlatPtr> {
60 // Note: If we are already in a jail, don't let the process escape it even if
61 // it knows there are other jails.
62 // Note: To ensure the process doesn't try to maliciously enumerate all jails
63 // in the system, just return EPERM before doing anything else.
64 if (my_jail)
65 return EPERM;
66 auto jail = Jail::find_by_index(static_cast<JailIndex>(params.index));
67 if (!jail)
68 return EINVAL;
69 my_jail = *jail;
70 my_jail->attach_count().with([&](auto& attach_count) {
71 attach_count++;
72 });
73 m_jail_process_list.with([&](auto& list_ptr) {
74 list_ptr = my_jail->process_list();
75 if (list_ptr) {
76 list_ptr->attached_processes().with([&](auto& list) {
77 list.append(*this);
78 });
79 }
80 });
81 return 0;
82 });
83}
84
85}