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_FORCE_SANDBOX 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
8587void ChildProcessProxy::connect()

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 if (proxy.proxyPath().data()) {
 245 args.appendVector(Vector<CString>({
 246 "--bind", proxy.proxyPath(), proxy.path(),
 247 }));
 248 }
 249}
 250
 251static void bindX11(Vector<CString>& args)
 252{
 253 const char* display = g_getenv("DISPLAY");
 254 if (!display || display[0] != ':' || !g_ascii_isdigit(const_cast<char*>(display)[1]))
 255 display = ":0";
 256 GUniquePtr<char> x11File(g_strdup_printf("/tmp/.X11-unix/X%s", display + 1));
 257 bindIfExists(args, x11File.get(), BindFlags::ReadWrite);
 258
 259 const char* xauth = g_getenv("XAUTHORITY");
 260 if (!xauth) {
 261 const char* homeDir = g_get_home_dir();
 262 GUniquePtr<char> xauthFile(g_build_filename(homeDir, ".Xauthority", nullptr));
 263 bindIfExists(args, xauthFile.get());
 264 } else
 265 bindIfExists(args, xauth);
 266}
 267
 268static void bindDconf(Vector<CString>& args)
 269{
 270 const char* runtimeDir = g_get_user_runtime_dir();
 271 GUniquePtr<char> dconfRuntimeDir(g_build_filename(runtimeDir, "dconf", nullptr));
 272 args.appendVector(Vector<CString>({ "--bind", dconfRuntimeDir.get(), dconfRuntimeDir.get() }));
 273
 274 const char* dconfDir = g_getenv("DCONF_USER_CONFIG_DIR");
 275 if (dconfDir)
 276 bindIfExists(args, dconfDir);
 277 else {
 278 const char* configDir = g_get_user_config_dir();
 279 GUniquePtr<char> dconfConfigDir(g_build_filename(configDir, "dconf", nullptr));
 280 bindIfExists(args, dconfConfigDir.get(), BindFlags::ReadWrite);
 281 }
 282}
 283
 284static void bindWayland(Vector<CString>& args)
 285{
 286 const char* display = g_getenv("WAYLAND_DISPLAY");
 287 if (!display)
 288 display = "wayland-0";
 289
 290 const char* runtimeDir = g_get_user_runtime_dir();
 291 GUniquePtr<char> waylandRuntimeFile(g_build_filename(runtimeDir, display, nullptr));
 292 bindIfExists(args, waylandRuntimeFile.get(), BindFlags::ReadWrite);
 293}
 294
 295static void bindPulse(Vector<CString>& args)
 296{
 297 // FIXME: The server can be defined in config files we'd have to parse.
 298 // They can also be set as X11 props but that is getting a bit ridiculous.
 299 const char* pulseServer = g_getenv("PULSE_SERVER");
 300 if (pulseServer) {
 301 if (g_str_has_prefix(pulseServer, "unix:"))
 302 bindIfExists(args, pulseServer + 5, BindFlags::ReadWrite);
 303 // else it uses tcp
 304 } else {
 305 const char* runtimeDir = g_get_user_runtime_dir();
 306 GUniquePtr<char> pulseRuntimeDir(g_build_filename(runtimeDir, "pulse", nullptr));
 307 bindIfExists(args, pulseRuntimeDir.get(), BindFlags::ReadWrite);
 308 }
 309
 310 const char* pulseConfig = g_getenv("PULSE_CLIENTCONFIG");
 311 if (pulseConfig)
 312 bindIfExists(args, pulseConfig);
 313
 314 const char* configDir = g_get_user_config_dir();
 315 GUniquePtr<char> pulseConfigDir(g_build_filename(configDir, "pulse", nullptr));
 316 bindIfExists(args, pulseConfigDir.get());
 317
 318 const char* homeDir = g_get_home_dir();
 319 GUniquePtr<char> pulseHomeConfigDir(g_build_filename(homeDir, ".pulse", nullptr));
 320 GUniquePtr<char> asoundHomeConfigDir(g_build_filename(homeDir, ".asoundrc", nullptr));
 321 bindIfExists(args, pulseHomeConfigDir.get());
 322 bindIfExists(args, asoundHomeConfigDir.get());
 323
 324 // This is the ultimate fallback to raw ALSA
 325 bindIfExists(args, "/dev/snd", BindFlags::Device);
 326}
 327
 328static void bindFonts(Vector<CString>& args)
 329{
 330 const char* configDir = g_get_user_config_dir();
 331 const char* homeDir = g_get_home_dir();
 332 const char* dataDir = g_get_user_data_dir();
 333 const char* cacheDir = g_get_user_cache_dir();
 334
 335 // Configs can include custom dirs but then we have to parse them...
 336 GUniquePtr<char> fontConfig(g_build_filename(configDir, "fontconfig", nullptr));
 337 GUniquePtr<char> fontCache(g_build_filename(cacheDir, "fontconfig", nullptr));
 338 GUniquePtr<char> fontHomeConfig(g_build_filename(homeDir, ".fonts.conf", nullptr));
 339 GUniquePtr<char> fontHomeConfigDir(g_build_filename(configDir, ".fonts.conf.d", nullptr));
 340 GUniquePtr<char> fontData(g_build_filename(dataDir, "fonts", nullptr));
 341 GUniquePtr<char> fontHomeData(g_build_filename(homeDir, ".fonts", nullptr));
 342 bindIfExists(args, fontConfig.get());
 343 bindIfExists(args, fontCache.get(), BindFlags::ReadWrite);
 344 bindIfExists(args, fontHomeConfig.get());
 345 bindIfExists(args, fontHomeConfigDir.get());
 346 bindIfExists(args, fontData.get());
 347 bindIfExists(args, fontHomeData.get());
 348}
 349
 350#if PLATFORM(GTK)
 351static void bindGtkData(Vector<CString>& args)
 352{
 353 const char* configDir = g_get_user_config_dir();
 354 const char* dataDir = g_get_user_data_dir();
 355 const char* homeDir = g_get_home_dir();
 356
 357 GUniquePtr<char> gtkConfig(g_build_filename(configDir, "gtk-3.0", nullptr));
 358 GUniquePtr<char> themeData(g_build_filename(dataDir, "themes", nullptr));
 359 GUniquePtr<char> themeHomeData(g_build_filename(homeDir, ".themes", nullptr));
 360 GUniquePtr<char> iconHomeData(g_build_filename(homeDir, ".icons", nullptr));
 361 bindIfExists(args, gtkConfig.get());
 362 bindIfExists(args, themeData.get());
 363 bindIfExists(args, themeHomeData.get());
 364 bindIfExists(args, iconHomeData.get());
 365}
 366
 367static void bindA11y(Vector<CString>& args)
 368{
 369 static XDGDBusProxyLauncher proxy;
 370
 371 if (!proxy.isRunning()) {
 372 // FIXME: Avoid blocking IO... (It is at least a one-time cost)
 373 GRefPtr<GDBusConnection> sessionBus = adoptGRef(g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr));
 374 if (!sessionBus.get())
 375 return;
 376
 377 GRefPtr<GDBusMessage> msg = adoptGRef(g_dbus_message_new_method_call(
 378 "org.a11y.Bus", "/org/a11y/bus", "org.a11y.Bus", "GetAddress"));
 379 g_dbus_message_set_body(msg.get(), g_variant_new("()"));
 380 GRefPtr<GDBusMessage> reply = adoptGRef(g_dbus_connection_send_message_with_reply_sync(
 381 sessionBus.get(), msg.get(),
 382 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
 383 30000,
 384 nullptr,
 385 nullptr,
 386 nullptr));
 387
 388 if (reply.get()) {
 389 GUniqueOutPtr<GError> error;
 390 if (g_dbus_message_to_gerror(reply.get(), &error.outPtr())) {
 391 if (!g_error_matches(error.get(), G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))
 392 g_warning("Can't find a11y bus: %s", error->message);
 393 } else {
 394 GUniqueOutPtr<char> a11yAddress;
 395 g_variant_get(g_dbus_message_get_body(reply.get()), "(s)", &a11yAddress.outPtr());
 396 proxy.setAddress(a11yAddress.get(), DBusAddressType::Abstract);
 397 }
 398 }
 399
 400 proxy.setPermissions({
 401 "--sloppy-names",
 402 "--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Embed@/org/a11y/atspi/accessible/root",
 403 "--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Unembed@/org/a11y/atspi/accessible/root",
 404 "--call=org.a11y.atspi.Registry=org.a11y.atspi.Registry.GetRegisteredEvents@/org/a11y/atspi/registry",
 405 "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetKeystrokeListeners@/org/a11y/atspi/registry/deviceeventcontroller",
 406 "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetDeviceEventListeners@/org/a11y/atspi/registry/deviceeventcontroller",
 407 "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersSync@/org/a11y/atspi/registry/deviceeventcontroller",
 408 "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersAsync@/org/a11y/atspi/registry/deviceeventcontroller",
 409 });
 410
 411 proxy.launch();
 412 }
 413
 414 if (proxy.proxyPath().data()) {
 415 args.appendVector(Vector<CString>({
 416 "--bind", proxy.proxyPath(), proxy.path(),
 417 }));
 418 }
 419}
 420#endif
 421
 422static bool bindPathVar(Vector<CString>& args, const char* varname)
 423{
 424 const char* pathValue = g_getenv(varname);
 425 if (!pathValue)
 426 return false;
 427
 428 GUniquePtr<char*> splitPaths(g_strsplit(pathValue, ":", -1));
 429 for (size_t i; splitPaths.get()[i]; ++i)
 430 bindIfExists(args, splitPaths.get()[i]);
 431
 432 return true;
 433}
 434
 435static void bindGStreamerData(Vector<CString>& args)
 436{
 437 if (!bindPathVar(args, "GST_PLUGIN_PATH_1_0"))
 438 bindPathVar(args, "GST_PLUGIN_PATH");
 439
 440 if (!bindPathVar(args, "GST_PLUGIN_SYSTEM_PATH_1_0")) {
 441 if (!bindPathVar(args, "GST_PLUGIN_SYSTEM_PATH")) {
 442 GUniquePtr<char> gstData(g_build_filename(g_get_user_data_dir(), "gstreamer-1.0", nullptr));
 443 bindIfExists(args, gstData.get());
 444 }
 445 }
 446
 447 GUniquePtr<char> gstCache(g_build_filename(g_get_user_cache_dir(), "gstreamer-1.0", nullptr));
 448 bindIfExists(args, gstCache.get(), BindFlags::ReadWrite);
 449
 450 // /usr/lib is already added so this is only requried for other dirs
 451 const char* scannerPath = g_getenv("GST_PLUGIN_SCANNER") ?: "/usr/libexec/gstreamer-1.0/gst-plugin-scanner";
 452 const char* helperPath = g_getenv("GST_INSTALL_PLUGINS_HELPER ") ?: "/usr/libexec/gst-install-plugins-helper";
 453
 454 bindIfExists(args, scannerPath);
 455 bindIfExists(args, helperPath);
 456}
 457
 458static void bindOpenGL(Vector<CString>& args)
 459{
 460 args.appendVector(Vector<CString>({
 461 "--dev-bind-try", "/dev/dri", "/dev/dri",
 462 // Mali
 463 "--dev-bind-try", "/dev/mali", "/dev/mali",
 464 "--dev-bind-try", "/dev/mali0", "/dev/mali0",
 465 "--dev-bind-try", "/dev/umplock", "/dev/umplock",
 466 // Nvidia
 467 "--dev-bind-try", "/dev/nvidiactl", "/dev/nvidiactl",
 468 "--dev-bind-try", "/dev/nvidia0", "/dev/nvidia0",
 469 "--dev-bind-try", "/dev/nvidia", "/dev/nvidia",
 470 // Adreno
 471 "--dev-bind-try", "/dev/kgsl-3d0", "/dev/kgsl-3d0",
 472 "--dev-bind-try", "/dev/ion", "/dev/ion",
 473#if PLATFORM(WPE)
 474 "--dev-bind-try", "/dev/fb0", "/dev/fb0",
 475 "--dev-bind-try", "/dev/fb1", "/dev/fb1",
 476#endif
 477 }));
 478}
 479
 480static void bindV4l(Vector<CString>& args)
 481{
 482 args.appendVector(Vector<CString>({
 483 "--dev-bind-try", "/dev/v4l", "/dev/v4l",
 484 // Not pretty but a stop-gap for pipewire anyway.
 485 "--dev-bind-try", "/dev/video0", "/dev/video0",
 486 "--dev-bind-try", "/dev/video1", "/dev/video1",
 487 }));
 488}
 489
 490static int setupSeccomp()
 491{
 492 // NOTE: This is shared code (flatpak-run.c - LGPLv2.1+)
 493 // There are today a number of different Linux container
 494 // implementations. That will likely continue for long into the
 495 // future. But we can still try to share code, and it's important
 496 // to do so because it affects what library and application writers
 497 // can do, and we should support code portability between different
 498 // container tools.
 499 //
 500 // This syscall blacklist is copied from linux-user-chroot, which was in turn
 501 // clearly influenced by the Sandstorm.io blacklist.
 502 //
 503 // If you make any changes here, I suggest sending the changes along
 504 // to other sandbox maintainers. Using the libseccomp list is also
 505 // an appropriate venue:
 506 // https://groups.google.com/forum/#!topic/libseccomp
 507 //
 508 // A non-exhaustive list of links to container tooling that might
 509 // want to share this blacklist:
 510 //
 511 // https://github.com/sandstorm-io/sandstorm
 512 // in src/sandstorm/supervisor.c++
 513 // http://cgit.freedesktop.org/xdg-app/xdg-app/
 514 // in common/flatpak-run.c
 515 // https://git.gnome.org/browse/linux-user-chroot
 516 // in src/setup-seccomp.c
 517 struct scmp_arg_cmp cloneArg = SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER);
 518 struct scmp_arg_cmp ttyArg = SCMP_A1(SCMP_CMP_EQ, (int)TIOCSTI);
 519 struct {
 520 int scall;
 521 struct scmp_arg_cmp* arg;
 522 } syscallBlacklist[] = {
 523 // Block dmesg
 524 { SCMP_SYS(syslog), nullptr },
 525 // Useless old syscall
 526 { SCMP_SYS(uselib), nullptr },
 527 // Don't allow disabling accounting
 528 { SCMP_SYS(acct), nullptr },
 529 // 16-bit code is unnecessary in the sandbox, and modify_ldt is a
 530 // historic source of interesting information leaks.
 531 { SCMP_SYS(modify_ldt), nullptr },
 532 // Don't allow reading current quota use
 533 { SCMP_SYS(quotactl), nullptr },
 534
 535 // Don't allow access to the kernel keyring
 536 { SCMP_SYS(add_key), nullptr },
 537 { SCMP_SYS(keyctl), nullptr },
 538 { SCMP_SYS(request_key), nullptr },
 539
 540 // Scary VM/NUMA ops
 541 { SCMP_SYS(move_pages), nullptr },
 542 { SCMP_SYS(mbind), nullptr },
 543 { SCMP_SYS(get_mempolicy), nullptr },
 544 { SCMP_SYS(set_mempolicy), nullptr },
 545 { SCMP_SYS(migrate_pages), nullptr },
 546
 547 // Don't allow subnamespace setups:
 548 { SCMP_SYS(unshare), nullptr },
 549 { SCMP_SYS(mount), nullptr },
 550 { SCMP_SYS(pivot_root), nullptr },
 551 { SCMP_SYS(clone), &cloneArg },
 552
 553 // Don't allow faking input to the controlling tty (CVE-2017-5226)
 554 { SCMP_SYS(ioctl), &ttyArg },
 555
 556 // Profiling operations; we expect these to be done by tools from outside
 557 // the sandbox. In particular perf has been the source of many CVEs.
 558 { SCMP_SYS(perf_event_open), nullptr },
 559 // Don't allow you to switch to bsd emulation or whatnot.
 560 { SCMP_SYS(personality), nullptr },
 561 { SCMP_SYS(ptrace), nullptr }
 562 };
 563
 564 scmp_filter_ctx seccomp = seccomp_init(SCMP_ACT_ALLOW);
 565 if (!seccomp)
 566 g_error("Failed to init seccomp");
 567
 568 for (auto& rule : syscallBlacklist) {
 569 int scall = rule.scall;
 570 int r;
 571 if (rule.arg)
 572 r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), scall, 1, rule.arg);
 573 else
 574 r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), scall, 0);
 575 if (r == -EFAULT) {
 576 seccomp_release(seccomp);
 577 g_error("Failed to add seccomp rule");
 578 }
 579 }
 580
 581 int tmpfd = memfd_create("seccomp-bpf", 0);
 582 if (tmpfd == -1) {
 583 seccomp_release(seccomp);
 584 g_error("Failed to create memfd: %s", g_strerror(errno));
 585 }
 586
 587 if (seccomp_export_bpf(seccomp, tmpfd)) {
 588 seccomp_release(seccomp);
 589 close(tmpfd);
 590 g_error("Failed to export seccomp bpf");
 591 }
 592
 593 if (lseek(tmpfd, 0, SEEK_SET) < 0)
 594 g_error("lseek failed: %s", g_strerror(errno));
 595
 596 seccomp_release(seccomp);
 597 return tmpfd;
 598}
 599
 600GRefPtr<GSubprocess> bubblewrapSpawn(GSubprocessLauncher* launcher, const ProcessLauncher::LaunchOptions& launchOptions, char** argv, GError **error)
 601{
 602 ASSERT(launcher);
 603
 604 // It is impossible to know what access arbitrary plugins need and since it is for legacy
 605 // reasons lets just leave it unsandboxed.
 606 if (launchOptions.processType == ProcessLauncher::ProcessType::Plugin64
 607 || launchOptions.processType == ProcessLauncher::ProcessType::Plugin32)
 608 return g_subprocess_launcher_spawnv(launcher, argv, error);
 609
 610 // NOTE: This is not a great solution but we just assume that applications create this directory
 611 // ahead of time if they require it.
 612 GUniquePtr<char> configDir(g_build_filename(g_get_user_config_dir(), g_get_prgname(), nullptr));
 613
 614 Vector<CString> sandboxArgs = {
 615 "--die-with-parent",
 616 "--unshare-pid",
 617 "--unshare-uts",
 618
 619 // We assume /etc has safe permissions.
 620 // At a later point we can start masking privacy-concerning files.
 621 "--ro-bind", "/etc", "/etc",
 622 "--dev", "/dev",
 623 "--proc", "/proc",
 624 "--tmpfs", "/tmp",
 625 "--unsetenv", "TMPDIR",
 626 "--dir", "/run",
 627 "--symlink", "../run", "/var/run",
 628 "--symlink", "../tmp", "/var/tmp",
 629 "--ro-bind", "/sys/block", "/sys/block",
 630 "--ro-bind", "/sys/bus", "/sys/bus",
 631 "--ro-bind", "/sys/class", "/sys/class",
 632 "--ro-bind", "/sys/dev", "/sys/dev",
 633 "--ro-bind", "/sys/devices", "/sys/devices",
 634
 635 "--ro-bind-try", "/usr/share", "/usr/share",
 636 "--ro-bind-try", "/usr/local/share", "/usr/local/share",
 637 "--ro-bind-try", DATADIR, DATADIR,
 638
 639 // We only grant access to the libdirs webkit is built with and
 640 // guess system libdirs. This will always have some edge cases.
 641 "--ro-bind-try", "/lib", "/lib",
 642 "--ro-bind-try", "/usr/lib", "/usr/lib",
 643 "--ro-bind-try", "/usr/local/lib", "/usr/local/lib",
 644 "--ro-bind-try", LIBDIR, LIBDIR,
 645 "--ro-bind-try", "/lib64", "/lib64",
 646 "--ro-bind-try", "/usr/lib64", "/usr/lib64",
 647 "--ro-bind-try", "/usr/local/lib64", "/usr/local/lib64",
 648
 649 "--ro-bind-try", PKGLIBEXECDIR, PKGLIBEXECDIR,
 650
 651 "--setenv", "GTK_USE_PORTAL", "1",
 652
 653 "--bind-try", configDir.get(), configDir.get(),
 654 };
 655 // We would have to parse ld config files for more info.
 656 bindPathVar(sandboxArgs, "LD_LIBRARY_PATH");
 657
 658 if (launchOptions.processType == ProcessLauncher::ProcessType::Network) {
 659 static XDGDBusProxyLauncher proxy;
 660
 661 // FIXME: The network process is used for `file://` URIs and
 662 // we would have to pass through most paths for this to work.
 663
 664 // FIXME: HTTP credentials talks to libsecret.
 665
 666 // glib-networking can use dbus for proxy information.
 667 // FIXME: Find and add the permissions it needs for this (pacrunner).
 668 bindDBusSession(sandboxArgs, proxy);
 669
 670 if (!proxy.isRunning())
 671 proxy.launch();
 672 }
 673
 674 // NOTE: This has network access for HLS via GStreamer.
 675 if (launchOptions.processType == ProcessLauncher::ProcessType::Web) {
 676 static XDGDBusProxyLauncher proxy;
 677
 678 // If Wayland in use don't grant X11
 679#if PLATFORM(WAYLAND) && USE(EGL)
 680 if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland) {
 681 bindWayland(sandboxArgs);
 682 sandboxArgs.append("--unshare-ipc");
 683 } else
 684#endif
 685 bindX11(sandboxArgs);
 686
 687 bindDBusSession(sandboxArgs, proxy);
 688 // FIXME: This needs to be restricted, upstream is working on it.
 689 bindDconf(sandboxArgs);
 690 // FIXME: We should move to Pipewire as soon as viable, Pulse doesn't restrict clients atm.
 691 bindPulse(sandboxArgs);
 692 bindFonts(sandboxArgs);
 693 bindGStreamerData(sandboxArgs);
 694 bindOpenGL(sandboxArgs);
 695 // FIXME: This is also fixed by Pipewire once in use.
 696 bindV4l(sandboxArgs);
 697#if PLATFORM(GTK)
 698 bindA11y(sandboxArgs);
 699 bindGtkData(sandboxArgs);
 700#endif
 701
 702 if (!proxy.isRunning()) {
 703 proxy.setPermissions({
 704 // FIXME: Used by GTK on Wayland.
 705 "--talk=ca.desrt.dconf",
 706 // xdg-desktop-portal used by GTK and us.
 707 "--talk=org.freedesktop.portal.Desktop",
 708 // GStreamers plugin install helper.
 709 "--call=org.freedesktop.PackageKit=org.freedesktop.PackageKit.Modify2.InstallGStreamerResources@/org/freedesktop/PackageKit"
 710 });
 711 proxy.launch();
 712 }
 713
 714
 715 } else {
 716 // Only X11 users need this for XShm which is only the Web process.
 717 sandboxArgs.append("--unshare-ipc");
 718 }
 719
 720 // Only process without any network access for now.
 721 if (launchOptions.processType == ProcessLauncher::ProcessType::Storage)
 722 sandboxArgs.append("--unshare-net");
 723
 724#if ENABLE(DEVELOPER_MODE)
 725 const char* execDirectory = g_getenv("WEBKIT_EXEC_PATH");
 726 if (execDirectory) {
 727 String parentDir = FileSystem::directoryName(FileSystem::stringFromFileSystemRepresentation(execDirectory));
 728 bindIfExists(sandboxArgs, parentDir.utf8().data());
 729 }
 730
 731 CString executablePath = getCurrentExecutablePath();
 732 if (!executablePath.isNull()) {
 733 // Our executable is `/foo/bar/bin/Process`, we want `/foo/bar` as a usable prefix
 734 String parentDir = FileSystem::directoryName(FileSystem::directoryName(FileSystem::stringFromFileSystemRepresentation(executablePath.data())));
 735 bindIfExists(sandboxArgs, parentDir.utf8().data());
 736 }
 737#endif
 738
 739 int seccompFd = setupSeccomp();
 740 GUniquePtr<char> fdStr(g_strdup_printf("%d", seccompFd));
 741 g_subprocess_launcher_take_fd(launcher, seccompFd, seccompFd);
 742 sandboxArgs.appendVector(Vector<CString>({ "--seccomp", fdStr.get() }));
 743
 744 for (const String& path : launchOptions.extraSandboxPaths) {
 745 if (path.isEmpty())
 746 g_warning("Empty path passed to sandbox, this is probably a bug");
 747 else if (!FileSystem::makeAllDirectories(path)) // FIXME: Blocking
 748 g_warning("Could not create directory \"%s\": %s", path.utf8().data(), g_strerror(errno));
 749 else
 750 sandboxArgs.appendVector(Vector<CString>({ "--bind", path.utf8(), path.utf8() }));
 751 }
 752
 753 int bwrapFd = argsToFd(sandboxArgs, "bwrap");
 754 GUniquePtr<char> bwrapFdStr(g_strdup_printf("%d", bwrapFd));
 755 g_subprocess_launcher_take_fd(launcher, bwrapFd, bwrapFd);
 756
 757 Vector<CString> bwrapArgs = {
 758 BWRAP_EXECUTABLE,
 759 "--args",
 760 bwrapFdStr.get(),
 761 "--",
 762 };
 763
 764 char** newArgv = g_newa(char*, g_strv_length(argv) + bwrapArgs.size() + 1);
 765 size_t i = 0;
 766
 767 for (auto& arg : bwrapArgs)
 768 newArgv[i++] = const_cast<char*>(arg.data());
 769 for (size_t x = 0; argv[x]; x++)
 770 newArgv[i++] = argv[x];
 771 newArgv[i++] = nullptr;
 772
 773 return adoptGRef(g_subprocess_launcher_spawnv(launcher, newArgv, error));
 774}
 775
 776};
 777
 778#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(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(GSubprocessLauncher* launcher, const WebKit::ProcessLauncher::LaunchOptions& launchOptions, char** argv, GError **error)
 34{
 35 ASSERT(launcher);
 36
 37 // When we are running inside of flatpak's sandbox we do not have permissions to
 38 // use the same sandbox we do outside but flatpak offers to create new sandboxes
 39 // for us using flatpak-spawn.
 40 //
 41 // This is extremely bare-bones atm though as the Spawn interface does not expose
 42 // much outside of `--sandbox` (no permissions) and `--no-network`. We need to
 43 // add some permissions in between those for this to provide meaningful security.
 44
 45 Vector<const char*> flatpakArgs = {
 46 "/usr/bin/flatpak-spawn",
 47 };
 48
 49 if (launchOptions.processType == WebKit::ProcessLauncher::ProcessType::Storage)
 50 flatpakArgs.append("--no-network");
 51
 52 char** newArgv = g_newa(char*, g_strv_length(argv) + flatpakArgs.size() + 1);
 53 size_t i = 0;
 54
 55 for (const auto& arg : flatpakArgs)
 56 newArgv[i++] = const_cast<char*>(arg);
 57 for (size_t x = 0; argv[x]; x++)
 58 newArgv[i++] = argv[x];
 59 newArgv[i++] = nullptr;
 60
 61 return adoptGRef(g_subprocess_launcher_spawnv(launcher, newArgv, error));
 62}
 63
 64};
 65
 66#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(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.get(), m_launchOptions, argv, &error.outPtr());
 180#if ENABLE(BUBBLEWRAP_SANDBOX)
 181 else if (sandboxEnabled)
 182 process = bubblewrapSpawn(launcher.get(), 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 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 "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 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 "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 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 "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.