Source/WebCore/ChangeLog

 12018-09-21 Patrick Griffis <pgriffis@igalia.com>
 2
 3 [GTK][WPE] Implement subprocess sandboxing
 4 https://bugs.webkit.org/show_bug.cgi?id=188568
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Link against libseccomp.
 9
 10 * PlatformGTK.cmake:
 11
1122018-09-18 Xabier Rodriguez Calvar <calvaris@igalia.com>
213
314 [EME][GStreamer] The current EME implementation doesn't support the waitingforkey event

Source/WebKit/ChangeLog

 12018-09-21 Patrick Griffis <pgriffis@igalia.com>
 2
 3 [GTK][WPE] Implement subprocess sandboxing
 4 https://bugs.webkit.org/show_bug.cgi?id=188568
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 This implements sandboxing of the WebKitWebProcess, WebKitNetworkProcess,
 9 and WebKitStorageProcess.
 10
 11 The sandbox is opt-in at runtime as it is a behavior change.
 12 See webkit_web_context_set_sandbox_enabled() and the
 13 WEBKIT_SANDBOX_ENABLED env var for developers.
 14
 15 Some currently broken behaviors:
 16
 17 - Access to file:// uris: No immediate plans.
 18 - HTTP credentials access: Planned.
 19 - DnD/FileChooser file access: Planned.
 20 - Downloads: Fix in progress.
 21
 22 This is Linux specific using Namespaces, Seccomp, and a DBus proxy service.
 23 This introduces three new dependencies:
 24
 25 - bwrap executable
 26 - libseccomp library
 27 - xdg-dbus-proxy executable
 28
 29 The use of xdg-dbus-proxy will ideally be replaced once upstream DBus
 30 gains the same filtering abilities which is a work in progress.
 31
 32 Currently the sandbox is not completed and there are a few large holes:
 33
 34 - Pulseaudio: The Pipewire project will solve this.
 35 - DRI device access: No immediate solutions planned.
 36 - Webcam device access: Pipewire will also solve this.
 37 - Webprocess network access: Will require GStreamer changes.
 38 - DConf access: Is being worked on upstream, no ETA.
 39 - X11 access: Wayland solves this.
 40
 41 That is not an exhaustive list but are the noteworthy ones. Filesystem access
 42 is still an evolving list as problems are found as is specific DBus name access.
 43
 44 * PlatformGTK.cmake:
 45 * PlatformWPE.cmake:
 46 * SourcesGTK.txt:
 47 * SourcesWPE.txt:
 48 * UIProcess/API/glib/WebKitWebContext.cpp:
 49 (webkit_web_context_set_sandbox_enabled):
 50 (webkit_web_context_get_sandbox_enabled):
 51 * UIProcess/API/gtk/WebKitWebContext.h:
 52 * UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt:
 53 * UIProcess/API/wpe/WebKitWebContext.h:
 54 * UIProcess/ChildProcessProxy.cpp:
 55 (WebKit::ChildProcessProxy::getLaunchOptions):
 56 * UIProcess/ChildProcessProxy.h:
 57 (WebKit::ChildProcessProxy::platformGetLaunchOptions):
 58 * UIProcess/Launcher/ProcessLauncher.h:
 59 * UIProcess/Launcher/glib/BubblewrapLauncher.cpp: Added.
 60 (WebKit::memfd_create):
 61 (WebKit::argsToFd):
 62 (WebKit::XDGDBusProxyLauncher::setAddress):
 63 (WebKit::XDGDBusProxyLauncher::isRunning const):
 64 (WebKit::XDGDBusProxyLauncher::path const):
 65 (WebKit::XDGDBusProxyLauncher::proxyPath const):
 66 (WebKit::XDGDBusProxyLauncher::setPermissions):
 67 (WebKit::XDGDBusProxyLauncher::launch):
 68 (WebKit::XDGDBusProxyLauncher::childSetupFunc):
 69 (WebKit::XDGDBusProxyLauncher::makeProxyPath):
 70 (WebKit::XDGDBusProxyLauncher::dbusAddressToPath):
 71 (WebKit::bindIfExists):
 72 (WebKit::bindDBusSession):
 73 (WebKit::bindX11):
 74 (WebKit::bindDconf):
 75 (WebKit::bindWayland):
 76 (WebKit::bindPulse):
 77 (WebKit::bindFonts):
 78 (WebKit::bindGtkData):
 79 (WebKit::bindA11y):
 80 (WebKit::bindPathVar):
 81 (WebKit::bindGStreamerData):
 82 (WebKit::bindOpenGL):
 83 (WebKit::bindV4l):
 84 (WebKit::setupSeccomp):
 85 (WebKit::bubblewrapSpawn):
 86 * UIProcess/Launcher/glib/BubblewrapLauncher.h: Added.
 87 * UIProcess/Launcher/glib/FlatpakLauncher.cpp: Added.
 88 (WebKit::flatpakSpawn):
 89 * UIProcess/Launcher/glib/FlatpakLauncher.h: Added.
 90 * UIProcess/Launcher/glib/ProcessLauncherGLib.cpp:
 91 (WebKit::isInsideFlatpak):
 92 (WebKit::ProcessLauncher::launchProcess):
 93 * UIProcess/Network/NetworkProcessProxy.cpp:
 94 (WebKit::WebProcessProxy::platformGetLaunchOptions):
 95 * UIProcess/Network/NetworkProcessProxy.h:
 96 * UIProcess/Storage/StorageProcessProxy.cpp:
 97 (WebKit::StorageProcessProxy::platformGetLaunchOptions):
 98 * UIProcess/Storage/StorageProcessProxy.h:
 99 * UIProcess/WebProcessPool.h:
 100 * UIProcess/WebProcessProxy.cpp:
 101 (WebKit::WebProcessProxy::platformGetLaunchOptions):
 102 * UIProcess/WebProcessProxy.h:
 103 * UIProcess/WebsiteData/WebsiteDataStore.cpp:
 104 (WebKit::WebsiteDataStore::resolveDirectoriesIfNecessary):
 105 * UIProcess/WebsiteData/WebsiteDataStore.h:
 106 (WebKit::WebsiteDataStore::resolvedNetworkCacheDirectory const):
 107 (WebKit::WebsiteDataStore::resolvedLocalStorageDirectory const):
 108 * UIProcess/glib/NetworkProcessProxyGLib.cpp: Added.
 109 (WebKit::NetworkProcessProxy::platformGetLaunchOptions):
 110 * UIProcess/glib/StorageProcessProxyGLib.cpp: Added.
 111 (WebKit::StorageProcessProxy::platformGetLaunchOptions):
 112 * UIProcess/glib/WebProcessProxyGLib.cpp: Added.
 113 (WebKit::WebProcessProxy::platformGetLaunchOptions):
 114
11152018-09-17 Zan Dobersek <zdobersek@igalia.com>
2116
3117 Unreviewed build fix after r236101.

Source/WebCore/PlatformGTK.cmake

@@list(APPEND WebCore_LIBRARIES
106106 ${GLIB_GMODULE_LIBRARIES}
107107 ${GLIB_GOBJECT_LIBRARIES}
108108 ${GLIB_LIBRARIES}
 109 ${LIBSECCOMP_LIBRARIES}
109110 ${LIBSECRET_LIBRARIES}
110111 ${LIBSOUP_LIBRARIES}
111112 ${LIBTASN1_LIBRARIES}

@@list(APPEND WebCore_SYSTEM_INCLUDE_DIRECTORIES
125126 ${ENCHANT_INCLUDE_DIRS}
126127 ${GIO_UNIX_INCLUDE_DIRS}
127128 ${GLIB_INCLUDE_DIRS}
 129 ${LIBSECCOMP_INCLUDE_DIRS}
128130 ${LIBSECRET_INCLUDE_DIRS}
129131 ${LIBSOUP_INCLUDE_DIRS}
130132 ${LIBTASN1_INCLUDE_DIRS}

Source/WebKit/PlatformGTK.cmake

@@add_definitions(-DWEBKIT_DOM_USE_UNSTABLE_API)
2020
2121add_definitions(-DPKGLIBEXECDIR="${LIBEXEC_INSTALL_DIR}")
2222add_definitions(-DLOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}")
 23add_definitions(-DDATADIR="${CMAKE_INSTALL_FULL_DATADIR}")
2324add_definitions(-DLIBDIR="${LIB_INSTALL_DIR}")
2425
2526if (NOT DEVELOPER_MODE AND NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")

@@if (ENABLE_PLUGIN_PROCESS_GTK2)
630631
631632 UIProcess/Launcher/ProcessLauncher.cpp
632633
 634 UIProcess/Launcher/glib/BubblewrapLauncher.cpp
 635 UIProcess/Launcher/glib/FlatpakLauncher.cpp
633636 UIProcess/Launcher/glib/ProcessLauncherGLib.cpp
634637
635638 UIProcess/Plugins/unix/PluginProcessProxyUnix.cpp

Source/WebKit/PlatformWPE.cmake

@@add_definitions(-DWEBKIT2_COMPILATION)
1717
1818add_definitions(-DPKGLIBDIR="${LIB_INSTALL_DIR}/wpe-webkit-${WPE_API_VERSION}")
1919add_definitions(-DPKGLIBEXECDIR="${LIBEXEC_INSTALL_DIR}")
 20add_definitions(-DDATADIR="${CMAKE_INSTALL_FULL_DATADIR}")
2021add_definitions(-DLOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}")
2122
2223if (NOT DEVELOPER_MODE AND NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")

Source/WebKit/SourcesGTK.txt

@@UIProcess/Automation/cairo/WebAutomationSessionCairo.cpp
204204UIProcess/Automation/gtk/WebAutomationSessionGtk.cpp
205205
206206UIProcess/Launcher/glib/ProcessLauncherGLib.cpp @no-unify
 207UIProcess/Launcher/glib/BubblewrapLauncher.cpp @no-unify
 208UIProcess/Launcher/glib/FlatpakLauncher.cpp @no-unify
207209
208210UIProcess/Network/CustomProtocols/LegacyCustomProtocolManagerProxy.cpp
209211

@@UIProcess/WebsiteData/unix/WebsiteDataStoreUnix.cpp
220222
221223UIProcess/cairo/BackingStoreCairo.cpp @no-unify
222224
 225UIProcess/glib/NetworkProcessProxyGLib.cpp
223226UIProcess/glib/RemoteInspectorClient.cpp
 227UIProcess/glib/StorageProcessProxyGLib.cpp
 228UIProcess/glib/WebProcessProxyGLib.cpp
224229
225230UIProcess/gstreamer/InstallMissingMediaPluginsPermissionRequest.cpp
226231UIProcess/gstreamer/WebPageProxyGStreamer.cpp

Source/WebKit/SourcesWPE.txt

@@UIProcess/Automation/cairo/WebAutomationSessionCairo.cpp
178178
179179UIProcess/Automation/wpe/WebAutomationSessionWPE.cpp
180180
 181UIProcess/glib/NetworkProcessProxyGLib.cpp
 182UIProcess/glib/StorageProcessProxyGLib.cpp
 183UIProcess/glib/WebProcessProxyGLib.cpp
 184
181185UIProcess/Launcher/glib/ProcessLauncherGLib.cpp
 186UIProcess/Launcher/glib/BubblewrapLauncher.cpp @no-unify
 187UIProcess/Launcher/glib/FlatpakLauncher.cpp @no-unify
182188
183189UIProcess/Network/CustomProtocols/LegacyCustomProtocolManagerProxy.cpp
184190

Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp

@@void webkit_web_context_register_uri_scheme(WebKitWebContext* context, const cha
11471147 context->priv->processPool->registerSchemeForCustomProtocol(String::fromUTF8(scheme));
11481148}
11491149
 1150/**
 1151 * webkit_web_context_set_sandbox_enabled:
 1152 * @context: a #WebKitWebContext
 1153 * @enabled: if %TRUE enable sandboxing
 1154 *
 1155 * Set whether WebKit subprocesses will be sandboxed, limiting access to the system.
 1156 *
 1157 * This method **must be called before any web process has been created**,
 1158 * as early as possible in your application. Calling it later is a fatal error.
 1159 *
 1160 * This is only implemented on Linux and is a no-op otherwise.
 1161 *
 1162 * If you use `$XDG_CONFIG_HOME/g_get_prgname()` in your #WebKitWebsiteDataManager
 1163 * you must ensure it exists before subprocesses are created.
 1164 *
 1165 * Since: 2.24
 1166 */
 1167void webkit_web_context_set_sandbox_enabled(WebKitWebContext* context, gboolean enabled)
 1168{
 1169 g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
 1170
 1171 if (context->priv->processPool->processes().size())
 1172 g_error("Sandboxing cannot be changed after subprocesses were spawned.");
 1173
 1174 context->priv->processPool->setSandboxEnabled(enabled);
 1175}
 1176
 1177/**
 1178 * webkit_web_context_get_sandbox_enabled:
 1179 * @context: a #WebKitWebContext
 1180 *
 1181 * Get whether sandboxing is currently enabled.
 1182 *
 1183 * Returns: %TRUE if sandboxing is enabled, or %FALSE otherwise.
 1184 *
 1185 * Since: 2.24
 1186 */
 1187gboolean webkit_web_context_get_sandbox_enabled(WebKitWebContext* context)
 1188{
 1189 g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), FALSE);
 1190
 1191 return context->priv->processPool->sandboxEnabled();
 1192}
 1193
11501194/**
11511195 * webkit_web_context_get_spell_checking_enabled:
11521196 * @context: a #WebKitWebContext

Source/WebKit/UIProcess/API/gtk/WebKitWebContext.h

@@webkit_web_context_register_uri_scheme (WebKitWebContext
247247 gpointer user_data,
248248 GDestroyNotify user_data_destroy_func);
249249
 250WEBKIT_API void
 251webkit_web_context_set_sandbox_enabled (WebKitWebContext *context,
 252 gboolean enabled);
 253
 254WEBKIT_API gboolean
 255webkit_web_context_get_sandbox_enabled (WebKitWebContext *context);
 256
250257WEBKIT_API gboolean
251258webkit_web_context_get_spell_checking_enabled (WebKitWebContext *context);
252259

Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt

@@webkit_web_context_get_security_manager
5151webkit_web_context_set_additional_plugins_directory
5252webkit_web_context_get_plugins
5353webkit_web_context_get_plugins_finish
 54webkit_web_context_get_sandbox_enabled
 55webkit_web_context_set_sandbox_enabled
5456webkit_web_context_get_spell_checking_enabled
5557webkit_web_context_set_spell_checking_enabled
5658webkit_web_context_get_spell_checking_languages

Source/WebKit/UIProcess/API/wpe/WebKitWebContext.h

@@webkit_web_context_set_process_model (WebKitWebContext
296296WEBKIT_API WebKitProcessModel
297297webkit_web_context_get_process_model (WebKitWebContext *context);
298298
 299WEBKIT_API void
 300webkit_web_context_set_sandbox_enabled (WebKitWebContext *context,
 301 gboolean enabled);
 302
 303WEBKIT_API gboolean
 304webkit_web_context_get_sandbox_enabled (WebKitWebContext *context);
 305
299306WEBKIT_API void
300307webkit_web_context_initialize_notification_permissions
301308 (WebKitWebContext *context,

Source/WebKit/UIProcess/ChildProcessProxy.cpp

@@void ChildProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchO
8080 if (processCmdPrefix && *processCmdPrefix)
8181 launchOptions.processCmdPrefix = String::fromUTF8(processCmdPrefix);
8282#endif // ENABLE(DEVELOPER_MODE) && (PLATFORM(GTK) || PLATFORM(WPE))
 83
 84 platformGetLaunchOptions(launchOptions);
8385}
8486
 87
8588void ChildProcessProxy::connect()
8689{
8790 ASSERT(!m_processLauncher);

Source/WebKit/UIProcess/ChildProcessProxy.h

@@protected:
9393 bool dispatchSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&);
9494
9595 virtual void getLaunchOptions(ProcessLauncher::LaunchOptions&);
 96 virtual void platformGetLaunchOptions(ProcessLauncher::LaunchOptions&) { };
9697
9798private:
9899 virtual void connectionWillOpen(IPC::Connection&);

Source/WebKit/UIProcess/Launcher/ProcessLauncher.h

@@public:
6868 bool shouldMakeProcessLaunchFailForTesting { false };
6969 CString customWebContentServiceBundleIdentifier;
7070
 71#if PLATFORM(GTK) || PLATFORM(WPE)
 72 Vector<String> extraSandboxPaths;
 73 bool sandboxEnabled { false };
 74#endif
 75
7176#if ENABLE(DEVELOPER_MODE) && (PLATFORM(GTK) || PLATFORM(WPE))
7277 String processCmdPrefix;
7378#endif

Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp

 1/*
 2 * Copyright (C) 2018 Igalia S.L.
 3 *
 4 * This program is free software; you can redistribute it and/or
 5 * modify it under the terms of the GNU Lesser General Public
 6 * License as published by the Free Software Foundation; either
 7 * version 2.1 of the License, or (at your option) any later version.
 8 *
 9 * This library is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 12 * Lesser General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU Lesser General Public
 15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 16 */
 17
 18#include "config.h"
 19#include "BubblewrapLauncher.h"
 20
 21#if ENABLE(BUBBLEWRAP_SANDBOX)
 22
 23#include <WebCore/FileSystem.h>
 24#include <WebCore/PlatformDisplay.h>
 25#include <fcntl.h>
 26#include <glib.h>
 27#include <seccomp.h>
 28#include <sys/ioctl.h>
 29#include <wtf/glib/GLibUtilities.h>
 30#include <wtf/glib/GRefPtr.h>
 31#include <wtf/glib/GUniquePtr.h>
 32
 33namespace WebKit {
 34using namespace WebCore;
 35
 36static int memfd_create(const char* name, unsigned flags)
 37{
 38 return syscall(__NR_memfd_create, name, flags);
 39}
 40
 41#define MFD_ALLOW_SEALING 2U
 42
 43static int
 44argsToFd(const Vector<CString>& args, const char *name)
 45{
 46 GString* buffer = g_string_new(nullptr);
 47
 48 for (const auto& arg : args)
 49 g_string_append_len(buffer, arg.data(), arg.length() + 1); // Include NUL
 50
 51 GRefPtr<GBytes> bytes = adoptGRef(g_string_free_to_bytes(buffer));
 52
 53 int memfd = memfd_create(name, MFD_ALLOW_SEALING);
 54 if (memfd == -1)
 55 g_error("memfd_create failed: %s", g_strerror(errno));
 56
 57 size_t size;
 58 gconstpointer data = g_bytes_get_data(bytes.get(), &size);
 59
 60 ssize_t bytesWritten = write(memfd, data, size);
 61 if (bytesWritten < 0)
 62 g_error("Writing args to memfd failed: %s", g_strerror(errno));
 63
 64 if (static_cast<size_t>(bytesWritten) != size)
 65 g_error("Failed to write all args to memfd");
 66
 67 if (lseek(memfd, 0, SEEK_SET) == -1)
 68 g_error("lseek failed: %s", g_strerror(errno));
 69
 70 if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) == -1)
 71 g_error("Failed to seal memfd: %s", g_strerror(errno));
 72
 73 return memfd;
 74}
 75
 76enum class DBusAddressType {
 77 Normal,
 78 Abstract,
 79};
 80
 81class XDGDBusProxyLauncher {
 82public:
 83 void setAddress(const char* dbusAddress, DBusAddressType addressType)
 84 {
 85 GUniquePtr<char> dbusPath = dbusAddressToPath(dbusAddress, addressType);
 86 if (!dbusPath.get())
 87 return;
 88
 89 GUniquePtr<char> appRunDir(g_build_filename(g_get_user_runtime_dir(), g_get_prgname(), nullptr));
 90 m_proxyPath = makeProxyPath(appRunDir.get()).get();
 91
 92 m_socket = dbusAddress;
 93 m_path = dbusPath.get();
 94 }
 95
 96 bool isRunning() const { return m_process.get() && g_subprocess_get_if_exited(m_process.get()); };
 97 const CString& path() const { return m_path; };
 98 const CString& proxyPath() const { return m_proxyPath; };
 99
 100 void setPermissions(Vector<CString>&& permissions)
 101 {
 102 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!isRunning());
 103 m_permissions = permissions;
 104 };
 105
 106 void launch()
 107 {
 108 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!isRunning());
 109
 110 if (m_socket.isNull() || m_path.isNull() || m_proxyPath.isNull())
 111 return;
 112
 113 int syncFds[2];
 114 if (pipe2 (syncFds, O_CLOEXEC) == -1)
 115 g_error("Failed to make syncfds for dbus-proxy: %s", g_strerror(errno));
 116
 117 GUniquePtr<char> syncFdStr(g_strdup_printf("--fd=%d", syncFds[1]));
 118
 119 Vector<CString> proxyArgs = {
 120 m_socket, m_proxyPath,
 121 "--filter",
 122 syncFdStr.get(),
 123 };
 124
 125 if (!g_strcmp0(g_getenv("WEBKIT_ENABLE_DBUS_PROXY_LOGGING"), "1"))
 126 proxyArgs.append("--log");
 127
 128 proxyArgs.appendVector(m_permissions);
 129
 130
 131 int proxyFd = argsToFd(proxyArgs, "dbus-proxy");
 132 GUniquePtr<char> proxyArgsStr(g_strdup_printf("--args=%d", proxyFd));
 133
 134 Vector<CString> args = {
 135 DBUS_PROXY_EXECUTABLE,
 136 proxyArgsStr.get(),
 137 };
 138
 139 int nargs = args.size() + 1;
 140 int i = 0;
 141 char** argv = g_newa(char*, nargs);
 142 for (const auto& arg : args)
 143 argv[i++] = const_cast<char*>(arg.data());
 144 argv[i] = nullptr;
 145
 146 GRefPtr<GSubprocessLauncher> launcher = adoptGRef(g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_INHERIT_FDS));
 147 g_subprocess_launcher_set_child_setup(launcher.get(), childSetupFunc, GINT_TO_POINTER(syncFds[1]), nullptr);
 148 g_subprocess_launcher_take_fd(launcher.get(), proxyFd, proxyFd);
 149 g_subprocess_launcher_take_fd(launcher.get(), syncFds[1], syncFds[1]);
 150 // We are purposefully leaving syncFds[0] open here.
 151 // xdg-dbus-proxy will exit() itself once that is closed on our exit
 152
 153 GUniqueOutPtr<GError> error;
 154 m_process = adoptGRef(g_subprocess_launcher_spawnv(launcher.get(), argv, &error.outPtr()));
 155 if (error.get())
 156 g_error("Failed to start dbus proxy: %s", error.get()->message);
 157
 158 char out;
 159 // We need to ensure the proxy has created the socket.
 160 // FIXME: This is more blocking IO.
 161 if (read (syncFds[0], &out, 1) != 1)
 162 g_error("Failed to fully launch dbus-proxy %s", g_strerror(errno));
 163 };
 164
 165private:
 166 static void childSetupFunc(gpointer userdata)
 167 {
 168 int fd = GPOINTER_TO_INT(userdata);
 169 fcntl(fd, F_SETFD, 0); // Unset CLOEXEC
 170 }
 171
 172 static GUniquePtr<char> makeProxyPath(const char* appRunDir)
 173 {
 174 if (g_mkdir_with_parents(appRunDir, 0700) == -1) {
 175 g_warning("Failed to mkdir for dbus proxy (%s): %s", appRunDir, g_strerror(errno));
 176 return GUniquePtr<char>(nullptr);
 177 }
 178
 179 char* proxySocketTemplate = g_build_filename(appRunDir, "dbus-proxy-XXXXXX", nullptr);
 180 int fd;
 181 if ((fd = g_mkstemp(proxySocketTemplate)) == -1) {
 182 g_free(proxySocketTemplate);
 183 g_warning("Failed to make socket file for dbus proxy: %s", g_strerror(errno));
 184 return GUniquePtr<char>(nullptr);
 185 }
 186
 187 close(fd);
 188 return GUniquePtr<char>(proxySocketTemplate);
 189 };
 190
 191 static GUniquePtr<char> dbusAddressToPath(const char* address, DBusAddressType addressType = DBusAddressType::Normal)
 192 {
 193 if (!address)
 194 return nullptr;
 195
 196 if (!g_str_has_prefix(address, "unix:"))
 197 return nullptr;
 198
 199 const char* path = strstr(address, addressType == DBusAddressType::Abstract ? "abstract=" : "path=");
 200 if (!path)
 201 return nullptr;
 202
 203 path += strlen(addressType == DBusAddressType::Abstract ? "abstract=" : "path=");
 204 const char* pathEnd = path;
 205 while (*pathEnd && *pathEnd != ',')
 206 pathEnd++;
 207
 208 return GUniquePtr<char>(g_strndup(path, pathEnd - path));
 209}
 210
 211 CString m_socket;
 212 CString m_path;
 213 CString m_proxyPath;
 214 GRefPtr<GSubprocess> m_process;
 215 Vector<CString> m_permissions;
 216};
 217
 218enum class BindFlags {
 219 ReadOnly,
 220 ReadWrite,
 221 Device,
 222};
 223
 224static void bindIfExists(Vector<CString>& args, const char* path, BindFlags bindFlags = BindFlags::ReadOnly)
 225{
 226 if (!path)
 227 return;
 228
 229 const char* bindType;
 230 if (bindFlags == BindFlags::Device)
 231 bindType = "--dev-bind-try";
 232 else if (bindFlags == BindFlags::ReadOnly)
 233 bindType = "--ro-bind-try";
 234 else
 235 bindType = "--bind-try";
 236 args.appendVector(Vector<CString>({ bindType, path, path }));
 237}
 238
 239static void bindDBusSession(Vector<CString>& args, XDGDBusProxyLauncher& proxy)
 240{
 241 if (!proxy.isRunning())
 242 proxy.setAddress(g_getenv("DBUS_SESSION_BUS_ADDRESS"), DBusAddressType::Normal);
 243
 244 args.appendVector(Vector<CString>({
 245 "--bind", proxy.proxyPath(), proxy.path(),
 246 }));
 247}
 248
 249static void bindX11(Vector<CString>& args)
 250{
 251 const char* display = g_getenv("DISPLAY");
 252 if (!display || display[0] != ':' || !g_ascii_isdigit(const_cast<char*>(display)[1]))
 253 display = ":0";
 254 GUniquePtr<char> x11File(g_strdup_printf("/tmp/.X11-unix/X%s", display + 1));
 255 bindIfExists(args, x11File.get(), BindFlags::ReadWrite);
 256
 257 const char* xauth = g_getenv("XAUTHORITY");
 258 if (!xauth) {
 259 const char* homeDir = g_get_home_dir();
 260 GUniquePtr<char> xauthFile(g_build_filename(homeDir, ".Xauthority", nullptr));
 261 bindIfExists(args, xauthFile.get());
 262 } else
 263 bindIfExists(args, xauth);
 264}
 265
 266static void bindDconf(Vector<CString>& args)
 267{
 268 const char* runtimeDir = g_get_user_runtime_dir();
 269 GUniquePtr<char> dconfRuntimeDir(g_build_filename(runtimeDir, "dconf", nullptr));
 270 args.appendVector(Vector<CString>({ "--bind", dconfRuntimeDir.get(), dconfRuntimeDir.get() }));
 271
 272 const char* dconfDir = g_getenv("DCONF_USER_CONFIG_DIR");
 273 if (dconfDir)
 274 bindIfExists(args, dconfDir);
 275 else {
 276 const char* configDir = g_get_user_config_dir();
 277 GUniquePtr<char> dconfConfigDir(g_build_filename(configDir, "dconf", nullptr));
 278 bindIfExists(args, dconfConfigDir.get(), BindFlags::ReadWrite);
 279 }
 280}
 281
 282static void bindWayland(Vector<CString>& args)
 283{
 284 const char* display = g_getenv("WAYLAND_DISPLAY");
 285 if (!display)
 286 display = "wayland-0";
 287
 288 const char* runtimeDir = g_get_user_runtime_dir();
 289 GUniquePtr<char> waylandRuntimeFile(g_build_filename(runtimeDir, display, nullptr));
 290 bindIfExists(args, waylandRuntimeFile.get(), BindFlags::ReadWrite);
 291}
 292
 293static void bindPulse(Vector<CString>& args)
 294{
 295 // FIXME: The server can be defined in config files we'd have to parse.
 296 // They can also be set as X11 props but that is getting a bit ridiculous.
 297 const char* pulseServer = g_getenv("PULSE_SERVER");
 298 if (pulseServer) {
 299 if (g_str_has_prefix(pulseServer, "unix:"))
 300 bindIfExists(args, pulseServer + 5, BindFlags::ReadWrite);
 301 // else it uses tcp
 302 } else {
 303 const char* runtimeDir = g_get_user_runtime_dir();
 304 GUniquePtr<char> pulseRuntimeDir(g_build_filename(runtimeDir, "pulse", nullptr));
 305 bindIfExists(args, pulseRuntimeDir.get(), BindFlags::ReadWrite);
 306 }
 307
 308 const char* pulseConfig = g_getenv("PULSE_CLIENTCONFIG");
 309 if (pulseConfig)
 310 bindIfExists(args, pulseConfig);
 311
 312 const char* configDir = g_get_user_config_dir();
 313 GUniquePtr<char> pulseConfigDir(g_build_filename(configDir, "pulse", nullptr));
 314 bindIfExists(args, pulseConfigDir.get());
 315
 316 const char* homeDir = g_get_home_dir();
 317 GUniquePtr<char> pulseHomeConfigDir(g_build_filename(homeDir, ".pulse", nullptr));
 318 GUniquePtr<char> asoundHomeConfigDir(g_build_filename(homeDir, ".asoundrc", nullptr));
 319 bindIfExists(args, pulseHomeConfigDir.get());
 320 bindIfExists(args, asoundHomeConfigDir.get());
 321
 322 // This is the ultimate fallback to raw ALSA
 323 bindIfExists(args, "/dev/snd", BindFlags::Device);
 324}
 325
 326static void bindFonts(Vector<CString>& args)
 327{
 328 const char* configDir = g_get_user_config_dir();
 329 const char* homeDir = g_get_home_dir();
 330 const char* dataDir = g_get_user_data_dir();
 331 const char* cacheDir = g_get_user_cache_dir();
 332
 333 // Configs can include custom dirs but then we have to parse them...
 334 GUniquePtr<char> fontConfig(g_build_filename(configDir, "fontconfig", nullptr));
 335 GUniquePtr<char> fontCache(g_build_filename(cacheDir, "fontconfig", nullptr));
 336 GUniquePtr<char> fontHomeConfig(g_build_filename(homeDir, ".fonts.conf", nullptr));
 337 GUniquePtr<char> fontHomeConfigDir(g_build_filename(configDir, ".fonts.conf.d", nullptr));
 338 GUniquePtr<char> fontData(g_build_filename(dataDir, "fonts", nullptr));
 339 GUniquePtr<char> fontHomeData(g_build_filename(homeDir, ".fonts", nullptr));
 340 bindIfExists(args, fontConfig.get());
 341 bindIfExists(args, fontCache.get(), BindFlags::ReadWrite);
 342 bindIfExists(args, fontHomeConfig.get());
 343 bindIfExists(args, fontHomeConfigDir.get());
 344 bindIfExists(args, fontData.get());
 345 bindIfExists(args, fontHomeData.get());
 346}
 347
 348#if PLATFORM(GTK)
 349static void bindGtkData(Vector<CString>& args)
 350{
 351 const char* configDir = g_get_user_config_dir();
 352 const char* dataDir = g_get_user_data_dir();
 353 const char* homeDir = g_get_home_dir();
 354
 355 GUniquePtr<char> gtkConfig(g_build_filename(configDir, "gtk-3.0", nullptr));
 356 GUniquePtr<char> themeData(g_build_filename(dataDir, "themes", nullptr));
 357 GUniquePtr<char> themeHomeData(g_build_filename(homeDir, ".themes", nullptr));
 358 GUniquePtr<char> iconHomeData(g_build_filename(homeDir, ".icons", nullptr));
 359 bindIfExists(args, gtkConfig.get());
 360 bindIfExists(args, themeData.get());
 361 bindIfExists(args, themeHomeData.get());
 362 bindIfExists(args, iconHomeData.get());
 363}
 364
 365static void bindA11y(Vector<CString>& args)
 366{
 367 static XDGDBusProxyLauncher proxy;
 368
 369 if (!proxy.isRunning()) {
 370 // FIXME: Avoid blocking IO... (It is at least a one-time cost)
 371 GRefPtr<GDBusConnection> sessionBus = adoptGRef(g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr));
 372 if (!sessionBus.get())
 373 return;
 374
 375 GRefPtr<GDBusMessage> msg = adoptGRef(g_dbus_message_new_method_call(
 376 "org.a11y.Bus", "/org/a11y/bus", "org.a11y.Bus", "GetAddress"));
 377 g_dbus_message_set_body(msg.get(), g_variant_new("()"));
 378 GRefPtr<GDBusMessage> reply = adoptGRef(g_dbus_connection_send_message_with_reply_sync(
 379 sessionBus.get(), msg.get(),
 380 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
 381 30000,
 382 nullptr,
 383 nullptr,
 384 nullptr));
 385
 386 if (reply.get()) {
 387 GUniqueOutPtr<GError> error;
 388 if (g_dbus_message_to_gerror(reply.get(), &error.outPtr())) {
 389 if (!g_error_matches(error.get(), G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))
 390 g_warning("Can't find a11y bus: %s", error->message);
 391 } else {
 392 GUniqueOutPtr<char> a11yAddress;
 393 g_variant_get(g_dbus_message_get_body(reply.get()), "(s)", &a11yAddress.outPtr());
 394 proxy.setAddress(a11yAddress.get(), DBusAddressType::Abstract);
 395 }
 396 }
 397
 398 proxy.setPermissions({
 399 "--sloppy-names",
 400 "--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Embed@/org/a11y/atspi/accessible/root",
 401 "--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Unembed@/org/a11y/atspi/accessible/root",
 402 "--call=org.a11y.atspi.Registry=org.a11y.atspi.Registry.GetRegisteredEvents@/org/a11y/atspi/registry",
 403 "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetKeystrokeListeners@/org/a11y/atspi/registry/deviceeventcontroller",
 404 "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetDeviceEventListeners@/org/a11y/atspi/registry/deviceeventcontroller",
 405 "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersSync@/org/a11y/atspi/registry/deviceeventcontroller",
 406 "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersAsync@/org/a11y/atspi/registry/deviceeventcontroller",
 407 });
 408
 409 proxy.launch();
 410 }
 411
 412 args.appendVector(Vector<CString>({
 413 "--bind", proxy.proxyPath(), proxy.path(),
 414 }));
 415}
 416#endif
 417
 418static bool bindPathVar(Vector<CString>& args, const char* varname)
 419{
 420 const char* pathValue = g_getenv(varname);
 421 if (!pathValue)
 422 return false;
 423
 424 GUniquePtr<char*> splitPaths(g_strsplit(pathValue, ":", -1));
 425 for (size_t i; splitPaths.get()[i]; ++i)
 426 bindIfExists(args, splitPaths.get()[i]);
 427
 428 return true;
 429}
 430
 431static void bindGStreamerData(Vector<CString>& args)
 432{
 433 if (!bindPathVar(args, "GST_PLUGIN_PATH_1_0"))
 434 bindPathVar(args, "GST_PLUGIN_PATH");
 435
 436 if (!bindPathVar(args, "GST_PLUGIN_SYSTEM_PATH_1_0")) {
 437 if (!bindPathVar(args, "GST_PLUGIN_SYSTEM_PATH")) {
 438 GUniquePtr<char> gstData(g_build_filename(g_get_user_data_dir(), "gstreamer-1.0", nullptr));
 439 bindIfExists(args, gstData.get());
 440 }
 441 }
 442
 443 GUniquePtr<char> gstCache(g_build_filename(g_get_user_cache_dir(), "gstreamer-1.0", nullptr));
 444 bindIfExists(args, gstCache.get(), BindFlags::ReadWrite);
 445
 446 // /usr/lib is already added so this is only requried for other dirs
 447 const char* scannerPath = g_getenv("GST_PLUGIN_SCANNER") ?: "/usr/libexec/gstreamer-1.0/gst-plugin-scanner";
 448 const char* helperPath = g_getenv("GST_INSTALL_PLUGINS_HELPER ") ?: "/usr/libexec/gst-install-plugins-helper";
 449
 450 bindIfExists(args, scannerPath);
 451 bindIfExists(args, helperPath);
 452}
 453
 454static void bindOpenGL(Vector<CString>& args)
 455{
 456 args.appendVector(Vector<CString>({
 457 "--dev-bind-try", "/dev/dri", "/dev/dri",
 458 // Mali
 459 "--dev-bind-try", "/dev/mali", "/dev/mali",
 460 "--dev-bind-try", "/dev/mali0", "/dev/mali0",
 461 "--dev-bind-try", "/dev/umplock", "/dev/umplock",
 462 // Nvidia
 463 "--dev-bind-try", "/dev/nvidiactl", "/dev/nvidiactl",
 464 "--dev-bind-try", "/dev/nvidia0", "/dev/nvidia0",
 465 "--dev-bind-try", "/dev/nvidia", "/dev/nvidia",
 466 // Adreno
 467 "--dev-bind-try", "/dev/kgsl-3d0", "/dev/kgsl-3d0",
 468 "--dev-bind-try", "/dev/ion", "/dev/ion",
 469#if PLATFORM(WPE)
 470 "--dev-bind-try", "/dev/fb0", "/dev/fb0",
 471 "--dev-bind-try", "/dev/fb1", "/dev/fb1",
 472#endif
 473 }));
 474}
 475
 476static void bindV4l(Vector<CString>& args)
 477{
 478 args.appendVector(Vector<CString>({
 479 "--dev-bind-try", "/dev/v4l", "/dev/v4l",
 480 // Not pretty but a stop-gap for pipewire anyway.
 481 "--dev-bind-try", "/dev/video0", "/dev/video0",
 482 "--dev-bind-try", "/dev/video1", "/dev/video1",
 483 }));
 484}
 485
 486static int setupSeccomp()
 487{
 488 // NOTE: This is shared code (flatpak-run.c - LGPLv2.1+)
 489 // There are today a number of different Linux container
 490 // implementations. That will likely continue for long into the
 491 // future. But we can still try to share code, and it's important
 492 // to do so because it affects what library and application writers
 493 // can do, and we should support code portability between different
 494 // container tools.
 495 //
 496 // This syscall blacklist is copied from linux-user-chroot, which was in turn
 497 // clearly influenced by the Sandstorm.io blacklist.
 498 //
 499 // If you make any changes here, I suggest sending the changes along
 500 // to other sandbox maintainers. Using the libseccomp list is also
 501 // an appropriate venue:
 502 // https://groups.google.com/forum/#!topic/libseccomp
 503 //
 504 // A non-exhaustive list of links to container tooling that might
 505 // want to share this blacklist:
 506 //
 507 // https://github.com/sandstorm-io/sandstorm
 508 // in src/sandstorm/supervisor.c++
 509 // http://cgit.freedesktop.org/xdg-app/xdg-app/
 510 // in common/flatpak-run.c
 511 // https://git.gnome.org/browse/linux-user-chroot
 512 // in src/setup-seccomp.c
 513 struct scmp_arg_cmp cloneArg = SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER);
 514 struct scmp_arg_cmp ttyArg = SCMP_A1(SCMP_CMP_EQ, (int)TIOCSTI);
 515 struct {
 516 int scall;
 517 struct scmp_arg_cmp* arg;
 518 } syscallBlacklist[] = {
 519 // Block dmesg
 520 { SCMP_SYS(syslog), nullptr },
 521 // Useless old syscall
 522 { SCMP_SYS(uselib), nullptr },
 523 // Don't allow disabling accounting
 524 { SCMP_SYS(acct), nullptr },
 525 // 16-bit code is unnecessary in the sandbox, and modify_ldt is a
 526 // historic source of interesting information leaks.
 527 { SCMP_SYS(modify_ldt), nullptr },
 528 // Don't allow reading current quota use
 529 { SCMP_SYS(quotactl), nullptr },
 530
 531 // Don't allow access to the kernel keyring
 532 { SCMP_SYS(add_key), nullptr },
 533 { SCMP_SYS(keyctl), nullptr },
 534 { SCMP_SYS(request_key), nullptr },
 535
 536 // Scary VM/NUMA ops
 537 { SCMP_SYS(move_pages), nullptr },
 538 { SCMP_SYS(mbind), nullptr },
 539 { SCMP_SYS(get_mempolicy), nullptr },
 540 { SCMP_SYS(set_mempolicy), nullptr },
 541 { SCMP_SYS(migrate_pages), nullptr },
 542
 543 // Don't allow subnamespace setups:
 544 { SCMP_SYS(unshare), nullptr },
 545 { SCMP_SYS(mount), nullptr },
 546 { SCMP_SYS(pivot_root), nullptr },
 547 { SCMP_SYS(clone), &cloneArg },
 548
 549 // Don't allow faking input to the controlling tty (CVE-2017-5226)
 550 { SCMP_SYS(ioctl), &ttyArg },
 551
 552 // Profiling operations; we expect these to be done by tools from outside
 553 // the sandbox. In particular perf has been the source of many CVEs.
 554 { SCMP_SYS(perf_event_open), nullptr },
 555 // Don't allow you to switch to bsd emulation or whatnot.
 556 { SCMP_SYS(personality), nullptr },
 557 { SCMP_SYS(ptrace), nullptr }
 558 };
 559
 560 scmp_filter_ctx seccomp = seccomp_init(SCMP_ACT_ALLOW);
 561 if (!seccomp)
 562 g_error("Failed to init seccomp");
 563
 564 for (auto& rule : syscallBlacklist) {
 565 int scall = rule.scall;
 566 int r;
 567 if (rule.arg)
 568 r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), scall, 1, rule.arg);
 569 else
 570 r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), scall, 0);
 571 if (r == -EFAULT) {
 572 seccomp_release(seccomp);
 573 g_error("Failed to add seccomp rule");
 574 }
 575 }
 576
 577 int tmpfd = memfd_create("seccomp-bpf", 0);
 578 if (tmpfd == -1) {
 579 seccomp_release(seccomp);
 580 g_error("Failed to create memfd: %s", g_strerror(errno));
 581 }
 582
 583 if (seccomp_export_bpf(seccomp, tmpfd)) {
 584 seccomp_release(seccomp);
 585 close(tmpfd);
 586 g_error("Failed to export seccomp bpf");
 587 }
 588
 589 if (lseek(tmpfd, 0, SEEK_SET) < 0)
 590 g_error("lseek failed: %s", g_strerror(errno));
 591
 592 seccomp_release(seccomp);
 593 return tmpfd;
 594}
 595
 596GRefPtr<GSubprocess> bubblewrapSpawn(GRefPtr<GSubprocessLauncher> launcher, const ProcessLauncher::LaunchOptions& launchOptions, char** argv, GError **error)
 597{
 598 // It is impossible to know what access arbitrary plugins need and since it is for legacy
 599 // reasons lets just leave it unsandboxed.
 600 if (launchOptions.processType == ProcessLauncher::ProcessType::Plugin64
 601 || launchOptions.processType == ProcessLauncher::ProcessType::Plugin32)
 602 return g_subprocess_launcher_spawnv(launcher.get(), argv, error);
 603
 604 // NOTE: This is not a great solution but we just assume that applications create this directory
 605 // ahead of time if they require it.
 606 GUniquePtr<char> configDir(g_build_filename(g_get_user_config_dir(), g_get_prgname(), nullptr));
 607
 608 Vector<CString> sandboxArgs = {
 609 "--die-with-parent",
 610 "--unshare-pid",
 611 "--unshare-uts",
 612
 613 // We assume /etc has safe permissions.
 614 // At a later point we can start masking privacy-concerning files.
 615 "--ro-bind", "/etc", "/etc",
 616 "--dev", "/dev",
 617 "--proc", "/proc",
 618 "--tmpfs", "/tmp",
 619 "--unsetenv", "TMPDIR",
 620 "--dir", "/run",
 621 "--symlink", "../run", "/var/run",
 622 "--symlink", "../tmp", "/var/tmp",
 623 "--ro-bind", "/sys/block", "/sys/block",
 624 "--ro-bind", "/sys/bus", "/sys/bus",
 625 "--ro-bind", "/sys/class", "/sys/class",
 626 "--ro-bind", "/sys/dev", "/sys/dev",
 627 "--ro-bind", "/sys/devices", "/sys/devices",
 628
 629 "--ro-bind-try", "/usr/share", "/usr/share",
 630 "--ro-bind-try", "/usr/local/share", "/usr/local/share",
 631 "--ro-bind-try", DATADIR, DATADIR,
 632
 633 // We only grant access to the libdirs webkit is built with and
 634 // guess system libdirs. This will always have some edge cases.
 635 "--ro-bind-try", "/lib", "/lib",
 636 "--ro-bind-try", "/usr/lib", "/usr/lib",
 637 "--ro-bind-try", "/usr/local/lib", "/usr/local/lib",
 638 "--ro-bind-try", LIBDIR, LIBDIR,
 639 "--ro-bind-try", "/lib64", "/lib64",
 640 "--ro-bind-try", "/usr/lib64", "/usr/lib64",
 641 "--ro-bind-try", "/usr/local/lib64", "/usr/local/lib64",
 642
 643 "--ro-bind-try", PKGLIBEXECDIR, PKGLIBEXECDIR,
 644
 645 "--setenv", "GTK_USE_PORTAL", "1",
 646
 647 "--bind-try", configDir.get(), configDir.get(),
 648 };
 649 // We would have to parse ld config files for more info.
 650 bindPathVar(sandboxArgs, "LD_LIBRARY_PATH");
 651
 652 if (launchOptions.processType == ProcessLauncher::ProcessType::Network) {
 653 static XDGDBusProxyLauncher proxy;
 654
 655 // FIXME: The network process is used for `file://` URIs and
 656 // we would have to pass through most paths for this to work.
 657
 658 // FIXME: HTTP credentials talks to libsecret.
 659
 660 // glib-networking can use dbus for proxy information.
 661 // FIXME: Find and add the permissions it needs for this (pacrunner).
 662 bindDBusSession(sandboxArgs, proxy);
 663
 664 if (!proxy.isRunning())
 665 proxy.launch();
 666 }
 667
 668 // NOTE: This has network access for HLS via GStreamer.
 669 if (launchOptions.processType == ProcessLauncher::ProcessType::Web) {
 670 static XDGDBusProxyLauncher proxy;
 671
 672 // If Wayland in use don't grant X11
 673#if PLATFORM(WAYLAND) && USE(EGL)
 674 if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland) {
 675 bindWayland(sandboxArgs);
 676 sandboxArgs.append("--unshare-ipc");
 677 } else
 678#endif
 679 bindX11(sandboxArgs);
 680
 681 bindDBusSession(sandboxArgs, proxy);
 682 // FIXME: This needs to be restricted, upstream is working on it.
 683 bindDconf(sandboxArgs);
 684 // FIXME: We should move to Pipewire as soon as viable, Pulse doesn't restrict clients atm.
 685 bindPulse(sandboxArgs);
 686 bindFonts(sandboxArgs);
 687 bindGStreamerData(sandboxArgs);
 688 bindOpenGL(sandboxArgs);
 689 // FIXME: This is also fixed by Pipewire once in use.
 690 bindV4l(sandboxArgs);
 691#if PLATFORM(GTK)
 692 bindA11y(sandboxArgs);
 693 bindGtkData(sandboxArgs);
 694#endif
 695
 696 if (!proxy.isRunning()) {
 697 proxy.setPermissions({
 698 // FIXME: Used by GTK on Wayland.
 699 "--talk=ca.desrt.dconf",
 700 // xdg-desktop-portal used by GTK and us.
 701 "--talk=org.freedesktop.portal.Desktop",
 702 // GStreamers plugin install helper.
 703 "--call=org.freedesktop.PackageKit=org.freedesktop.PackageKit.Modify2.InstallGStreamerResources@/org/freedesktop/PackageKit"
 704 });
 705 proxy.launch();
 706 }
 707
 708
 709 } else {
 710 // Only X11 users need this for XShm which is only the Web process.
 711 sandboxArgs.append("--unshare-ipc");
 712 }
 713
 714 // Only process without any network access for now.
 715 if (launchOptions.processType == ProcessLauncher::ProcessType::Storage)
 716 sandboxArgs.append("--unshare-net");
 717
 718#if ENABLE(DEVELOPER_MODE)
 719 const char* execDirectory = g_getenv("WEBKIT_EXEC_PATH");
 720 if (execDirectory) {
 721 String parentDir = FileSystem::directoryName(FileSystem::stringFromFileSystemRepresentation(execDirectory));
 722 bindIfExists(sandboxArgs, parentDir.utf8().data());
 723 }
 724
 725 CString executablePath = getCurrentExecutablePath();
 726 if (!executablePath.isNull()) {
 727 // Our executable is `/foo/bar/bin/Process`, we want `/foo/bar` as a usable prefix
 728 String parentDir = FileSystem::directoryName(FileSystem::directoryName(FileSystem::stringFromFileSystemRepresentation(executablePath.data())));
 729 bindIfExists(sandboxArgs, parentDir.utf8().data());
 730 }
 731#endif
 732
 733 int seccompFd = setupSeccomp();
 734 GUniquePtr<char> fdStr(g_strdup_printf("%d", seccompFd));
 735 g_subprocess_launcher_take_fd(launcher.get(), seccompFd, seccompFd);
 736 sandboxArgs.appendVector(Vector<CString>({ "--seccomp", fdStr.get() }));
 737
 738 for (const String& path : launchOptions.extraSandboxPaths) {
 739 if (path.isEmpty())
 740 g_warning("Empty path passed to sandbox, this is probably a bug");
 741 else if (!FileSystem::makeAllDirectories(path)) // FIXME: Blocking
 742 g_warning("Could not create directory \"%s\": %s", path.utf8().data(), g_strerror(errno));
 743 else
 744 sandboxArgs.appendVector(Vector<CString>({ "--bind", path.utf8(), path.utf8() }));
 745 }
 746
 747 int bwrapFd = argsToFd(sandboxArgs, "bwrap");
 748 GUniquePtr<char> bwrapFdStr(g_strdup_printf("%d", bwrapFd));
 749 g_subprocess_launcher_take_fd(launcher.get(), bwrapFd, bwrapFd);
 750
 751 Vector<CString> bwrapArgs = {
 752 BWRAP_EXECUTABLE,
 753 "--args",
 754 bwrapFdStr.get(),
 755 "--",
 756 };
 757
 758 char** newArgv = g_newa(char*, g_strv_length(argv) + bwrapArgs.size() + 1);
 759 size_t i = 0;
 760
 761 for (auto& arg : bwrapArgs)
 762 newArgv[i++] = const_cast<char*>(arg.data());
 763 for (size_t x = 0; argv[x]; x++)
 764 newArgv[i++] = argv[x];
 765 newArgv[i++] = nullptr;
 766
 767 return adoptGRef(g_subprocess_launcher_spawnv(launcher.get(), newArgv, error));
 768}
 769
 770};
 771
 772#endif // ENABLE(BUBBLEWRAP_SANDBOX)

Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.h

 1/*
 2 * Copyright (C) 2018 Igalia S.L.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#if ENABLE(BUBBLEWRAP_SANDBOX)
 29
 30#include "ProcessLauncher.h"
 31
 32#include <glib.h>
 33
 34namespace WebKit {
 35
 36GRefPtr<GSubprocess> bubblewrapSpawn(GRefPtr<GSubprocessLauncher>, const ProcessLauncher::LaunchOptions&, char** argv, GError**);
 37
 38};
 39
 40#endif

Source/WebKit/UIProcess/Launcher/glib/FlatpakLauncher.cpp

 1/*
 2 * Copyright (C) 2018 Igalia S.L.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "FlatpakLauncher.h"
 28
 29#if OS(LINUX)
 30
 31namespace WebKit {
 32
 33GRefPtr<GSubprocess> flatpakSpawn(GRefPtr<GSubprocessLauncher>& launcher, const WebKit::ProcessLauncher::LaunchOptions& launchOptions, char** argv, GError **error)
 34{
 35 // When we are running inside of flatpak's sandbox we do not have permissions to
 36 // use the same sandbox we do outside but flatpak offers to create new sandboxes
 37 // for us using flatpak-spawn.
 38 //
 39 // This is extremely bare-bones atm though as the Spawn interface does not expose
 40 // much outside of `--sandbox` (no permissions) and `--no-network`. We need to
 41 // add some permissions in between those for this to provide meaningful security.
 42
 43 Vector<const char*> flatpakArgs = {
 44 "/usr/bin/flatpak-spawn",
 45 };
 46
 47 if (launchOptions.processType == WebKit::ProcessLauncher::ProcessType::Storage)
 48 flatpakArgs.append("--no-network");
 49
 50 char** newArgv = g_newa(char*, g_strv_length(argv) + flatpakArgs.size() + 1);
 51 size_t i = 0;
 52
 53 for (const auto& arg : flatpakArgs)
 54 newArgv[i++] = const_cast<char*>(arg);
 55 for (size_t x = 0; argv[x]; x++)
 56 newArgv[i++] = argv[x];
 57 newArgv[i++] = nullptr;
 58
 59 return adoptGRef(g_subprocess_launcher_spawnv(launcher.get(), newArgv, error));
 60}
 61
 62};
 63
 64#endif // OS(LINUX)

Source/WebKit/UIProcess/Launcher/glib/FlatpakLauncher.h

 1/*
 2 * Copyright (C) 2018 Igalia S.L.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#if OS(LINUX)
 29
 30#include "ProcessLauncher.h"
 31
 32#include <glib.h>
 33
 34namespace WebKit {
 35
 36GRefPtr<GSubprocess> flatpakSpawn(GRefPtr<GSubprocessLauncher>&, const WebKit::ProcessLauncher::LaunchOptions&, char** argv, GError**);
 37
 38};
 39
 40#endif

Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp

2727#include "config.h"
2828#include "ProcessLauncher.h"
2929
 30#include "BubblewrapLauncher.h"
3031#include "Connection.h"
 32#include "FlatpakLauncher.h"
3133#include "ProcessExecutablePath.h"
3234#include <WebCore/FileSystem.h>
3335#include <errno.h>

@@static void childSetupFunction(gpointer userData)
5355 close(socket);
5456}
5557
56 void ProcessLauncher::launchProcess()
 58#if OS(LINUX)
 59static bool isInsideFlatpak()
5760{
58  GPid pid = 0;
 61 static int ret = -1;
 62 if (ret != -1)
 63 return ret;
 64
 65 GUniquePtr<GKeyFile> infoFile(g_key_file_new());
 66 if (!g_key_file_load_from_file(infoFile.get(), "/.flatpak-info", G_KEY_FILE_NONE, nullptr)) {
 67 ret = false;
 68 return ret;
 69 }
5970
 71 // If we are in a `flatpak build` session we cannot launch ourselves since we aren't installed.
 72 ret = !g_key_file_get_boolean(infoFile.get(), "Instance", "build", nullptr);
 73 return ret;
 74}
 75#endif
 76
 77void ProcessLauncher::launchProcess()
 78{
6079 IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection(IPC::Connection::ConnectionOptions::SetCloexecOnServer);
6180
6281 String executablePath;

@@void ProcessLauncher::launchProcess()
143162#endif
144163 argv[i++] = nullptr;
145164
 165 GRefPtr<GSubprocessLauncher> launcher = adoptGRef(g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_INHERIT_FDS));
 166 g_subprocess_launcher_set_child_setup(launcher.get(), childSetupFunction, GINT_TO_POINTER(socketPair.server), nullptr);
 167 g_subprocess_launcher_take_fd(launcher.get(), socketPair.client, socketPair.client);
 168
146169 GUniqueOutPtr<GError> error;
147  if (!g_spawn_async(nullptr, argv, nullptr, G_SPAWN_LEAVE_DESCRIPTORS_OPEN, childSetupFunction, GINT_TO_POINTER(socketPair.server), &pid, &error.outPtr()))
 170 GRefPtr<GSubprocess> process;
 171#if OS(LINUX)
 172 const char* sandboxEnv = g_getenv("WEBKIT_FORCE_SANDBOX");
 173 bool sandboxEnabled = m_launchOptions.sandboxEnabled;
 174
 175 if (sandboxEnv)
 176 sandboxEnabled = !strcmp(sandboxEnv, "1");
 177
 178 if (sandboxEnabled && isInsideFlatpak())
 179 process = flatpakSpawn(launcher, m_launchOptions, argv, &error.outPtr());
 180#if ENABLE(BUBBLEWRAP_SANDBOX)
 181 else if (sandboxEnabled)
 182 process = bubblewrapSpawn(launcher, m_launchOptions, argv, &error.outPtr());
 183#endif
 184 else
 185#endif
 186 process = adoptGRef(g_subprocess_launcher_spawnv(launcher.get(), argv, &error.outPtr()));
 187
 188 if (!process.get())
148189 g_error("Unable to fork a new child process: %s", error->message);
149190
 191 const char* processIdStr = g_subprocess_get_identifier(process.get());
 192 m_processIdentifier = g_ascii_strtoll(processIdStr, nullptr, 0);
 193 RELEASE_ASSERT(m_processIdentifier);
 194
150195 // Don't expose the parent socket to potential future children.
151196 if (!setCloseOnExec(socketPair.client))
152197 RELEASE_ASSERT_NOT_REACHED();
153198
154  close(socketPair.client);
155  m_processIdentifier = pid;
156 
157199 // We've finished launching the process, message back to the main run loop.
158200 RunLoop::main().dispatch([protectedThis = makeRef(*this), this, serverSocket = socketPair.server] {
159201 didFinishLaunchingProcess(m_processIdentifier, serverSocket);

Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp

@@void NetworkProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launc
108108 }
109109}
110110
 111#if !PLATFORM(GTK) && !PLATFORM(WPE)
 112void NetworkProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
 113{
 114}
 115#endif
 116
 117
111118void NetworkProcessProxy::connectionWillOpen(IPC::Connection& connection)
112119{
113120#if ENABLE(SEC_ITEM_SHIM)

Source/WebKit/UIProcess/Network/NetworkProcessProxy.h

@@private:
112112
113113 // ChildProcessProxy
114114 void getLaunchOptions(ProcessLauncher::LaunchOptions&) override;
 115 void platformGetLaunchOptions(ProcessLauncher::LaunchOptions&) override;
115116 void connectionWillOpen(IPC::Connection&) override;
116117 void processWillShutDown(IPC::Connection&) override;
117118

Source/WebKit/UIProcess/Plugins/PluginProcessProxy.cpp

@@PluginProcessProxy::~PluginProcessProxy()
8787
8888void PluginProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
8989{
90  platformGetLaunchOptions(launchOptions, m_pluginProcessAttributes);
 90 platformGetLaunchOptionsWithAttributes(launchOptions, m_pluginProcessAttributes);
9191 ChildProcessProxy::getLaunchOptions(launchOptions);
9292}
9393

Source/WebKit/UIProcess/Plugins/PluginProcessProxy.h

@@private:
9696 PluginProcessProxy(PluginProcessManager*, const PluginProcessAttributes&, uint64_t pluginProcessToken);
9797
9898 void getLaunchOptions(ProcessLauncher::LaunchOptions&) override;
99  void platformGetLaunchOptions(ProcessLauncher::LaunchOptions&, const PluginProcessAttributes&);
 99 void platformGetLaunchOptionsWithAttributes(ProcessLauncher::LaunchOptions&, const PluginProcessAttributes&);
100100 void processWillShutDown(IPC::Connection&) override;
101101
102102 void pluginProcessCrashedOrFailedToLaunch();

Source/WebKit/UIProcess/Plugins/mac/PluginProcessProxyMac.mm

@@namespace WebKit {
6060using namespace WebCore;
6161
6262
63 void PluginProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions, const PluginProcessAttributes& pluginProcessAttributes)
 63void PluginProcessProxy::platformGetLaunchOptionsWithAttributes(ProcessLauncher::LaunchOptions& launchOptions, const PluginProcessAttributes& pluginProcessAttributes)
6464{
6565 if (pluginProcessAttributes.moduleInfo.pluginArchitecture == CPU_TYPE_X86)
6666 launchOptions.processType = ProcessLauncher::ProcessType::Plugin32;

Source/WebKit/UIProcess/Plugins/unix/PluginProcessProxyUnix.cpp

5050namespace WebKit {
5151using namespace WebCore;
5252
53 void PluginProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions, const PluginProcessAttributes& pluginProcessAttributes)
 53void PluginProcessProxy::platformGetLaunchOptionsWithAttributes(ProcessLauncher::LaunchOptions& launchOptions, const PluginProcessAttributes& pluginProcessAttributes)
5454{
5555 launchOptions.processType = ProcessLauncher::ProcessType::Plugin64;
5656

Source/WebKit/UIProcess/Storage/StorageProcessProxy.cpp

@@void StorageProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launc
8888 ChildProcessProxy::getLaunchOptions(launchOptions);
8989}
9090
 91#if !PLATFORM(GTK) && !PLATFORM(WPE)
 92void StorageProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
 93{
 94}
 95#endif
 96
9197void StorageProcessProxy::processWillShutDown(IPC::Connection& connection)
9298{
9399 ASSERT_UNUSED(connection, this->connection() == &connection);

Source/WebKit/UIProcess/Storage/StorageProcessProxy.h

@@private:
6565
6666 // ChildProcessProxy
6767 void getLaunchOptions(ProcessLauncher::LaunchOptions&) override;
 68 void platformGetLaunchOptions(ProcessLauncher::LaunchOptions&) override;
6869 void processWillShutDown(IPC::Connection&) override;
6970
7071 // IPC::Connection::Client

Source/WebKit/UIProcess/WebProcessPool.h

@@public:
461461
462462 void sendDisplayConfigurationChangedMessageForTesting();
463463
 464#if PLATFORM(GTK) || PLATFORM(WPE)
 465 void setSandboxEnabled(bool enabled) { m_sandboxEnabled = enabled; };
 466 bool sandboxEnabled() const { return m_sandboxEnabled; };
 467#endif
 468
464469private:
465470 void platformInitialize();
466471

@@private:
705710
706711 HashMap<WebCore::SecurityOriginData, Vector<SuspendedPageProxy*>> m_suspendedPages;
707712 HashMap<String, RefPtr<WebProcessProxy>> m_swappedProcessesPerRegistrableDomain;
 713
 714#if PLATFORM(GTK) || PLATFORM(WPE)
 715 bool m_sandboxEnabled { false };
 716#endif
708717};
709718
710719template<typename T>

Source/WebKit/UIProcess/WebProcessProxy.cpp

@@void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOpt
197197 }
198198}
199199
 200#if !PLATFORM(GTK) && !PLATFORM(WPE)
 201void WebProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
 202{
 203}
 204#endif
 205
200206void WebProcessProxy::connectionWillOpen(IPC::Connection& connection)
201207{
202208 ASSERT(this->connection() == &connection);

Source/WebKit/UIProcess/WebProcessProxy.h

@@protected:
236236
237237 // ChildProcessProxy
238238 void getLaunchOptions(ProcessLauncher::LaunchOptions&) override;
 239 void platformGetLaunchOptions(ProcessLauncher::LaunchOptions&) override;
239240 void connectionWillOpen(IPC::Connection&) override;
240241 void processWillShutDown(IPC::Connection&) override;
241242

Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp

@@void WebsiteDataStore::resolveDirectoriesIfNecessary()
178178 m_resolvedConfiguration.javaScriptConfigurationDirectory = resolvePathForSandboxExtension(m_configuration.javaScriptConfigurationDirectory);
179179 if (!m_configuration.cacheStorageDirectory.isEmpty() && m_resolvedConfiguration.cacheStorageDirectory.isEmpty())
180180 m_resolvedConfiguration.cacheStorageDirectory = resolvePathForSandboxExtension(m_configuration.cacheStorageDirectory);
 181 if (!m_configuration.networkCacheDirectory.isEmpty())
 182 m_resolvedConfiguration.networkCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.networkCacheDirectory);
 183 if (!m_configuration.localStorageDirectory.isEmpty())
 184 m_resolvedConfiguration.localStorageDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.localStorageDirectory);
181185
182186 // Resolve directories for file paths.
183187 if (!m_configuration.cookieStorageFile.isEmpty()) {

Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h

@@public:
154154 const String& resolvedIndexedDatabaseDirectory() const { return m_resolvedConfiguration.indexedDBDatabaseDirectory; }
155155 const String& resolvedServiceWorkerRegistrationDirectory() const { return m_resolvedConfiguration.serviceWorkerRegistrationDirectory; }
156156 const String& resolvedResourceLoadStatisticsDirectory() const { return m_resolvedConfiguration.resourceLoadStatisticsDirectory; }
 157 const String& resolvedNetworkCacheDirectory() const { return m_resolvedConfiguration.networkCacheDirectory; }
 158 const String& resolvedLocalStorageDirectory() const { return m_resolvedConfiguration.localStorageDirectory; }
 159
157160
158161 StorageManager* storageManager() { return m_storageManager.get(); }
159162

Source/WebKit/UIProcess/glib/NetworkProcessProxyGLib.cpp

 1/*
 2 * Copyright (C) 2018 S.L. Igalia
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "NetworkProcessProxy.h"
 28
 29namespace WebKit {
 30
 31void NetworkProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
 32{
 33 WebsiteDataStore& store = processPool().websiteDataStore()->websiteDataStore();
 34 store.resolveDirectoriesIfNecessary();
 35 launchOptions.extraSandboxPaths.append(store.resolvedNetworkCacheDirectory());
 36
 37 launchOptions.sandboxEnabled = m_processPool.sandboxEnabled();
 38}
 39
 40};

Source/WebKit/UIProcess/glib/StorageProcessProxyGLib.cpp

 1/*
 2 * Copyright (C) 2018 S.L. Igalia
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "StorageProcessProxy.h"
 28
 29namespace WebKit {
 30
 31void StorageProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
 32{
 33 launchOptions.sandboxEnabled = m_processPool.sandboxEnabled();
 34
 35 WebsiteDataStore& store = m_processPool.websiteDataStore()->websiteDataStore();
 36 store.resolveDirectoriesIfNecessary();
 37 launchOptions.extraSandboxPaths.append(store.resolvedIndexedDatabaseDirectory());
 38}
 39
 40};

Source/WebKit/UIProcess/glib/WebProcessProxyGLib.cpp

 1/*
 2 * Copyright (C) 2018 S.L. Igalia
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "WebProcessProxy.h"
 28
 29#if PLATFORM(WAYLAND) && USE(EGL)
 30#include "WaylandCompositor.h"
 31#endif
 32#include "WebProcessPool.h"
 33#include "WebsiteDataStore.h"
 34#include <WebCore/FileSystem.h>
 35#include <WebCore/PlatformDisplay.h>
 36
 37namespace WebKit {
 38using namespace WebCore;
 39
 40void WebProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
 41{
 42 launchOptions.sandboxEnabled = m_processPool->sandboxEnabled();
 43
 44 websiteDataStore().resolveDirectoriesIfNecessary();
 45 launchOptions.extraSandboxPaths.append(websiteDataStore().resolvedNetworkCacheDirectory());
 46 launchOptions.extraSandboxPaths.append(websiteDataStore().resolvedApplicationCacheDirectory());
 47
 48#if PLATFORM(WAYLAND) && USE(EGL)
 49 if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland) {
 50 String displayName = WaylandCompositor::singleton().displayName();
 51 String runtimeDir(g_get_user_runtime_dir());
 52 String waylandSocket = FileSystem::pathByAppendingComponent(runtimeDir, displayName);
 53 launchOptions.extraSandboxPaths.append(waylandSocket);
 54 }
 55#endif
 56}
 57
 58};

Source/cmake/FindLibseccomp.cmake

 1# - Try to find libseccomp
 2# Once done, this will define
 3#
 4# LIBSECCOMP_FOUND - system has libseccomp
 5# LIBSECCOMP_INCLUDE_DIRS - the libseccomp include drectories
 6# LIBSECCOMP_LIBRARIES - link these to use libseccomp
 7#
 8# Copyright (C) 2018 Igalia S.L.
 9#
 10# Redistribution and use in source and binary forms, with or without
 11# modification, are permitted provided that the following conditions
 12# are met:
 13# 1. Redistributions of source code must retain the above copyright
 14# notice, this list of conditions and the following disclaimer.
 15# 2. Redistributions in binary form must reproduce the above copyright
 16# notice, this list of conditions and the following disclaimer in the
 17# documentation and/or other materials provided with the distribution.
 18#
 19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
 20# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 21# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 22# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
 23# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 24# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 25# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 26# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 27# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 28# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 29# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 30
 31find_package(PkgConfig)
 32pkg_check_modules(PC_LIBSECCOMP libseccomp)
 33
 34find_path(LIBSECCOMP_INCLUDE_DIRS
 35 NAMES seccomp.h
 36 HINTS ${PC_LIBSECCOMP_INCLUDEDIR}
 37)
 38
 39find_library(LIBSECCOMP_LIBRARIES
 40 NAMES seccomp
 41 HINTS ${PC_LIBSECCOMP_LIBDIR}
 42)
 43
 44include(FindPackageHandleStandardArgs)
 45find_package_handle_standard_args(LIBSECCOMP
 46 REQUIRED_VARS LIBSECCOMP_LIBRARIES
 47 FOUND_VAR LIBSECCOMP_FOUND
 48 VERSION_VAR PC_LIBSECCOMP_VERSION)
 49
 50mark_as_advanced(
 51 LIBSECCOMP_INCLUDE_DIRS
 52 LIBSECCOMP_LIBRARIES
 53)

Source/cmake/OptionsGTK.cmake

@@else ()
118118 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_RESOURCE_USAGE PRIVATE OFF)
119119endif ()
120120
 121if (CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT EXISTS "/.flatpak-info")
 122 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_BUBBLEWRAP_SANDBOX PUBLIC ON)
 123else ()
 124 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_BUBBLEWRAP_SANDBOX PRIVATE OFF)
 125endif ()
 126
121127# Public options shared with other WebKit ports. Do not add any options here
122128# without approval from a GTK+ reviewer. There must be strong reason to support
123129# changing the value of the option.

@@if (ENABLE_ACCELERATED_2D_CANVAS)
201207 endif ()
202208endif ()
203209
 210if (ENABLE_BUBBLEWRAP_SANDBOX)
 211 find_program(BWRAP_EXECUTABLE bwrap)
 212 if (NOT BWRAP_EXECUTABLE)
 213 message(FATAL_ERROR "bwrap executable is needed for ENABLE_BUBBLEWRAP_SANDBOX")
 214 endif ()
 215 add_definitions(-DBWRAP_EXECUTABLE="${BWRAP_EXECUTABLE}")
 216
 217 execute_process(
 218 COMMAND "${BWRAP_EXECUTABLE}" --version
 219 RESULT_VARIABLE BWRAP_RET
 220 OUTPUT_VARIABLE BWRAP_OUTPUT
 221 )
 222 if (BWRAP_RET)
 223 message(FATAL_ERROR "Failed to run ${BWRAP_EXECUTABLE}")
 224 endif ()
 225 string(REGEX MATCH "([0-9]+.[0-9]+.[0-9]+)" BWRAP_VERSION "${BWRAP_OUTPUT}")
 226 if (NOT "${BWRAP_VERSION}" VERSION_GREATER_EQUAL "0.3.1")
 227 message(FATAL_ERROR "bwrap must be >= 0.3.1 but ${BWRAP_VERSION} found")
 228 endif ()
 229
 230 find_package(Libseccomp)
 231 if (NOT LIBSECCOMP_FOUND)
 232 message(FATAL_ERROR "libseccomp is needed for ENABLE_BUBBLEWRAP_SANDBOX")
 233 endif ()
 234
 235 find_program(DBUS_PROXY_EXECUTABLE xdg-dbus-proxy)
 236 if (NOT DBUS_PROXY_EXECUTABLE)
 237 message(FATAL_ERROR "xdg-dbus-proxy not found and is needed for ENABLE_BUBBLEWRAP_SANDBOX")
 238 endif ()
 239 add_definitions(-DDBUS_PROXY_EXECUTABLE="${DBUS_PROXY_EXECUTABLE}")
 240endif ()
 241
204242if (USE_LIBSECRET)
205243 find_package(Libsecret)
206244 if (NOT LIBSECRET_FOUND)

Source/cmake/WebKitFeatures.cmake

@@macro(WEBKIT_OPTION_BEGIN)
8585 WEBKIT_OPTION_DEFINE(ENABLE_ASYNC_SCROLLING "Enable asynchronouse scrolling" PRIVATE OFF)
8686 WEBKIT_OPTION_DEFINE(ENABLE_ATTACHMENT_ELEMENT "Toggle attachment element support" PRIVATE OFF)
8787 WEBKIT_OPTION_DEFINE(ENABLE_AVF_CAPTIONS "Toggle AVFoundation caption support" PRIVATE OFF)
 88 WEBKIT_OPTION_DEFINE(ENABLE_BUBBLEWRAP_SANDBOX "Toggle bubblewrap sandboxing support" PRIVATE OFF)
8889 WEBKIT_OPTION_DEFINE(ENABLE_CACHE_PARTITIONING "Toggle cache partitioning support" PRIVATE OFF)
8990 WEBKIT_OPTION_DEFINE(ENABLE_CHANNEL_MESSAGING "Toggle MessageChannel and MessagePort support" PRIVATE ON)
9091 WEBKIT_OPTION_DEFINE(ENABLE_CONTENT_FILTERING "Toggle content filtering support" PRIVATE OFF)

ChangeLog

 12018-09-21 Patrick Griffis <pgriffis@igalia.com>
 2
 3 [GTK][WPE] Implement subprocess sandboxing
 4 https://bugs.webkit.org/show_bug.cgi?id=188568
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Add ENABLE_BUBBLEWRAP_SANDBOX option for sandboxing.
 9
 10 * Source/cmake/FindLibseccomp.cmake: Added.
 11 * Source/cmake/OptionsGTK.cmake:
 12 * Source/cmake/WebKitFeatures.cmake:
 13
1142018-09-12 Dan Bernstein <mitz@apple.com>
215
316 Updated svn:ignore after r235381.