diff --git a/Libraries/LibSandbox/Seccomp.cpp b/Libraries/LibSandbox/Seccomp.cpp index ed3f7c68da..562bad4d5a 100644 --- a/Libraries/LibSandbox/Seccomp.cpp +++ b/Libraries/LibSandbox/Seccomp.cpp @@ -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); diff --git a/Libraries/LibSandbox/Seccomp.h b/Libraries/LibSandbox/Seccomp.h index d37b5136ec..7574e97e47 100644 --- a/Libraries/LibSandbox/Seccomp.h +++ b/Libraries/LibSandbox/Seccomp.h @@ -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(); diff --git a/Libraries/LibWebView/HelperProcess.cpp b/Libraries/LibWebView/HelperProcess.cpp index 9c14488b01..fd724a04d5 100644 --- a/Libraries/LibWebView/HelperProcess.cpp +++ b/Libraries/LibWebView/HelperProcess.cpp @@ -161,9 +161,12 @@ ErrorOr> launch_image_decoder_process( ErrorOr> launch_compositor_process() { + auto const& browser_options = WebView::Application::browser_options(); auto const& web_content_options = WebView::Application::web_content_options(); Vector 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) diff --git a/Services/Compositor/CMakeLists.txt b/Services/Compositor/CMakeLists.txt index 39808fe130..e6dee92202 100644 --- a/Services/Compositor/CMakeLists.txt +++ b/Services/Compositor/CMakeLists.txt @@ -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) diff --git a/Services/Compositor/Sandbox.h b/Services/Compositor/Sandbox.h new file mode 100644 index 0000000000..2aba3323da --- /dev/null +++ b/Services/Compositor/Sandbox.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2026-present, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Compositor { + +[[nodiscard]] ErrorOr apply_sandbox(); + +} diff --git a/Services/Compositor/SandboxLinux.cpp b/Services/Compositor/SandboxLinux.cpp new file mode 100644 index 0000000000..486b28ba6f --- /dev/null +++ b/Services/Compositor/SandboxLinux.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026-present, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Compositor { + +ErrorOr 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 {}; +} + +} diff --git a/Services/Compositor/SandboxUnimplemented.cpp b/Services/Compositor/SandboxUnimplemented.cpp new file mode 100644 index 0000000000..9f212bcefd --- /dev/null +++ b/Services/Compositor/SandboxUnimplemented.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2026-present, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace Compositor { + +ErrorOr apply_sandbox() +{ + return {}; +} + +} diff --git a/Services/Compositor/main.cpp b/Services/Compositor/main.cpp index 90bacbf20b..d7f9ed8773 100644 --- a/Services/Compositor/main.cpp +++ b/Services/Compositor/main.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -24,6 +25,7 @@ ErrorOr 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 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 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( mach_server_name, move(skia_backend_context), !disable_async_scrolling));