Compositor: Sandbox the process on Linux
Add opt-in Linux sandbox support to Compositor. Ladybird and test-web pass --enable-sandbox through when requested, and Compositor only installs the sandbox when that flag is present. Install the sandbox after Compositor has initialized platform, font, and GPU state so startup probing can complete before filesystem access is removed. Compose the runtime seccomp policy from LibSandbox building blocks and add an explicit GPU device operations group for driver IPC through already-open descriptors.
This commit is contained in:
parent
ba87a32626
commit
a69fd61eaf
8 changed files with 113 additions and 1 deletions
|
|
@ -72,6 +72,11 @@ static constexpr unsigned read_only_open_flags = O_CLOEXEC;
|
|||
#define IF_DEFINED_close(if_defined, if_not_defined) if_defined
|
||||
#define IF_DEFINED_dup(if_defined, if_not_defined) if_defined
|
||||
#define IF_DEFINED_dup3(if_defined, if_not_defined) if_defined
|
||||
#define IF_DEFINED_epoll_create1(if_defined, if_not_defined) if_defined
|
||||
#define IF_DEFINED_epoll_ctl(if_defined, if_not_defined) if_defined
|
||||
#define IF_DEFINED_epoll_pwait(if_defined, if_not_defined) if_defined
|
||||
#define IF_DEFINED_epoll_wait(if_defined, if_not_defined) if_defined
|
||||
#define IF_DEFINED_eventfd2(if_defined, if_not_defined) if_defined
|
||||
#define IF_DEFINED_exit(if_defined, if_not_defined) if_defined
|
||||
#define IF_DEFINED_exit_group(if_defined, if_not_defined) if_defined
|
||||
#define IF_DEFINED_fcntl(if_defined, if_not_defined) if_defined
|
||||
|
|
@ -161,6 +166,26 @@ static constexpr unsigned read_only_open_flags = O_CLOEXEC;
|
|||
# undef IF_DEFINED_dup3
|
||||
# define IF_DEFINED_dup3(if_defined, if_not_defined) if_not_defined
|
||||
#endif
|
||||
#ifndef __NR_epoll_create1
|
||||
# undef IF_DEFINED_epoll_create1
|
||||
# define IF_DEFINED_epoll_create1(if_defined, if_not_defined) if_not_defined
|
||||
#endif
|
||||
#ifndef __NR_epoll_ctl
|
||||
# undef IF_DEFINED_epoll_ctl
|
||||
# define IF_DEFINED_epoll_ctl(if_defined, if_not_defined) if_not_defined
|
||||
#endif
|
||||
#ifndef __NR_epoll_pwait
|
||||
# undef IF_DEFINED_epoll_pwait
|
||||
# define IF_DEFINED_epoll_pwait(if_defined, if_not_defined) if_not_defined
|
||||
#endif
|
||||
#ifndef __NR_epoll_wait
|
||||
# undef IF_DEFINED_epoll_wait
|
||||
# define IF_DEFINED_epoll_wait(if_defined, if_not_defined) if_not_defined
|
||||
#endif
|
||||
#ifndef __NR_eventfd2
|
||||
# undef IF_DEFINED_eventfd2
|
||||
# define IF_DEFINED_eventfd2(if_defined, if_not_defined) if_not_defined
|
||||
#endif
|
||||
#ifndef __NR_fcntl64
|
||||
# undef IF_DEFINED_fcntl64
|
||||
# define IF_DEFINED_fcntl64(if_defined, if_not_defined) if_not_defined
|
||||
|
|
@ -681,6 +706,16 @@ void SeccompPolicy::allow_clocks()
|
|||
SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, restart_syscall);
|
||||
}
|
||||
|
||||
void SeccompPolicy::allow_gpu_device_operations()
|
||||
{
|
||||
SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, ioctl);
|
||||
SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, eventfd2);
|
||||
SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, epoll_create1);
|
||||
SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, epoll_ctl);
|
||||
SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, epoll_wait);
|
||||
SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, epoll_pwait);
|
||||
}
|
||||
|
||||
void SeccompPolicy::allow_process_metadata()
|
||||
{
|
||||
SECCOMP_APPEND_ALLOW_SYSCALL_IF_DEFINED(*this, getpid);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ public:
|
|||
void allow_threads();
|
||||
void allow_signals();
|
||||
void allow_clocks();
|
||||
void allow_gpu_device_operations();
|
||||
void allow_process_metadata();
|
||||
void allow_common_runtime();
|
||||
void allow_prctl();
|
||||
|
|
|
|||
|
|
@ -161,9 +161,12 @@ ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process(
|
|||
|
||||
ErrorOr<NonnullRefPtr<WebView::CompositorClient>> launch_compositor_process()
|
||||
{
|
||||
auto const& browser_options = WebView::Application::browser_options();
|
||||
auto const& web_content_options = WebView::Application::web_content_options();
|
||||
|
||||
Vector<ByteString> arguments;
|
||||
if (browser_options.enable_sandbox == EnableSandbox::Yes)
|
||||
arguments.append("--enable-sandbox"sv);
|
||||
if (web_content_options.force_cpu_painting == WebView::ForceCPUPainting::Yes)
|
||||
arguments.append("--force-cpu-painting"sv);
|
||||
if (web_content_options.force_fontconfig == WebView::ForceFontconfig::Yes)
|
||||
|
|
|
|||
|
|
@ -20,10 +20,16 @@ ladybird_generated_sources(compositorservice)
|
|||
|
||||
add_executable(Compositor main.cpp)
|
||||
|
||||
if (LINUX)
|
||||
target_sources(Compositor PRIVATE SandboxLinux.cpp)
|
||||
else()
|
||||
target_sources(Compositor PRIVATE SandboxUnimplemented.cpp)
|
||||
endif()
|
||||
|
||||
target_include_directories(compositorservice PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../..)
|
||||
target_include_directories(compositorservice PRIVATE ${LADYBIRD_SOURCE_DIR}/Services/)
|
||||
|
||||
target_link_libraries(Compositor PRIVATE compositorservice LibCore LibMain LibWebView)
|
||||
target_link_libraries(Compositor PRIVATE compositorservice LibCore LibMain LibSandbox LibWebView)
|
||||
target_link_libraries(compositorservice PRIVATE LibCore LibGfx LibIPC LibMedia LibSync LibWeb)
|
||||
|
||||
if (APPLE)
|
||||
|
|
|
|||
15
Services/Compositor/Sandbox.h
Normal file
15
Services/Compositor/Sandbox.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2026-present, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Error.h>
|
||||
|
||||
namespace Compositor {
|
||||
|
||||
[[nodiscard]] ErrorOr<void> apply_sandbox();
|
||||
|
||||
}
|
||||
30
Services/Compositor/SandboxLinux.cpp
Normal file
30
Services/Compositor/SandboxLinux.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2026-present, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Compositor/Sandbox.h>
|
||||
#include <LibSandbox/Sandbox.h>
|
||||
#include <LibSandbox/Seccomp.h>
|
||||
|
||||
namespace Compositor {
|
||||
|
||||
ErrorOr<void> apply_sandbox()
|
||||
{
|
||||
TRY(Sandbox::install_no_new_privileges());
|
||||
TRY(Sandbox::configure_runtime());
|
||||
TRY(Sandbox::restrict_filesystem_with_landlock());
|
||||
|
||||
Sandbox::SeccompPolicy policy;
|
||||
policy.deny_readonly_filesystem_probes();
|
||||
policy.allow_file_descriptor_operations();
|
||||
policy.allow_ipc();
|
||||
policy.allow_gpu_device_operations();
|
||||
policy.allow_common_runtime();
|
||||
TRY(policy.install());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
16
Services/Compositor/SandboxUnimplemented.cpp
Normal file
16
Services/Compositor/SandboxUnimplemented.cpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2026-present, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Compositor/Sandbox.h>
|
||||
|
||||
namespace Compositor {
|
||||
|
||||
ErrorOr<void> apply_sandbox()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <Compositor/ConnectionFromClient.h>
|
||||
#include <Compositor/Sandbox.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/Process.h>
|
||||
|
|
@ -24,6 +25,7 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
|
|||
bool force_cpu_painting = false;
|
||||
bool force_fontconfig = false;
|
||||
bool disable_async_scrolling = false;
|
||||
bool enable_sandbox = false;
|
||||
|
||||
Core::ArgsParser args_parser;
|
||||
args_parser.add_option(mach_server_name, "Mach server name", "mach-server-name", 0, "mach_server_name");
|
||||
|
|
@ -31,6 +33,7 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
|
|||
args_parser.add_option(force_cpu_painting, "Force CPU painting", "force-cpu-painting");
|
||||
args_parser.add_option(force_fontconfig, "Force using fontconfig for font loading", "force-fontconfig");
|
||||
args_parser.add_option(disable_async_scrolling, "Disable async scrolling", "disable-async-scrolling");
|
||||
args_parser.add_option(enable_sandbox, "Enable process sandboxing", "enable-sandbox");
|
||||
args_parser.parse(arguments);
|
||||
|
||||
if (wait_for_debugger)
|
||||
|
|
@ -45,6 +48,9 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
|
|||
Gfx::SkiaBackendContext::initialize_gpu_backend();
|
||||
auto skia_backend_context = Gfx::SkiaBackendContext::the_main_thread_context();
|
||||
|
||||
if (enable_sandbox)
|
||||
TRY(Compositor::apply_sandbox());
|
||||
|
||||
auto& event_loop = Core::EventLoop::initialize_for_current_thread();
|
||||
auto client = TRY(IPC::take_over_accepted_client_from_system_server<Compositor::ConnectionFromClient>(
|
||||
mach_server_name, move(skia_backend_context), !disable_async_scrolling));
|
||||
|
|
|
|||
Loading…
Reference in a new issue