From 8289759f1da4c8fa6a390b8e0138a4dd312d1442 Mon Sep 17 00:00:00 2001 From: Liav A Date: Thu, 12 Jan 2023 22:47:09 +0200 Subject: [PATCH] Kernel: Allow configuring a Jail to not impose PID isolation restriction This is quite useful for userspace applications that can't cope with the restriction, but it's still useful to impose other non-configurable restrictions by using jails. --- Base/usr/share/man/man1/jail-create.md | 9 ++++++++- Base/usr/share/man/man7/Mitigations.md | 2 +- Kernel/API/Jail.h | 17 +++++++++++++++++ Kernel/API/Syscall.h | 1 + Kernel/Jail.cpp | 16 ++++++++++------ Kernel/Jail.h | 8 ++++---- Kernel/Syscalls/jail.cpp | 4 ++-- Userland/Libraries/LibCore/System.cpp | 4 ++-- Userland/Libraries/LibCore/System.h | 6 +++++- Userland/Utilities/jail-attach.cpp | 4 +++- Userland/Utilities/jail-create.cpp | 14 +++++++++----- 11 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 Kernel/API/Jail.h diff --git a/Base/usr/share/man/man1/jail-create.md b/Base/usr/share/man/man1/jail-create.md index c6660ad9bd3..1cc71f18ab3 100644 --- a/Base/usr/share/man/man1/jail-create.md +++ b/Base/usr/share/man/man1/jail-create.md @@ -12,9 +12,16 @@ $ jail-create `jail-create` creates a new jail, with a specified name +## Options + +* `-p`, `--pid-isolation`: Use PID-isolation (as a custom isolation option) + ## Examples ```sh -# Create jail with the name "test-jail" +# Create jail with the name "test-jail", with no PID isolation $ jail-create test-jail + +# Create jail with the name "test-jail", with PID isolation +$ jail-create -p test-jail ``` diff --git a/Base/usr/share/man/man7/Mitigations.md b/Base/usr/share/man/man7/Mitigations.md index 590b4e99004..ad8cdd9336c 100644 --- a/Base/usr/share/man/man7/Mitigations.md +++ b/Base/usr/share/man/man7/Mitigations.md @@ -95,7 +95,7 @@ Kernel: Add a basic implementation of unveil() `jails` are mitigation originating from FreeBSD. It allows a program to be placed inside a lightweight OS-level virtualization environment. -Current restrictions on jailed processes: +Current restrictions on jailed processes (configurable when creating a Jail): - Process ID view isolation, being limited (both in `/proc` and `/sys/kernel/processes`) to only processes that share the same jail. Special restrictions on filesystem also apply: diff --git a/Kernel/API/Jail.h b/Kernel/API/Jail.h new file mode 100644 index 00000000000..cb2885fa187 --- /dev/null +++ b/Kernel/API/Jail.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +enum class JailIsolationFlags : u32 { + None = 0, + PIDIsolation = 1 << 0, +}; + +AK_ENUM_BITWISE_OPERATORS(JailIsolationFlags); diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index b2de4d18087..122eb2d8268 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -343,6 +343,7 @@ struct SC_setkeymap_params { struct SC_jail_create_params { u64 index; StringArgument name; + int flags; }; struct SC_jail_attach_params { diff --git a/Kernel/Jail.cpp b/Kernel/Jail.cpp index b0a602afd5b..e364b21b135 100644 --- a/Kernel/Jail.cpp +++ b/Kernel/Jail.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -19,16 +20,19 @@ static JailIndex generate_jail_id() return s_jail_id.fetch_add(1); } -NonnullRefPtr Jail::process_list() +RefPtr Jail::process_list() { return m_process_list; } -ErrorOr> Jail::create(NonnullOwnPtr name) +ErrorOr> Jail::create(NonnullOwnPtr name, unsigned flags) { + RefPtr jail_process_list; + if (flags & static_cast(JailIsolationFlags::PIDIsolation)) + jail_process_list = TRY(ProcessList::create()); + return s_all_instances->with([&](auto& list) -> ErrorOr> { - auto process_list = TRY(ProcessList::create()); - auto jail = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Jail(move(name), generate_jail_id(), move(process_list)))); + auto jail = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Jail(move(name), generate_jail_id(), jail_process_list))); list.append(jail); return jail; }); @@ -61,10 +65,10 @@ RefPtr Jail::find_by_index(JailIndex index) }); } -Jail::Jail(NonnullOwnPtr name, JailIndex index, NonnullRefPtr process_list) +Jail::Jail(NonnullOwnPtr name, JailIndex index, RefPtr process_list) : m_name(move(name)) , m_index(index) - , m_process_list(move(process_list)) + , m_process_list(process_list) { } diff --git a/Kernel/Jail.h b/Kernel/Jail.h index 2f8355eccbc..72817db3109 100644 --- a/Kernel/Jail.h +++ b/Kernel/Jail.h @@ -28,10 +28,10 @@ AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, JailIndex); class Jail : public AtomicRefCounted { public: - NonnullRefPtr process_list(); + RefPtr process_list(); static RefPtr find_by_index(JailIndex); - static ErrorOr> create(NonnullOwnPtr name); + static ErrorOr> create(NonnullOwnPtr name, unsigned flags); static ErrorOr for_each_when_process_is_not_jailed(Function(Jail const&)> callback); StringView name() const { return m_name->view(); } @@ -41,7 +41,7 @@ public: SpinlockProtected& attach_count() { return m_attach_count; } private: - Jail(NonnullOwnPtr, JailIndex, NonnullRefPtr); + Jail(NonnullOwnPtr, JailIndex, RefPtr); NonnullOwnPtr m_name; JailIndex const m_index; @@ -52,7 +52,7 @@ public: using List = IntrusiveListRelaxedConst<&Jail::m_list_node>; private: - NonnullRefPtr const m_process_list; + RefPtr const m_process_list; SpinlockProtected m_attach_count { 0 }; }; diff --git a/Kernel/Syscalls/jail.cpp b/Kernel/Syscalls/jail.cpp index 5a36bcbce12..8c6dd443519 100644 --- a/Kernel/Syscalls/jail.cpp +++ b/Kernel/Syscalls/jail.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include @@ -30,7 +30,7 @@ ErrorOr Process::sys$jail_create(Userspace(params.flags))); return jail->index().value(); })); // Note: We do the copy_to_user outside of the m_attached_jail Spinlock locked scope because diff --git a/Userland/Libraries/LibCore/System.cpp b/Userland/Libraries/LibCore/System.cpp index 04624f7a379..24d37968103 100644 --- a/Userland/Libraries/LibCore/System.cpp +++ b/Userland/Libraries/LibCore/System.cpp @@ -1172,9 +1172,9 @@ ErrorOr join_jail(u64 jail_index) HANDLE_SYSCALL_RETURN_VALUE("jail_attach", rc, {}); } -ErrorOr create_jail(StringView jail_name) +ErrorOr create_jail(StringView jail_name, JailIsolationFlags flags) { - Syscall::SC_jail_create_params params { 0, { jail_name.characters_without_null_termination(), jail_name.length() } }; + Syscall::SC_jail_create_params params { 0, { jail_name.characters_without_null_termination(), jail_name.length() }, static_cast(flags) }; int rc = syscall(SC_jail_create, ¶ms); HANDLE_SYSCALL_RETURN_VALUE("jail_create", rc, static_cast(params.index)); } diff --git a/Userland/Libraries/LibCore/System.h b/Userland/Libraries/LibCore/System.h index 664db9c63a6..75e4fceb644 100644 --- a/Userland/Libraries/LibCore/System.h +++ b/Userland/Libraries/LibCore/System.h @@ -31,6 +31,10 @@ #include #include +#ifdef AK_OS_SERENITY +# include +#endif + #if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID) # include #endif @@ -191,7 +195,7 @@ ErrorOr exec(StringView filename, ReadonlySpan arguments, Sear #ifdef AK_OS_SERENITY ErrorOr join_jail(u64 jail_index); -ErrorOr create_jail(StringView jail_name); +ErrorOr create_jail(StringView jail_name, JailIsolationFlags); #endif ErrorOr socket(int domain, int type, int protocol); diff --git a/Userland/Utilities/jail-attach.cpp b/Userland/Utilities/jail-attach.cpp index 781359fcaab..91a30317da5 100644 --- a/Userland/Utilities/jail-attach.cpp +++ b/Userland/Utilities/jail-attach.cpp @@ -31,7 +31,9 @@ ErrorOr serenity_main(Main::Arguments arguments) if (existing_jail_index.has_value()) { TRY(Core::System::join_jail(existing_jail_index.value())); } else { - u64 new_jail_index = TRY(Core::System::create_jail(new_jail_name.is_null() ? ""sv : new_jail_name)); + // NOTE: We create a jail with "default" isolation options (as we define them in this program) + JailIsolationFlags default_flags = (JailIsolationFlags::PIDIsolation); + u64 new_jail_index = TRY(Core::System::create_jail(new_jail_name.is_null() ? ""sv : new_jail_name, default_flags)); TRY(Core::System::join_jail(new_jail_index)); } TRY(Core::System::exec_command(command, preserve_env)); diff --git a/Userland/Utilities/jail-create.cpp b/Userland/Utilities/jail-create.cpp index 43d235c86e0..c43627d4b7e 100644 --- a/Userland/Utilities/jail-create.cpp +++ b/Userland/Utilities/jail-create.cpp @@ -13,15 +13,19 @@ ErrorOr serenity_main(Main::Arguments arguments) { StringView new_jail_name; Core::ArgsParser args_parser; + bool pid_isolation = false; args_parser.add_positional_argument(new_jail_name, "New jail name", "jail name"); + args_parser.add_option(pid_isolation, "Use PID-isolation (as a custom isolation option)", "pid-isolation", 'p'); args_parser.parse(arguments); TRY(Core::System::pledge("stdio jail")); - if (!new_jail_name.is_null() && !new_jail_name.is_empty()) { - TRY(Core::System::create_jail(new_jail_name)); - return 0; - } + if (new_jail_name.is_null() || new_jail_name.is_empty()) + return Error::from_string_view("Can't create a jail with empty name."sv); - return Error::from_string_view("Can't create a jail with empty name."sv); + JailIsolationFlags flags = JailIsolationFlags::None; + if (pid_isolation) + flags |= JailIsolationFlags::PIDIsolation; + TRY(Core::System::create_jail(new_jail_name, flags)); + return 0; }