LibSandbox: Add macOS service sandboxing
Add Seatbelt-based macOS sandboxing for the browser service processes. The shared profile builder grants only the filesystem, network, Mach, and process execution permissions each service needs, with fatal sandbox violation reporting enabled so denials are visible during development. Wire sandbox profiles into WebContent, WebWorker, RequestServer, ImageDecoder, and Compositor. Keep Landlock and Seatbelt APIs visible only on the platforms that use them. Allow RequestServer resource substitution files explicitly, preserve read access for read-write cache paths, and only grant renderer process execution for an existing Cranelift helper.
This commit is contained in:
parent
fc02ab95fe
commit
ddbc3e2006
13 changed files with 635 additions and 19 deletions
|
|
@ -19,6 +19,22 @@
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(AK_OS_MACOS)
|
||||||
|
# include <AK/LexicalPath.h>
|
||||||
|
# include <AK/StringBuilder.h>
|
||||||
|
# include <errno.h>
|
||||||
|
# include <limits.h>
|
||||||
|
# include <sandbox.h>
|
||||||
|
# include <signal.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <sys/stat.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
int sandbox_init_with_parameters(char const* profile, u64 flags, char const* const parameters[], char** errorbuf);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__GLIBC__)
|
#if defined(__GLIBC__)
|
||||||
# include <malloc.h>
|
# include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -43,9 +59,9 @@ ErrorOr<void> configure_runtime()
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(AK_OS_LINUX)
|
||||||
ErrorOr<void> add_landlock_path_if_exists(Vector<LandlockPath>& paths, StringView path, LandlockPath::Access access)
|
ErrorOr<void> add_landlock_path_if_exists(Vector<LandlockPath>& paths, StringView path, LandlockPath::Access access)
|
||||||
{
|
{
|
||||||
#if defined(AK_OS_LINUX)
|
|
||||||
auto path_bytes = path.to_byte_string();
|
auto path_bytes = path.to_byte_string();
|
||||||
|
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
@ -64,17 +80,342 @@ ErrorOr<void> add_landlock_path_if_exists(Vector<LandlockPath>& paths, StringVie
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(paths.try_append({ move(path_bytes), access }));
|
TRY(paths.try_append({ move(path_bytes), access }));
|
||||||
#else
|
return {};
|
||||||
(void)paths;
|
}
|
||||||
(void)path;
|
|
||||||
(void)access;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(AK_OS_MACOS)
|
||||||
|
ErrorOr<void> add_seatbelt_path_if_exists(Vector<SeatbeltPath>& paths, StringView path, SeatbeltPath::Access access)
|
||||||
|
{
|
||||||
|
auto path_bytes = path.to_byte_string();
|
||||||
|
|
||||||
|
struct stat statbuf;
|
||||||
|
if (stat(path_bytes.characters(), &statbuf) < 0) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return {};
|
||||||
|
return Error::from_syscall("stat"sv, errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
char resolved_path[PATH_MAX];
|
||||||
|
if (realpath(path_bytes.characters(), resolved_path) == nullptr)
|
||||||
|
return Error::from_syscall("realpath"sv, errno);
|
||||||
|
path_bytes = resolved_path;
|
||||||
|
|
||||||
|
auto is_directory = S_ISDIR(statbuf.st_mode);
|
||||||
|
|
||||||
|
for (auto const& existing_path : paths) {
|
||||||
|
if (existing_path.access == access && existing_path.path == path_bytes)
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY(paths.try_append({ move(path_bytes), access, is_directory }));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void append_sandbox_string_literal(StringBuilder& builder, StringView string)
|
||||||
|
{
|
||||||
|
builder.append('"');
|
||||||
|
for (auto ch : string.bytes()) {
|
||||||
|
if (ch == '"' || ch == '\\')
|
||||||
|
builder.append('\\');
|
||||||
|
builder.append(static_cast<char>(ch));
|
||||||
|
}
|
||||||
|
builder.append('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_sandbox_path_filter(StringBuilder& builder, SeatbeltPath const& path)
|
||||||
|
{
|
||||||
|
builder.append(path.is_directory ? "(subpath "sv : "(literal "sv);
|
||||||
|
append_sandbox_string_literal(builder, path.path);
|
||||||
|
builder.append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool seatbelt_path_allows_access(SeatbeltPath::Access path_access, SeatbeltPath::Access requested_access)
|
||||||
|
{
|
||||||
|
if (requested_access == SeatbeltPath::Access::ReadOnly)
|
||||||
|
return true;
|
||||||
|
return path_access == requested_access;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ErrorOr<void> append_allowed_paths(StringBuilder& builder, StringView operation, ReadonlySpan<SeatbeltPath> paths, SeatbeltPath::Access access)
|
||||||
|
{
|
||||||
|
bool emitted_header = false;
|
||||||
|
for (auto const& path : paths) {
|
||||||
|
if (!seatbelt_path_allows_access(path.access, access))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!emitted_header) {
|
||||||
|
builder.append("(allow "sv);
|
||||||
|
builder.append(operation);
|
||||||
|
emitted_header = true;
|
||||||
|
}
|
||||||
|
builder.append(' ');
|
||||||
|
append_sandbox_path_filter(builder, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emitted_header)
|
||||||
|
builder.append(")\n"sv);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static ErrorOr<void> append_allowed_path_extensions(StringBuilder& builder, ReadonlySpan<SeatbeltPath> paths, SeatbeltPath::Access access)
|
||||||
|
{
|
||||||
|
auto extension_class = access == SeatbeltPath::Access::ReadWrite ? "com.apple.app-sandbox.read-write"sv : "com.apple.app-sandbox.read"sv;
|
||||||
|
|
||||||
|
bool emitted_header = false;
|
||||||
|
for (auto const& path : paths) {
|
||||||
|
if (!seatbelt_path_allows_access(path.access, access))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!emitted_header) {
|
||||||
|
builder.append("(allow file-issue-extension"sv);
|
||||||
|
emitted_header = true;
|
||||||
|
}
|
||||||
|
builder.append(" (require-all (extension-class "sv);
|
||||||
|
append_sandbox_string_literal(builder, extension_class);
|
||||||
|
builder.append(") "sv);
|
||||||
|
append_sandbox_path_filter(builder, path);
|
||||||
|
builder.append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emitted_header)
|
||||||
|
builder.append(")\n"sv);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static ErrorOr<void> append_allowed_executables(StringBuilder& builder, ReadonlySpan<ByteString> executable_paths)
|
||||||
|
{
|
||||||
|
if (executable_paths.is_empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
builder.append("(allow process-exec"sv);
|
||||||
|
for (auto const& path : executable_paths) {
|
||||||
|
builder.append(" (literal "sv);
|
||||||
|
append_sandbox_string_literal(builder, path);
|
||||||
|
builder.append(')');
|
||||||
|
}
|
||||||
|
builder.append(")\n"sv);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sandbox_violation_signal_handler(int)
|
||||||
|
{
|
||||||
|
char const message[] = "Sandbox violation: terminating process\n";
|
||||||
|
[[maybe_unused]] auto nwritten = write(STDERR_FILENO, message, sizeof(message) - 1);
|
||||||
|
_exit(128 + SIGSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ErrorOr<void> install_sandbox_violation_signal_handler()
|
||||||
|
{
|
||||||
|
struct sigaction action {};
|
||||||
|
action.sa_handler = sandbox_violation_signal_handler;
|
||||||
|
sigemptyset(&action.sa_mask);
|
||||||
|
action.sa_flags = SA_RESETHAND;
|
||||||
|
if (sigaction(SIGSYS, &action, nullptr) < 0)
|
||||||
|
return Error::from_syscall("sigaction(SIGSYS)"sv, errno);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> apply_macos_sandbox(ReadonlySpan<SeatbeltPath> paths, NetworkAccess network_access, ReadonlySpan<ByteString> executable_paths)
|
||||||
|
{
|
||||||
|
TRY(install_sandbox_violation_signal_handler());
|
||||||
|
|
||||||
|
StringBuilder profile;
|
||||||
|
TRY(profile.try_append(R"~~~(
|
||||||
|
(version 1)
|
||||||
|
(deny default
|
||||||
|
(with send-signal SIGSYS)
|
||||||
|
(with message "Ladybird macOS sandbox default deny"))
|
||||||
|
|
||||||
|
(allow process-info*)
|
||||||
|
(allow signal (target self))
|
||||||
|
(allow sysctl-read)
|
||||||
|
(allow system*)
|
||||||
|
(allow ipc*)
|
||||||
|
(allow mach*)
|
||||||
|
(allow iokit-open-user-client
|
||||||
|
(iokit-user-client-class "IOSurfaceRootUserClient"))
|
||||||
|
(allow user-preference-read
|
||||||
|
(preference-domain "kCFPreferencesAnyApplication")
|
||||||
|
(preference-domain "org.ladybird.ladybird"))
|
||||||
|
|
||||||
|
(allow network-outbound
|
||||||
|
(literal "/private/var/run/syslog"))
|
||||||
|
|
||||||
|
(deny syscall-unix
|
||||||
|
(with send-signal SIGKILL)
|
||||||
|
(with message "Ladybird macOS sandbox syscall deny"))
|
||||||
|
|
||||||
|
(allow syscall-unix
|
||||||
|
(syscall-group-bsdthread)
|
||||||
|
(syscall-group-close)
|
||||||
|
(syscall-group-fcntl)
|
||||||
|
(syscall-group-getfsstat)
|
||||||
|
(syscall-group-kevent)
|
||||||
|
(syscall-group-kqueue)
|
||||||
|
(syscall-group-mkdir)
|
||||||
|
(syscall-group-open)
|
||||||
|
(syscall-group-open-dprotected)
|
||||||
|
(syscall-group-pthread)
|
||||||
|
(syscall-group-pthread-cv)
|
||||||
|
(syscall-group-pthread-locks)
|
||||||
|
(syscall-group-read)
|
||||||
|
(syscall-group-recv)
|
||||||
|
(syscall-group-rlimit)
|
||||||
|
(syscall-group-select)
|
||||||
|
(syscall-group-send)
|
||||||
|
(syscall-group-signal)
|
||||||
|
(syscall-group-sockopt)
|
||||||
|
(syscall-group-stat)
|
||||||
|
(syscall-group-statfs)
|
||||||
|
(syscall-group-ulock)
|
||||||
|
(syscall-group-write)
|
||||||
|
(syscall-number
|
||||||
|
SYS___disable_threadsignal
|
||||||
|
SYS___channel_open
|
||||||
|
SYS___mac_syscall
|
||||||
|
SYS___semwait_signal
|
||||||
|
SYS___semwait_signal_nocancel
|
||||||
|
SYS_abort_with_payload
|
||||||
|
SYS_access
|
||||||
|
SYS_change_fdguard_np
|
||||||
|
SYS_connect
|
||||||
|
SYS_crossarch_trap
|
||||||
|
SYS_csops_audittoken
|
||||||
|
SYS_csrctl
|
||||||
|
SYS_dup
|
||||||
|
SYS_exit
|
||||||
|
SYS_faccessat
|
||||||
|
SYS_fileport_makefd
|
||||||
|
SYS_fileport_makeport
|
||||||
|
SYS_fgetattrlist
|
||||||
|
SYS_fgetxattr
|
||||||
|
SYS_flock
|
||||||
|
SYS_fsgetpath
|
||||||
|
SYS_fsync
|
||||||
|
SYS_ftruncate
|
||||||
|
SYS_getaudit_addr
|
||||||
|
SYS_getattrlist
|
||||||
|
SYS_getattrlistbulk
|
||||||
|
SYS_getdirentries64
|
||||||
|
SYS_getentropy
|
||||||
|
SYS_getegid
|
||||||
|
SYS_geteuid
|
||||||
|
SYS_getgid
|
||||||
|
SYS_gethostuuid
|
||||||
|
SYS_getpeername
|
||||||
|
SYS_getpid
|
||||||
|
SYS_getrusage
|
||||||
|
SYS_getsockname
|
||||||
|
SYS_gettid
|
||||||
|
SYS_gettimeofday
|
||||||
|
SYS_getuid
|
||||||
|
SYS_getxattr
|
||||||
|
SYS_ioctl
|
||||||
|
SYS_issetugid
|
||||||
|
SYS_kdebug_trace
|
||||||
|
SYS_kdebug_trace64
|
||||||
|
SYS_kdebug_trace_string
|
||||||
|
SYS_kdebug_typefilter
|
||||||
|
SYS_listxattr
|
||||||
|
SYS_lseek
|
||||||
|
SYS_madvise
|
||||||
|
SYS_mlock
|
||||||
|
SYS_mmap
|
||||||
|
SYS_mprotect
|
||||||
|
SYS_mremap_encrypted
|
||||||
|
SYS_msync
|
||||||
|
SYS_munlock
|
||||||
|
SYS_munmap
|
||||||
|
SYS_necp_client_action
|
||||||
|
SYS_necp_open
|
||||||
|
SYS_open
|
||||||
|
SYS_open_nocancel
|
||||||
|
SYS_openat
|
||||||
|
SYS_os_fault_with_payload
|
||||||
|
SYS_pathconf
|
||||||
|
SYS_pipe
|
||||||
|
SYS_poll
|
||||||
|
SYS_posix_spawn
|
||||||
|
SYS_proc_info
|
||||||
|
SYS_readlink
|
||||||
|
SYS_rename
|
||||||
|
SYS_rmdir
|
||||||
|
SYS_sendfile
|
||||||
|
SYS_shm_open
|
||||||
|
SYS_shared_region_check_np
|
||||||
|
SYS_shared_region_map_and_slide_2_np
|
||||||
|
SYS_socket
|
||||||
|
SYS_socketpair
|
||||||
|
SYS_sysctl
|
||||||
|
SYS_sysctlbyname
|
||||||
|
SYS_thread_selfid
|
||||||
|
SYS_umask
|
||||||
|
SYS_wait4
|
||||||
|
SYS_work_interval_ctl
|
||||||
|
SYS_workq_kernreturn
|
||||||
|
SYS_workq_open))
|
||||||
|
|
||||||
|
(allow file-read-metadata)
|
||||||
|
(allow file-read*
|
||||||
|
(literal "/")
|
||||||
|
(literal "/dev/dtracehelper")
|
||||||
|
(literal "/dev/null")
|
||||||
|
(literal "/dev/random")
|
||||||
|
(literal "/dev/urandom")
|
||||||
|
(literal "/private/etc/localtime")
|
||||||
|
(subpath "/private/etc/ssl")
|
||||||
|
(subpath "/System")
|
||||||
|
(subpath "/Library/Preferences/Logging")
|
||||||
|
(subpath "/private/var/db/timezone")
|
||||||
|
(subpath "/usr/lib")
|
||||||
|
(subpath "/usr/share"))
|
||||||
|
|
||||||
|
(allow file-map-executable
|
||||||
|
(subpath "/System")
|
||||||
|
(subpath "/usr/lib"))
|
||||||
|
|
||||||
|
(allow file-write-data file-ioctl
|
||||||
|
(literal "/dev/dtracehelper"))
|
||||||
|
)~~~"sv));
|
||||||
|
|
||||||
|
if (network_access == NetworkAccess::Allowed)
|
||||||
|
TRY(profile.try_append("(allow network*)\n"sv));
|
||||||
|
|
||||||
|
TRY(append_allowed_paths(profile, "file-read*"sv, paths, SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(append_allowed_paths(profile, "file-map-executable"sv, paths, SeatbeltPath::Access::ReadAndExecute));
|
||||||
|
TRY(append_allowed_paths(profile, "file-write*"sv, paths, SeatbeltPath::Access::ReadWrite));
|
||||||
|
TRY(append_allowed_path_extensions(profile, paths, SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(append_allowed_path_extensions(profile, paths, SeatbeltPath::Access::ReadWrite));
|
||||||
|
TRY(append_allowed_executables(profile, executable_paths));
|
||||||
|
|
||||||
|
auto profile_string = profile.to_byte_string();
|
||||||
|
|
||||||
|
char* errorbuf = nullptr;
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
auto result = sandbox_init_with_parameters(profile_string.characters(), 0, nullptr, &errorbuf);
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
if (result < 0) {
|
||||||
|
if (errorbuf) {
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
sandbox_free_error(errorbuf);
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
}
|
||||||
|
return Error::from_string_literal("sandbox_init_with_parameters failed");
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AK_OS_LINUX)
|
||||||
ErrorOr<void> restrict_filesystem_with_landlock(ReadonlySpan<LandlockPath> paths)
|
ErrorOr<void> restrict_filesystem_with_landlock(ReadonlySpan<LandlockPath> paths)
|
||||||
{
|
{
|
||||||
#if defined(AK_OS_LINUX) && defined(__NR_landlock_create_ruleset) && defined(__NR_landlock_add_rule) && defined(__NR_landlock_restrict_self)
|
# if defined(__NR_landlock_create_ruleset) && defined(__NR_landlock_add_rule) && defined(__NR_landlock_restrict_self)
|
||||||
auto landlock_abi = syscall(__NR_landlock_create_ruleset, nullptr, 0, LANDLOCK_CREATE_RULESET_VERSION);
|
auto landlock_abi = syscall(__NR_landlock_create_ruleset, nullptr, 0, LANDLOCK_CREATE_RULESET_VERSION);
|
||||||
if (landlock_abi < 0) {
|
if (landlock_abi < 0) {
|
||||||
if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
|
if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
|
||||||
|
|
@ -99,19 +440,19 @@ ErrorOr<void> restrict_filesystem_with_landlock(ReadonlySpan<LandlockPath> paths
|
||||||
| LANDLOCK_ACCESS_FS_MAKE_BLOCK
|
| LANDLOCK_ACCESS_FS_MAKE_BLOCK
|
||||||
| LANDLOCK_ACCESS_FS_MAKE_SYM;
|
| LANDLOCK_ACCESS_FS_MAKE_SYM;
|
||||||
|
|
||||||
# ifdef LANDLOCK_ACCESS_FS_REFER
|
# ifdef LANDLOCK_ACCESS_FS_REFER
|
||||||
if (landlock_abi >= 2)
|
if (landlock_abi >= 2)
|
||||||
ruleset_attributes.handled_access_fs |= LANDLOCK_ACCESS_FS_REFER;
|
ruleset_attributes.handled_access_fs |= LANDLOCK_ACCESS_FS_REFER;
|
||||||
# endif
|
# endif
|
||||||
# ifdef LANDLOCK_ACCESS_FS_TRUNCATE
|
# ifdef LANDLOCK_ACCESS_FS_TRUNCATE
|
||||||
if (landlock_abi >= 3)
|
if (landlock_abi >= 3)
|
||||||
ruleset_attributes.handled_access_fs |= LANDLOCK_ACCESS_FS_TRUNCATE;
|
ruleset_attributes.handled_access_fs |= LANDLOCK_ACCESS_FS_TRUNCATE;
|
||||||
# endif
|
# endif
|
||||||
# if defined(LANDLOCK_ACCESS_NET_BIND_TCP) && defined(LANDLOCK_ACCESS_NET_CONNECT_TCP)
|
# if defined(LANDLOCK_ACCESS_NET_BIND_TCP) && defined(LANDLOCK_ACCESS_NET_CONNECT_TCP)
|
||||||
auto ruleset_attributes_size = offsetof(landlock_ruleset_attr, handled_access_net);
|
auto ruleset_attributes_size = offsetof(landlock_ruleset_attr, handled_access_net);
|
||||||
# else
|
# else
|
||||||
auto ruleset_attributes_size = sizeof(ruleset_attributes);
|
auto ruleset_attributes_size = sizeof(ruleset_attributes);
|
||||||
# endif
|
# endif
|
||||||
auto ruleset_fd = syscall(__NR_landlock_create_ruleset, &ruleset_attributes, ruleset_attributes_size, 0);
|
auto ruleset_fd = syscall(__NR_landlock_create_ruleset, &ruleset_attributes, ruleset_attributes_size, 0);
|
||||||
if (ruleset_fd < 0)
|
if (ruleset_fd < 0)
|
||||||
return Error::from_syscall("landlock_create_ruleset"sv, errno);
|
return Error::from_syscall("landlock_create_ruleset"sv, errno);
|
||||||
|
|
@ -141,14 +482,14 @@ ErrorOr<void> restrict_filesystem_with_landlock(ReadonlySpan<LandlockPath> paths
|
||||||
| LANDLOCK_ACCESS_FS_MAKE_REG
|
| LANDLOCK_ACCESS_FS_MAKE_REG
|
||||||
| LANDLOCK_ACCESS_FS_MAKE_SOCK
|
| LANDLOCK_ACCESS_FS_MAKE_SOCK
|
||||||
| LANDLOCK_ACCESS_FS_MAKE_FIFO;
|
| LANDLOCK_ACCESS_FS_MAKE_FIFO;
|
||||||
# ifdef LANDLOCK_ACCESS_FS_REFER
|
# ifdef LANDLOCK_ACCESS_FS_REFER
|
||||||
if (landlock_abi >= 2)
|
if (landlock_abi >= 2)
|
||||||
path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_REFER;
|
path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_REFER;
|
||||||
# endif
|
# endif
|
||||||
# ifdef LANDLOCK_ACCESS_FS_TRUNCATE
|
# ifdef LANDLOCK_ACCESS_FS_TRUNCATE
|
||||||
if (landlock_abi >= 3)
|
if (landlock_abi >= 3)
|
||||||
path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_TRUNCATE;
|
path_beneath.allowed_access |= LANDLOCK_ACCESS_FS_TRUNCATE;
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
path_beneath.parent_fd = path_fd;
|
path_beneath.parent_fd = path_fd;
|
||||||
if (syscall(__NR_landlock_add_rule, ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0) < 0)
|
if (syscall(__NR_landlock_add_rule, ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0) < 0)
|
||||||
|
|
@ -157,9 +498,9 @@ ErrorOr<void> restrict_filesystem_with_landlock(ReadonlySpan<LandlockPath> paths
|
||||||
|
|
||||||
if (syscall(__NR_landlock_restrict_self, ruleset_fd, 0) < 0)
|
if (syscall(__NR_landlock_restrict_self, ruleset_fd, 0) < 0)
|
||||||
return Error::from_syscall("landlock_restrict_self"sv, errno);
|
return Error::from_syscall("landlock_restrict_self"sv, errno);
|
||||||
#else
|
# else
|
||||||
(void)paths;
|
(void)paths;
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
@ -171,5 +512,6 @@ ErrorOr<void> restrict_filesystem_with_landlock(ReadonlySpan<StringView> readabl
|
||||||
TRY(paths.try_append({ readable_path.to_byte_string(), LandlockPath::Access::ReadOnly }));
|
TRY(paths.try_append({ readable_path.to_byte_string(), LandlockPath::Access::ReadOnly }));
|
||||||
return restrict_filesystem_with_landlock(paths.span());
|
return restrict_filesystem_with_landlock(paths.span());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,14 @@
|
||||||
|
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
#include <AK/Error.h>
|
#include <AK/Error.h>
|
||||||
|
#include <AK/Platform.h>
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
#include <AK/StringView.h>
|
#include <AK/StringView.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
|
|
||||||
namespace Sandbox {
|
namespace Sandbox {
|
||||||
|
|
||||||
|
#if defined(AK_OS_LINUX)
|
||||||
struct LandlockPath {
|
struct LandlockPath {
|
||||||
enum class Access {
|
enum class Access {
|
||||||
ReadOnly,
|
ReadOnly,
|
||||||
|
|
@ -24,11 +26,39 @@ struct LandlockPath {
|
||||||
ByteString path;
|
ByteString path;
|
||||||
Access access { Access::ReadOnly };
|
Access access { Access::ReadOnly };
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AK_OS_MACOS)
|
||||||
|
struct SeatbeltPath {
|
||||||
|
enum class Access {
|
||||||
|
ReadOnly,
|
||||||
|
ReadAndExecute,
|
||||||
|
ReadWrite,
|
||||||
|
};
|
||||||
|
|
||||||
|
ByteString path;
|
||||||
|
Access access { Access::ReadOnly };
|
||||||
|
bool is_directory { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class NetworkAccess {
|
||||||
|
Denied,
|
||||||
|
Allowed,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
[[nodiscard]] ErrorOr<void> install_no_new_privileges();
|
[[nodiscard]] ErrorOr<void> install_no_new_privileges();
|
||||||
[[nodiscard]] ErrorOr<void> configure_runtime();
|
[[nodiscard]] ErrorOr<void> configure_runtime();
|
||||||
|
|
||||||
|
#if defined(AK_OS_LINUX)
|
||||||
[[nodiscard]] ErrorOr<void> add_landlock_path_if_exists(Vector<LandlockPath>& paths, StringView path, LandlockPath::Access);
|
[[nodiscard]] ErrorOr<void> add_landlock_path_if_exists(Vector<LandlockPath>& paths, StringView path, LandlockPath::Access);
|
||||||
[[nodiscard]] ErrorOr<void> restrict_filesystem_with_landlock(ReadonlySpan<LandlockPath>);
|
[[nodiscard]] ErrorOr<void> restrict_filesystem_with_landlock(ReadonlySpan<LandlockPath>);
|
||||||
[[nodiscard]] ErrorOr<void> restrict_filesystem_with_landlock(ReadonlySpan<StringView> readable_paths = {});
|
[[nodiscard]] ErrorOr<void> restrict_filesystem_with_landlock(ReadonlySpan<StringView> readable_paths = {});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(AK_OS_MACOS)
|
||||||
|
[[nodiscard]] ErrorOr<void> add_seatbelt_path_if_exists(Vector<SeatbeltPath>& paths, StringView path, SeatbeltPath::Access);
|
||||||
|
[[nodiscard]] ErrorOr<void> apply_macos_sandbox(ReadonlySpan<SeatbeltPath>, NetworkAccess, ReadonlySpan<ByteString> executable_paths = {});
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ add_executable(Compositor main.cpp)
|
||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
target_sources(Compositor PRIVATE SandboxLinux.cpp)
|
target_sources(Compositor PRIVATE SandboxLinux.cpp)
|
||||||
|
elseif (APPLE)
|
||||||
|
target_sources(Compositor PRIVATE SandboxMacOS.cpp)
|
||||||
else()
|
else()
|
||||||
target_sources(Compositor PRIVATE SandboxUnimplemented.cpp)
|
target_sources(Compositor PRIVATE SandboxUnimplemented.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
56
Services/Compositor/SandboxMacOS.cpp
Normal file
56
Services/Compositor/SandboxMacOS.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2026-present, the Ladybird developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/LexicalPath.h>
|
||||||
|
#include <Compositor/Sandbox.h>
|
||||||
|
#include <LibCore/Directory.h>
|
||||||
|
#include <LibCore/StandardPaths.h>
|
||||||
|
#include <LibCore/System.h>
|
||||||
|
#include <LibGfx/Font/FontDatabase.h>
|
||||||
|
#include <LibSandbox/Sandbox.h>
|
||||||
|
#include <LibWebView/Utilities.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace Compositor {
|
||||||
|
|
||||||
|
ErrorOr<void> apply_sandbox()
|
||||||
|
{
|
||||||
|
TRY(Sandbox::configure_runtime());
|
||||||
|
|
||||||
|
auto executable_path = TRY(Core::System::current_executable_path());
|
||||||
|
auto build_root = LexicalPath::dirname(LexicalPath::dirname(LexicalPath::dirname(LexicalPath::dirname(LexicalPath::dirname(executable_path)))));
|
||||||
|
|
||||||
|
Vector<Sandbox::SeatbeltPath> paths;
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, executable_path, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, LexicalPath::join(build_root, "bin"sv).string(), Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, LexicalPath::join(build_root, "lib"sv).string(), Sandbox::SeatbeltPath::Access::ReadAndExecute));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, LexicalPath::join(build_root, "vcpkg_installed"sv).string(), Sandbox::SeatbeltPath::Access::ReadAndExecute));
|
||||||
|
|
||||||
|
for (auto const& path : TRY(Gfx::FontDatabase::font_directories()))
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, path, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, TRY(String::formatted("{}/fonts", WebView::s_ladybird_resource_root)), Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
|
||||||
|
auto cache_path = Core::StandardPaths::cache_directory();
|
||||||
|
auto skia_cache_path = TRY(String::formatted("{}/Ladybird", cache_path));
|
||||||
|
TRY(Core::Directory::create(skia_cache_path.to_byte_string(), Core::Directory::CreateDirectories::Yes));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, skia_cache_path, Sandbox::SeatbeltPath::Access::ReadWrite));
|
||||||
|
|
||||||
|
char darwin_user_cache_directory[PATH_MAX];
|
||||||
|
if (confstr(_CS_DARWIN_USER_CACHE_DIR, darwin_user_cache_directory, sizeof(darwin_user_cache_directory)) > 0) {
|
||||||
|
StringView darwin_user_cache_directory_view { darwin_user_cache_directory, strlen(darwin_user_cache_directory) };
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, darwin_user_cache_directory_view, Sandbox::SeatbeltPath::Access::ReadWrite));
|
||||||
|
if (darwin_user_cache_directory_view.starts_with("/var/"sv)) {
|
||||||
|
auto private_darwin_user_cache_directory = TRY(String::formatted("/private{}", darwin_user_cache_directory));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, private_darwin_user_cache_directory, Sandbox::SeatbeltPath::Access::ReadWrite));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sandbox::apply_macos_sandbox(paths.span(), Sandbox::NetworkAccess::Denied);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -24,6 +24,8 @@ if (LINUX)
|
||||||
if (ENABLE_ADDRESS_SANITIZER)
|
if (ENABLE_ADDRESS_SANITIZER)
|
||||||
target_sources(ImageDecoder PRIVATE LeakSanitizer.cpp)
|
target_sources(ImageDecoder PRIVATE LeakSanitizer.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
elseif (APPLE)
|
||||||
|
target_sources(ImageDecoder PRIVATE SandboxMacOS.cpp)
|
||||||
else()
|
else()
|
||||||
target_sources(ImageDecoder PRIVATE SandboxUnimplemented.cpp)
|
target_sources(ImageDecoder PRIVATE SandboxUnimplemented.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
20
Services/ImageDecoder/SandboxMacOS.cpp
Normal file
20
Services/ImageDecoder/SandboxMacOS.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2026-present, the Ladybird developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ImageDecoder/Sandbox.h>
|
||||||
|
#include <LibSandbox/Sandbox.h>
|
||||||
|
|
||||||
|
namespace ImageDecoder {
|
||||||
|
|
||||||
|
ErrorOr<void> apply_sandbox()
|
||||||
|
{
|
||||||
|
TRY(Sandbox::configure_runtime());
|
||||||
|
|
||||||
|
Vector<Sandbox::SeatbeltPath> paths;
|
||||||
|
return Sandbox::apply_macos_sandbox(paths.span(), Sandbox::NetworkAccess::Denied);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
85
Services/RendererSandboxMacOS.cpp
Normal file
85
Services/RendererSandboxMacOS.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2026-present, the Ladybird developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/LexicalPath.h>
|
||||||
|
#include <LibCore/Directory.h>
|
||||||
|
#include <LibCore/Environment.h>
|
||||||
|
#include <LibCore/StandardPaths.h>
|
||||||
|
#include <LibCore/System.h>
|
||||||
|
#include <LibGfx/Font/FontDatabase.h>
|
||||||
|
#include <LibSandbox/Sandbox.h>
|
||||||
|
#include <LibWebView/Utilities.h>
|
||||||
|
#include <Services/RendererSandbox.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace RendererSandbox {
|
||||||
|
|
||||||
|
static ErrorOr<Optional<ByteString>> canonicalized_path_if_exists(StringView path)
|
||||||
|
{
|
||||||
|
auto path_bytes = path.to_byte_string();
|
||||||
|
|
||||||
|
char resolved_path[PATH_MAX];
|
||||||
|
if (realpath(path_bytes.characters(), resolved_path) == nullptr) {
|
||||||
|
if (errno == ENOENT || errno == ENOTDIR)
|
||||||
|
return OptionalNone {};
|
||||||
|
return Error::from_syscall("realpath"sv, errno);
|
||||||
|
}
|
||||||
|
return ByteString { resolved_path };
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> apply_sandbox(Optional<StringView> config_path)
|
||||||
|
{
|
||||||
|
TRY(Sandbox::configure_runtime());
|
||||||
|
|
||||||
|
auto executable_path = TRY(Core::System::current_executable_path());
|
||||||
|
auto build_root = LexicalPath::dirname(LexicalPath::dirname(LexicalPath::dirname(LexicalPath::dirname(LexicalPath::dirname(executable_path)))));
|
||||||
|
|
||||||
|
Vector<Sandbox::SeatbeltPath> paths;
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, WebView::s_ladybird_resource_root, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
if (config_path.has_value())
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, *config_path, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, executable_path, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, LexicalPath::join(build_root, "bin"sv).string(), Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, LexicalPath::join(build_root, "lib"sv).string(), Sandbox::SeatbeltPath::Access::ReadAndExecute));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, LexicalPath::join(build_root, "vcpkg_installed"sv).string(), Sandbox::SeatbeltPath::Access::ReadAndExecute));
|
||||||
|
|
||||||
|
for (auto const& path : TRY(Gfx::FontDatabase::font_directories()))
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, path, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
|
||||||
|
Vector<ByteString> executable_paths;
|
||||||
|
if (auto cranelift_compiler_path = Core::Environment::get("LADYBIRD_CRANELIFT_COMPILER"sv); cranelift_compiler_path.has_value()) {
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, *cranelift_compiler_path, Sandbox::SeatbeltPath::Access::ReadAndExecute));
|
||||||
|
if (auto canonicalized_cranelift_compiler_path = TRY(canonicalized_path_if_exists(*cranelift_compiler_path)); canonicalized_cranelift_compiler_path.has_value())
|
||||||
|
TRY(executable_paths.try_append(canonicalized_cranelift_compiler_path.release_value()));
|
||||||
|
} else {
|
||||||
|
auto default_cranelift_compiler_path = LexicalPath::join(build_root, "bin/cranelift-compiler"sv).string();
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, default_cranelift_compiler_path, Sandbox::SeatbeltPath::Access::ReadAndExecute));
|
||||||
|
if (auto canonicalized_cranelift_compiler_path = TRY(canonicalized_path_if_exists(default_cranelift_compiler_path)); canonicalized_cranelift_compiler_path.has_value())
|
||||||
|
TRY(executable_paths.try_append(canonicalized_cranelift_compiler_path.release_value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto skia_cache_path = TRY(String::formatted("{}/Ladybird", Core::StandardPaths::cache_directory()));
|
||||||
|
TRY(Core::Directory::create(skia_cache_path.to_byte_string(), Core::Directory::CreateDirectories::Yes));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, skia_cache_path, Sandbox::SeatbeltPath::Access::ReadWrite));
|
||||||
|
|
||||||
|
char darwin_user_cache_directory[PATH_MAX];
|
||||||
|
if (confstr(_CS_DARWIN_USER_CACHE_DIR, darwin_user_cache_directory, sizeof(darwin_user_cache_directory)) > 0) {
|
||||||
|
StringView darwin_user_cache_directory_view { darwin_user_cache_directory, strlen(darwin_user_cache_directory) };
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, darwin_user_cache_directory_view, Sandbox::SeatbeltPath::Access::ReadWrite));
|
||||||
|
if (darwin_user_cache_directory_view.starts_with("/var/"sv)) {
|
||||||
|
auto private_darwin_user_cache_directory = TRY(String::formatted("/private{}", darwin_user_cache_directory));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, private_darwin_user_cache_directory, Sandbox::SeatbeltPath::Access::ReadWrite));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sandbox::apply_macos_sandbox(paths.span(), Sandbox::NetworkAccess::Denied, executable_paths.span());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,8 @@ set(SOURCES
|
||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
list(APPEND SOURCES SandboxLinux.cpp)
|
list(APPEND SOURCES SandboxLinux.cpp)
|
||||||
|
elseif (APPLE)
|
||||||
|
list(APPEND SOURCES SandboxMacOS.cpp)
|
||||||
else()
|
else()
|
||||||
list(APPEND SOURCES SandboxUnimplemented.cpp)
|
list(APPEND SOURCES SandboxUnimplemented.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -87,4 +87,11 @@ Optional<ResourceSubstitution const&> ResourceSubstitutionMap::lookup(URL::URL c
|
||||||
return it->value;
|
return it->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> ResourceSubstitutionMap::for_each_substitution(Function<ErrorOr<void>(ResourceSubstitution const&)> const& callback) const
|
||||||
|
{
|
||||||
|
for (auto const& entry : m_substitutions)
|
||||||
|
TRY(callback(entry.value));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
|
#include <AK/Function.h>
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <AK/NonnullOwnPtr.h>
|
#include <AK/NonnullOwnPtr.h>
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
|
#include <AK/OwnPtr.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <LibURL/URL.h>
|
#include <LibURL/URL.h>
|
||||||
|
|
||||||
|
|
@ -26,6 +28,7 @@ public:
|
||||||
static ErrorOr<NonnullOwnPtr<ResourceSubstitutionMap>> load_from_file(StringView path);
|
static ErrorOr<NonnullOwnPtr<ResourceSubstitutionMap>> load_from_file(StringView path);
|
||||||
|
|
||||||
Optional<ResourceSubstitution const&> lookup(URL::URL const&) const;
|
Optional<ResourceSubstitution const&> lookup(URL::URL const&) const;
|
||||||
|
ErrorOr<void> for_each_substitution(Function<ErrorOr<void>(ResourceSubstitution const&)> const&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ResourceSubstitutionMap() = default;
|
ResourceSubstitutionMap() = default;
|
||||||
|
|
@ -33,4 +36,6 @@ private:
|
||||||
HashMap<String, ResourceSubstitution> m_substitutions;
|
HashMap<String, ResourceSubstitution> m_substitutions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern OwnPtr<ResourceSubstitutionMap> g_resource_substitution_map;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
61
Services/RequestServer/SandboxMacOS.cpp
Normal file
61
Services/RequestServer/SandboxMacOS.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2026-present, the Ladybird developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/LexicalPath.h>
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <LibCore/Directory.h>
|
||||||
|
#include <LibCore/StandardPaths.h>
|
||||||
|
#include <LibCore/System.h>
|
||||||
|
#include <LibSandbox/Sandbox.h>
|
||||||
|
#include <RequestServer/ResourceSubstitutionMap.h>
|
||||||
|
#include <RequestServer/Sandbox.h>
|
||||||
|
|
||||||
|
namespace RequestServer {
|
||||||
|
|
||||||
|
ErrorOr<void> apply_sandbox(Vector<ByteString> const& certificates)
|
||||||
|
{
|
||||||
|
TRY(Sandbox::configure_runtime());
|
||||||
|
|
||||||
|
Vector<Sandbox::SeatbeltPath> paths;
|
||||||
|
auto cache_path = TRY(String::formatted("{}/Ladybird", Core::StandardPaths::cache_directory()));
|
||||||
|
TRY(Core::Directory::create(cache_path.to_byte_string(), Core::Directory::CreateDirectories::Yes));
|
||||||
|
|
||||||
|
auto executable_path = TRY(Core::System::current_executable_path());
|
||||||
|
auto build_root = LexicalPath::dirname(LexicalPath::dirname(LexicalPath::dirname(LexicalPath::dirname(LexicalPath::dirname(executable_path)))));
|
||||||
|
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, executable_path, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, LexicalPath::join(build_root, "bin"sv).string(), Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, LexicalPath::join(build_root, "lib"sv).string(), Sandbox::SeatbeltPath::Access::ReadAndExecute));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, LexicalPath::join(build_root, "vcpkg_installed"sv).string(), Sandbox::SeatbeltPath::Access::ReadAndExecute));
|
||||||
|
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, "/etc/hosts"sv, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, "/etc/resolv.conf"sv, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, "/private/etc/hosts"sv, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, "/private/etc/resolv.conf"sv, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, "/private/etc/ssl"sv, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, "/Library/Preferences/com.apple.networkd.plist"sv, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
|
||||||
|
for (auto const& certificate : certificates) {
|
||||||
|
auto certificate_path = LexicalPath::dirname(certificate);
|
||||||
|
if (certificate_path.is_empty())
|
||||||
|
certificate_path = ".";
|
||||||
|
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, certificate_path, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_resource_substitution_map) {
|
||||||
|
TRY(g_resource_substitution_map->for_each_substitution([&](auto const& substitution) -> ErrorOr<void> {
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, substitution.file_path, Sandbox::SeatbeltPath::Access::ReadOnly));
|
||||||
|
return {};
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY(Sandbox::add_seatbelt_path_if_exists(paths, cache_path, Sandbox::SeatbeltPath::Access::ReadWrite));
|
||||||
|
|
||||||
|
return Sandbox::apply_macos_sandbox(paths.span(), Sandbox::NetworkAccess::Allowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -40,6 +40,8 @@ add_executable(WebContent main.cpp)
|
||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
target_sources(WebContent PRIVATE ../RendererSandboxLinux.cpp)
|
target_sources(WebContent PRIVATE ../RendererSandboxLinux.cpp)
|
||||||
|
elseif (APPLE)
|
||||||
|
target_sources(WebContent PRIVATE ../RendererSandboxMacOS.cpp)
|
||||||
else()
|
else()
|
||||||
target_sources(WebContent PRIVATE ../RendererSandboxUnimplemented.cpp)
|
target_sources(WebContent PRIVATE ../RendererSandboxUnimplemented.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ add_executable(WebWorker main.cpp)
|
||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
target_sources(WebWorker PRIVATE ../RendererSandboxLinux.cpp)
|
target_sources(WebWorker PRIVATE ../RendererSandboxLinux.cpp)
|
||||||
|
elseif (APPLE)
|
||||||
|
target_sources(WebWorker PRIVATE ../RendererSandboxMacOS.cpp)
|
||||||
else()
|
else()
|
||||||
target_sources(WebWorker PRIVATE ../RendererSandboxUnimplemented.cpp)
|
target_sources(WebWorker PRIVATE ../RendererSandboxUnimplemented.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue