mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 08:44:58 +00:00
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.
This commit is contained in:
parent
cf8875426d
commit
8289759f1d
11 changed files with 62 additions and 23 deletions
|
@ -12,9 +12,16 @@ $ jail-create <name>
|
||||||
|
|
||||||
`jail-create` creates a new jail, with a specified name
|
`jail-create` creates a new jail, with a specified name
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
* `-p`, `--pid-isolation`: Use PID-isolation (as a custom isolation option)
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Create jail with the name "test-jail"
|
# Create jail with the name "test-jail", with no PID isolation
|
||||||
$ jail-create test-jail
|
$ jail-create test-jail
|
||||||
|
|
||||||
|
# Create jail with the name "test-jail", with PID isolation
|
||||||
|
$ jail-create -p test-jail
|
||||||
```
|
```
|
||||||
|
|
|
@ -95,7 +95,7 @@ Kernel: Add a basic implementation of unveil()
|
||||||
`jails` are mitigation originating from FreeBSD.
|
`jails` are mitigation originating from FreeBSD.
|
||||||
It allows a program to be placed inside a lightweight OS-level virtualization environment.
|
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.
|
- 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:
|
Special restrictions on filesystem also apply:
|
||||||
|
|
17
Kernel/API/Jail.h
Normal file
17
Kernel/API/Jail.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/EnumBits.h>
|
||||||
|
#include <AK/Types.h>
|
||||||
|
|
||||||
|
enum class JailIsolationFlags : u32 {
|
||||||
|
None = 0,
|
||||||
|
PIDIsolation = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
AK_ENUM_BITWISE_OPERATORS(JailIsolationFlags);
|
|
@ -343,6 +343,7 @@ struct SC_setkeymap_params {
|
||||||
struct SC_jail_create_params {
|
struct SC_jail_create_params {
|
||||||
u64 index;
|
u64 index;
|
||||||
StringArgument name;
|
StringArgument name;
|
||||||
|
int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_jail_attach_params {
|
struct SC_jail_attach_params {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <AK/IntrusiveList.h>
|
#include <AK/IntrusiveList.h>
|
||||||
#include <AK/Singleton.h>
|
#include <AK/Singleton.h>
|
||||||
|
#include <Kernel/API/Jail.h>
|
||||||
#include <Kernel/Jail.h>
|
#include <Kernel/Jail.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
|
|
||||||
|
@ -19,16 +20,19 @@ static JailIndex generate_jail_id()
|
||||||
return s_jail_id.fetch_add(1);
|
return s_jail_id.fetch_add(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullRefPtr<ProcessList> Jail::process_list()
|
RefPtr<ProcessList> Jail::process_list()
|
||||||
{
|
{
|
||||||
return m_process_list;
|
return m_process_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<Jail>> Jail::create(NonnullOwnPtr<KString> name)
|
ErrorOr<NonnullRefPtr<Jail>> Jail::create(NonnullOwnPtr<KString> name, unsigned flags)
|
||||||
{
|
{
|
||||||
|
RefPtr<ProcessList> jail_process_list;
|
||||||
|
if (flags & static_cast<unsigned>(JailIsolationFlags::PIDIsolation))
|
||||||
|
jail_process_list = TRY(ProcessList::create());
|
||||||
|
|
||||||
return s_all_instances->with([&](auto& list) -> ErrorOr<NonnullRefPtr<Jail>> {
|
return s_all_instances->with([&](auto& list) -> ErrorOr<NonnullRefPtr<Jail>> {
|
||||||
auto process_list = TRY(ProcessList::create());
|
auto jail = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Jail(move(name), generate_jail_id(), jail_process_list)));
|
||||||
auto jail = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Jail(move(name), generate_jail_id(), move(process_list))));
|
|
||||||
list.append(jail);
|
list.append(jail);
|
||||||
return jail;
|
return jail;
|
||||||
});
|
});
|
||||||
|
@ -61,10 +65,10 @@ RefPtr<Jail> Jail::find_by_index(JailIndex index)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Jail::Jail(NonnullOwnPtr<KString> name, JailIndex index, NonnullRefPtr<ProcessList> process_list)
|
Jail::Jail(NonnullOwnPtr<KString> name, JailIndex index, RefPtr<ProcessList> process_list)
|
||||||
: m_name(move(name))
|
: m_name(move(name))
|
||||||
, m_index(index)
|
, m_index(index)
|
||||||
, m_process_list(move(process_list))
|
, m_process_list(process_list)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,10 @@ AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, JailIndex);
|
||||||
class Jail : public AtomicRefCounted<Jail> {
|
class Jail : public AtomicRefCounted<Jail> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NonnullRefPtr<ProcessList> process_list();
|
RefPtr<ProcessList> process_list();
|
||||||
|
|
||||||
static RefPtr<Jail> find_by_index(JailIndex);
|
static RefPtr<Jail> find_by_index(JailIndex);
|
||||||
static ErrorOr<NonnullRefPtr<Jail>> create(NonnullOwnPtr<KString> name);
|
static ErrorOr<NonnullRefPtr<Jail>> create(NonnullOwnPtr<KString> name, unsigned flags);
|
||||||
static ErrorOr<void> for_each_when_process_is_not_jailed(Function<ErrorOr<void>(Jail const&)> callback);
|
static ErrorOr<void> for_each_when_process_is_not_jailed(Function<ErrorOr<void>(Jail const&)> callback);
|
||||||
|
|
||||||
StringView name() const { return m_name->view(); }
|
StringView name() const { return m_name->view(); }
|
||||||
|
@ -41,7 +41,7 @@ public:
|
||||||
SpinlockProtected<size_t, LockRank::None>& attach_count() { return m_attach_count; }
|
SpinlockProtected<size_t, LockRank::None>& attach_count() { return m_attach_count; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Jail(NonnullOwnPtr<KString>, JailIndex, NonnullRefPtr<ProcessList>);
|
Jail(NonnullOwnPtr<KString>, JailIndex, RefPtr<ProcessList>);
|
||||||
|
|
||||||
NonnullOwnPtr<KString> m_name;
|
NonnullOwnPtr<KString> m_name;
|
||||||
JailIndex const m_index;
|
JailIndex const m_index;
|
||||||
|
@ -52,7 +52,7 @@ public:
|
||||||
using List = IntrusiveListRelaxedConst<&Jail::m_list_node>;
|
using List = IntrusiveListRelaxedConst<&Jail::m_list_node>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NonnullRefPtr<ProcessList> const m_process_list;
|
RefPtr<ProcessList> const m_process_list;
|
||||||
|
|
||||||
SpinlockProtected<size_t, LockRank::None> m_attach_count { 0 };
|
SpinlockProtected<size_t, LockRank::None> m_attach_count { 0 };
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Userspace.h>
|
#include <AK/Userspace.h>
|
||||||
#include <Kernel/API/Ioctl.h>
|
#include <Kernel/API/Jail.h>
|
||||||
#include <Kernel/Jail.h>
|
#include <Kernel/Jail.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
#include <Kernel/StdLib.h>
|
#include <Kernel/StdLib.h>
|
||||||
|
@ -30,7 +30,7 @@ ErrorOr<FlatPtr> Process::sys$jail_create(Userspace<Syscall::SC_jail_create_para
|
||||||
// any info leak about the "outside world" jail metadata.
|
// any info leak about the "outside world" jail metadata.
|
||||||
if (my_jail)
|
if (my_jail)
|
||||||
return Error::from_errno(EPERM);
|
return Error::from_errno(EPERM);
|
||||||
auto jail = TRY(Jail::create(move(jail_name)));
|
auto jail = TRY(Jail::create(move(jail_name), static_cast<unsigned>(params.flags)));
|
||||||
return jail->index().value();
|
return jail->index().value();
|
||||||
}));
|
}));
|
||||||
// Note: We do the copy_to_user outside of the m_attached_jail Spinlock locked scope because
|
// Note: We do the copy_to_user outside of the m_attached_jail Spinlock locked scope because
|
||||||
|
|
|
@ -1172,9 +1172,9 @@ ErrorOr<void> join_jail(u64 jail_index)
|
||||||
HANDLE_SYSCALL_RETURN_VALUE("jail_attach", rc, {});
|
HANDLE_SYSCALL_RETURN_VALUE("jail_attach", rc, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<u64> create_jail(StringView jail_name)
|
ErrorOr<u64> 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<int>(flags) };
|
||||||
int rc = syscall(SC_jail_create, ¶ms);
|
int rc = syscall(SC_jail_create, ¶ms);
|
||||||
HANDLE_SYSCALL_RETURN_VALUE("jail_create", rc, static_cast<u64>(params.index));
|
HANDLE_SYSCALL_RETURN_VALUE("jail_create", rc, static_cast<u64>(params.index));
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,10 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
|
|
||||||
|
#ifdef AK_OS_SERENITY
|
||||||
|
# include <Kernel/API/Jail.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID)
|
#if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID)
|
||||||
# include <shadow.h>
|
# include <shadow.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -191,7 +195,7 @@ ErrorOr<void> exec(StringView filename, ReadonlySpan<StringView> arguments, Sear
|
||||||
|
|
||||||
#ifdef AK_OS_SERENITY
|
#ifdef AK_OS_SERENITY
|
||||||
ErrorOr<void> join_jail(u64 jail_index);
|
ErrorOr<void> join_jail(u64 jail_index);
|
||||||
ErrorOr<u64> create_jail(StringView jail_name);
|
ErrorOr<u64> create_jail(StringView jail_name, JailIsolationFlags);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ErrorOr<int> socket(int domain, int type, int protocol);
|
ErrorOr<int> socket(int domain, int type, int protocol);
|
||||||
|
|
|
@ -31,7 +31,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
if (existing_jail_index.has_value()) {
|
if (existing_jail_index.has_value()) {
|
||||||
TRY(Core::System::join_jail(existing_jail_index.value()));
|
TRY(Core::System::join_jail(existing_jail_index.value()));
|
||||||
} else {
|
} 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::join_jail(new_jail_index));
|
||||||
}
|
}
|
||||||
TRY(Core::System::exec_command(command, preserve_env));
|
TRY(Core::System::exec_command(command, preserve_env));
|
||||||
|
|
|
@ -13,15 +13,19 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
{
|
{
|
||||||
StringView new_jail_name;
|
StringView new_jail_name;
|
||||||
Core::ArgsParser args_parser;
|
Core::ArgsParser args_parser;
|
||||||
|
bool pid_isolation = false;
|
||||||
args_parser.add_positional_argument(new_jail_name, "New jail name", "jail name");
|
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);
|
args_parser.parse(arguments);
|
||||||
|
|
||||||
TRY(Core::System::pledge("stdio jail"));
|
TRY(Core::System::pledge("stdio jail"));
|
||||||
|
|
||||||
if (!new_jail_name.is_null() && !new_jail_name.is_empty()) {
|
if (new_jail_name.is_null() || new_jail_name.is_empty())
|
||||||
TRY(Core::System::create_jail(new_jail_name));
|
return Error::from_string_view("Can't create a jail with empty name."sv);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue