Add new files missing from previous commit.
authormcatanzaro@igalia.com <mcatanzaro@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Oct 2018 15:10:27 +0000 (15:10 +0000)
committermcatanzaro@igalia.com <mcatanzaro@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Oct 2018 15:10:27 +0000 (15:10 +0000)
* Source/cmake/FindLibseccomp.cmake: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237109 268f45cc-cd09-0410-ab3c-d52691b4dbfc

ChangeLog
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.h [new file with mode: 0644]
Source/WebKit/UIProcess/Launcher/glib/FlatpakLauncher.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/Launcher/glib/FlatpakLauncher.h [new file with mode: 0644]
Source/WebKit/UIProcess/glib/WebProcessProxyGLib.cpp [new file with mode: 0644]
Source/cmake/FindLibseccomp.cmake [new file with mode: 0644]

index 00f6a53..2d02dbe 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2018-10-15  Michael Catanzaro  <mcatanzaro@igalia.com>
+
+        Add new files missing from previous commit.
+
+        * Source/cmake/FindLibseccomp.cmake: Added.
+
 2018-10-15  Patrick Griffis  <pgriffis@igalia.com>
 
         [GTK][WPE] Implement subprocess sandboxing
index 24402ce..8ec90f1 100644 (file)
@@ -1,3 +1,9 @@
+2018-10-15  Michael Catanzaro  <mcatanzaro@igalia.com>
+
+        Add new files missing from previous commit.
+
+        * Source/cmake/FindLibseccomp.cmake: Added.
+
 2018-10-15  Patrick Griffis  <pgriffis@igalia.com>
 
         [GTK][WPE] Implement subprocess sandboxing
diff --git a/Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp b/Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp
new file mode 100644 (file)
index 0000000..6084d69
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+ * Copyright (C) 2018 Igalia S.L.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "BubblewrapLauncher.h"
+
+#if ENABLE(BUBBLEWRAP_SANDBOX)
+
+#include <WebCore/FileSystem.h>
+#include <WebCore/PlatformDisplay.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <seccomp.h>
+#include <sys/ioctl.h>
+#include <wtf/glib/GLibUtilities.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
+
+namespace WebKit {
+using namespace WebCore;
+
+static int memfd_create(const char* name, unsigned flags)
+{
+    return syscall(__NR_memfd_create, name, flags);
+}
+
+#define MFD_ALLOW_SEALING 2U
+
+static int
+argsToFd(const Vector<CString>& args, const char *name)
+{
+    GString* buffer = g_string_new(nullptr);
+
+    for (const auto& arg : args)
+        g_string_append_len(buffer, arg.data(), arg.length() + 1); // Include NUL
+
+    GRefPtr<GBytes> bytes = adoptGRef(g_string_free_to_bytes(buffer));
+
+    int memfd = memfd_create(name, MFD_ALLOW_SEALING);
+    if (memfd == -1)
+        g_error("memfd_create failed: %s", g_strerror(errno));
+
+    size_t size;
+    gconstpointer data = g_bytes_get_data(bytes.get(), &size);
+
+    ssize_t bytesWritten = write(memfd, data, size);
+    if (bytesWritten < 0)
+        g_error("Writing args to memfd failed: %s", g_strerror(errno));
+
+    if (static_cast<size_t>(bytesWritten) != size)
+        g_error("Failed to write all args to memfd");
+
+    if (lseek(memfd, 0, SEEK_SET) == -1)
+        g_error("lseek failed: %s", g_strerror(errno));
+
+    if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) == -1)
+        g_error("Failed to seal memfd: %s", g_strerror(errno));
+
+    return memfd;
+}
+
+enum class DBusAddressType {
+    Normal,
+    Abstract,
+};
+
+class XDGDBusProxyLauncher {
+public:
+    void setAddress(const char* dbusAddress, DBusAddressType addressType)
+    {
+        GUniquePtr<char> dbusPath = dbusAddressToPath(dbusAddress, addressType);
+        if (!dbusPath.get())
+            return;
+
+        GUniquePtr<char> appRunDir(g_build_filename(g_get_user_runtime_dir(), g_get_prgname(), nullptr));
+        m_proxyPath = makeProxyPath(appRunDir.get()).get();
+
+        m_socket = dbusAddress;
+        m_path = dbusPath.get();
+    }
+
+    bool isRunning() const { return m_isRunning; };
+    const CString& path() const { return m_path; };
+    const CString& proxyPath() const { return m_proxyPath; };
+
+    void setPermissions(Vector<CString>&& permissions)
+    {
+        RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!isRunning());
+        m_permissions = WTFMove(permissions);
+    };
+
+    void launch()
+    {
+        RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!isRunning());
+
+        if (m_socket.isNull() || m_path.isNull() || m_proxyPath.isNull())
+            return;
+
+        int syncFds[2];
+        if (pipe2 (syncFds, O_CLOEXEC) == -1)
+            g_error("Failed to make syncfds for dbus-proxy: %s", g_strerror(errno));
+
+        GUniquePtr<char> syncFdStr(g_strdup_printf("--fd=%d", syncFds[1]));
+
+        Vector<CString> proxyArgs = {
+            m_socket, m_proxyPath,
+            "--filter",
+            syncFdStr.get(),
+        };
+
+        if (!g_strcmp0(g_getenv("WEBKIT_ENABLE_DBUS_PROXY_LOGGING"), "1"))
+            proxyArgs.append("--log");
+
+        proxyArgs.appendVector(m_permissions);
+
+        int proxyFd = argsToFd(proxyArgs, "dbus-proxy");
+        GUniquePtr<char> proxyArgsStr(g_strdup_printf("--args=%d", proxyFd));
+
+        Vector<CString> args = {
+            DBUS_PROXY_EXECUTABLE,
+            proxyArgsStr.get(),
+        };
+
+        int nargs = args.size() + 1;
+        int i = 0;
+        char** argv = g_newa(char*, nargs);
+        for (const auto& arg : args)
+            argv[i++] = const_cast<char*>(arg.data());
+        argv[i] = nullptr;
+
+        GRefPtr<GSubprocessLauncher> launcher = adoptGRef(g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_INHERIT_FDS));
+        g_subprocess_launcher_set_child_setup(launcher.get(), childSetupFunc, GINT_TO_POINTER(syncFds[1]), nullptr);
+        g_subprocess_launcher_take_fd(launcher.get(), proxyFd, proxyFd);
+        g_subprocess_launcher_take_fd(launcher.get(), syncFds[1], syncFds[1]);
+        // We are purposefully leaving syncFds[0] open here.
+        // xdg-dbus-proxy will exit() itself once that is closed on our exit
+
+        GUniqueOutPtr<GError> error;
+        GRefPtr<GSubprocess> process = adoptGRef(g_subprocess_launcher_spawnv(launcher.get(), argv, &error.outPtr()));
+        if (!process.get())
+            g_error("Failed to start dbus proxy: %s", error->message);
+
+        char out;
+        // We need to ensure the proxy has created the socket.
+        // FIXME: This is more blocking IO.
+        if (read (syncFds[0], &out, 1) != 1)
+            g_error("Failed to fully launch dbus-proxy %s", g_strerror(errno));
+
+        m_isRunning = true;
+    };
+
+private:
+    static void childSetupFunc(gpointer userdata)
+    {
+        int fd = GPOINTER_TO_INT(userdata);
+        fcntl(fd, F_SETFD, 0); // Unset CLOEXEC
+    }
+
+    static GUniquePtr<char> makeProxyPath(const char* appRunDir)
+    {
+        if (g_mkdir_with_parents(appRunDir, 0700) == -1) {
+            g_warning("Failed to mkdir for dbus proxy (%s): %s", appRunDir, g_strerror(errno));
+            return GUniquePtr<char>(nullptr);
+        }
+
+        GUniquePtr<char> proxySocketTemplate(g_build_filename(appRunDir, "dbus-proxy-XXXXXX", nullptr));
+        int fd;
+        if ((fd = g_mkstemp(proxySocketTemplate.get())) == -1) {
+            g_warning("Failed to make socket file for dbus proxy: %s", g_strerror(errno));
+            return GUniquePtr<char>(nullptr);
+        }
+
+        close(fd);
+        return proxySocketTemplate;
+    };
+
+    static GUniquePtr<char> dbusAddressToPath(const char* address, DBusAddressType addressType = DBusAddressType::Normal)
+    {
+        if (!address)
+            return nullptr;
+
+        if (!g_str_has_prefix(address, "unix:"))
+            return nullptr;
+
+        const char* path = strstr(address, addressType == DBusAddressType::Abstract ? "abstract=" : "path=");
+        if (!path)
+            return nullptr;
+
+        path += strlen(addressType == DBusAddressType::Abstract ? "abstract=" : "path=");
+        const char* pathEnd = path;
+        while (*pathEnd && *pathEnd != ',')
+            pathEnd++;
+
+        return GUniquePtr<char>(g_strndup(path, pathEnd - path));
+}
+
+    CString m_socket;
+    CString m_path;
+    CString m_proxyPath;
+    bool m_isRunning;
+    Vector<CString> m_permissions;
+};
+
+enum class BindFlags {
+    ReadOnly,
+    ReadWrite,
+    Device,
+};
+
+static void bindIfExists(Vector<CString>& args, const char* path, BindFlags bindFlags = BindFlags::ReadOnly)
+{
+    if (!path)
+        return;
+
+    const char* bindType;
+    if (bindFlags == BindFlags::Device)
+        bindType = "--dev-bind-try";
+    else if (bindFlags == BindFlags::ReadOnly)
+        bindType = "--ro-bind-try";
+    else
+        bindType = "--bind-try";
+    args.appendVector(Vector<CString>({ bindType, path, path }));
+}
+
+static void bindDBusSession(Vector<CString>& args, XDGDBusProxyLauncher& proxy)
+{
+    if (!proxy.isRunning())
+        proxy.setAddress(g_getenv("DBUS_SESSION_BUS_ADDRESS"), DBusAddressType::Normal);
+
+    if (proxy.proxyPath().data()) {
+        args.appendVector(Vector<CString>({
+            "--bind", proxy.proxyPath(), proxy.path(),
+        }));
+    }
+}
+
+static void bindX11(Vector<CString>& args)
+{
+    const char* display = g_getenv("DISPLAY");
+    if (!display || display[0] != ':' || !g_ascii_isdigit(const_cast<char*>(display)[1]))
+        display = ":0";
+    GUniquePtr<char> x11File(g_strdup_printf("/tmp/.X11-unix/X%s", display + 1));
+    bindIfExists(args, x11File.get(), BindFlags::ReadWrite);
+
+    const char* xauth = g_getenv("XAUTHORITY");
+    if (!xauth) {
+        const char* homeDir = g_get_home_dir();
+        GUniquePtr<char> xauthFile(g_build_filename(homeDir, ".Xauthority", nullptr));
+        bindIfExists(args, xauthFile.get());
+    } else
+        bindIfExists(args, xauth);
+}
+
+static void bindDconf(Vector<CString>& args)
+{
+    const char* runtimeDir = g_get_user_runtime_dir();
+    GUniquePtr<char> dconfRuntimeDir(g_build_filename(runtimeDir, "dconf", nullptr));
+    args.appendVector(Vector<CString>({ "--bind", dconfRuntimeDir.get(), dconfRuntimeDir.get() }));
+
+    const char* dconfDir = g_getenv("DCONF_USER_CONFIG_DIR");
+    if (dconfDir)
+        bindIfExists(args, dconfDir);
+    else {
+        const char* configDir = g_get_user_config_dir();
+        GUniquePtr<char> dconfConfigDir(g_build_filename(configDir, "dconf", nullptr));
+        bindIfExists(args, dconfConfigDir.get(), BindFlags::ReadWrite);
+    }
+}
+
+static void bindWayland(Vector<CString>& args)
+{
+    const char* display = g_getenv("WAYLAND_DISPLAY");
+    if (!display)
+        display = "wayland-0";
+
+    const char* runtimeDir = g_get_user_runtime_dir();
+    GUniquePtr<char> waylandRuntimeFile(g_build_filename(runtimeDir, display, nullptr));
+    bindIfExists(args, waylandRuntimeFile.get(), BindFlags::ReadWrite);
+}
+
+static void bindPulse(Vector<CString>& args)
+{
+    // FIXME: The server can be defined in config files we'd have to parse.
+    // They can also be set as X11 props but that is getting a bit ridiculous.
+    const char* pulseServer = g_getenv("PULSE_SERVER");
+    if (pulseServer) {
+        if (g_str_has_prefix(pulseServer, "unix:"))
+            bindIfExists(args, pulseServer + 5, BindFlags::ReadWrite);
+        // else it uses tcp
+    } else {
+        const char* runtimeDir = g_get_user_runtime_dir();
+        GUniquePtr<char> pulseRuntimeDir(g_build_filename(runtimeDir, "pulse", nullptr));
+        bindIfExists(args, pulseRuntimeDir.get(), BindFlags::ReadWrite);
+    }
+
+    const char* pulseConfig = g_getenv("PULSE_CLIENTCONFIG");
+    if (pulseConfig)
+        bindIfExists(args, pulseConfig);
+
+    const char* configDir = g_get_user_config_dir();
+    GUniquePtr<char> pulseConfigDir(g_build_filename(configDir, "pulse", nullptr));
+    bindIfExists(args, pulseConfigDir.get());
+
+    const char* homeDir = g_get_home_dir();
+    GUniquePtr<char> pulseHomeConfigDir(g_build_filename(homeDir, ".pulse", nullptr));
+    GUniquePtr<char> asoundHomeConfigDir(g_build_filename(homeDir, ".asoundrc", nullptr));
+    bindIfExists(args, pulseHomeConfigDir.get());
+    bindIfExists(args, asoundHomeConfigDir.get());
+
+    // This is the ultimate fallback to raw ALSA
+    bindIfExists(args, "/dev/snd", BindFlags::Device);
+}
+
+static void bindFonts(Vector<CString>& args)
+{
+    const char* configDir = g_get_user_config_dir();
+    const char* homeDir = g_get_home_dir();
+    const char* dataDir = g_get_user_data_dir();
+    const char* cacheDir = g_get_user_cache_dir();
+
+    // Configs can include custom dirs but then we have to parse them...
+    GUniquePtr<char> fontConfig(g_build_filename(configDir, "fontconfig", nullptr));
+    GUniquePtr<char> fontCache(g_build_filename(cacheDir, "fontconfig", nullptr));
+    GUniquePtr<char> fontHomeConfig(g_build_filename(homeDir, ".fonts.conf", nullptr));
+    GUniquePtr<char> fontHomeConfigDir(g_build_filename(configDir, ".fonts.conf.d", nullptr));
+    GUniquePtr<char> fontData(g_build_filename(dataDir, "fonts", nullptr));
+    GUniquePtr<char> fontHomeData(g_build_filename(homeDir, ".fonts", nullptr));
+    bindIfExists(args, fontConfig.get());
+    bindIfExists(args, fontCache.get(), BindFlags::ReadWrite);
+    bindIfExists(args, fontHomeConfig.get());
+    bindIfExists(args, fontHomeConfigDir.get());
+    bindIfExists(args, fontData.get());
+    bindIfExists(args, fontHomeData.get());
+}
+
+#if PLATFORM(GTK)
+static void bindGtkData(Vector<CString>& args)
+{
+    const char* configDir = g_get_user_config_dir();
+    const char* dataDir = g_get_user_data_dir();
+    const char* homeDir = g_get_home_dir();
+
+    GUniquePtr<char> gtkConfig(g_build_filename(configDir, "gtk-3.0", nullptr));
+    GUniquePtr<char> themeData(g_build_filename(dataDir, "themes", nullptr));
+    GUniquePtr<char> themeHomeData(g_build_filename(homeDir, ".themes", nullptr));
+    GUniquePtr<char> iconHomeData(g_build_filename(homeDir, ".icons", nullptr));
+    bindIfExists(args, gtkConfig.get());
+    bindIfExists(args, themeData.get());
+    bindIfExists(args, themeHomeData.get());
+    bindIfExists(args, iconHomeData.get());
+}
+
+static void bindA11y(Vector<CString>& args)
+{
+    static XDGDBusProxyLauncher proxy;
+
+    if (!proxy.isRunning()) {
+        // FIXME: Avoid blocking IO... (It is at least a one-time cost)
+        GRefPtr<GDBusConnection> sessionBus = adoptGRef(g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr));
+        if (!sessionBus.get())
+            return;
+
+        GRefPtr<GDBusMessage> msg = adoptGRef(g_dbus_message_new_method_call(
+            "org.a11y.Bus", "/org/a11y/bus", "org.a11y.Bus", "GetAddress"));
+        g_dbus_message_set_body(msg.get(), g_variant_new("()"));
+        GRefPtr<GDBusMessage> reply = adoptGRef(g_dbus_connection_send_message_with_reply_sync(
+            sessionBus.get(), msg.get(),
+            G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+            30000,
+            nullptr,
+            nullptr,
+            nullptr));
+
+        if (reply.get()) {
+            GUniqueOutPtr<GError> error;
+            if (g_dbus_message_to_gerror(reply.get(), &error.outPtr())) {
+                if (!g_error_matches(error.get(), G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))
+                    g_warning("Can't find a11y bus: %s", error->message);
+            } else {
+                GUniqueOutPtr<char> a11yAddress;
+                g_variant_get(g_dbus_message_get_body(reply.get()), "(s)", &a11yAddress.outPtr());
+                proxy.setAddress(a11yAddress.get(), DBusAddressType::Abstract);
+            }
+        }
+
+        proxy.setPermissions({
+            "--sloppy-names",
+            "--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Embed@/org/a11y/atspi/accessible/root",
+            "--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Unembed@/org/a11y/atspi/accessible/root",
+            "--call=org.a11y.atspi.Registry=org.a11y.atspi.Registry.GetRegisteredEvents@/org/a11y/atspi/registry",
+            "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetKeystrokeListeners@/org/a11y/atspi/registry/deviceeventcontroller",
+            "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetDeviceEventListeners@/org/a11y/atspi/registry/deviceeventcontroller",
+            "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersSync@/org/a11y/atspi/registry/deviceeventcontroller",
+            "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersAsync@/org/a11y/atspi/registry/deviceeventcontroller",
+        });
+
+        proxy.launch();
+    }
+
+    if (proxy.proxyPath().data()) {
+        args.appendVector(Vector<CString>({
+            "--bind", proxy.proxyPath(), proxy.path(),
+        }));
+    }
+}
+#endif
+
+static bool bindPathVar(Vector<CString>& args, const char* varname)
+{
+    const char* pathValue = g_getenv(varname);
+    if (!pathValue)
+        return false;
+
+    GUniquePtr<char*> splitPaths(g_strsplit(pathValue, ":", -1));
+    for (size_t i; splitPaths.get()[i]; ++i)
+        bindIfExists(args, splitPaths.get()[i]);
+
+    return true;
+}
+
+static void bindGStreamerData(Vector<CString>& args)
+{
+    if (!bindPathVar(args, "GST_PLUGIN_PATH_1_0"))
+        bindPathVar(args, "GST_PLUGIN_PATH");
+
+    if (!bindPathVar(args, "GST_PLUGIN_SYSTEM_PATH_1_0")) {
+        if (!bindPathVar(args, "GST_PLUGIN_SYSTEM_PATH")) {
+            GUniquePtr<char> gstData(g_build_filename(g_get_user_data_dir(), "gstreamer-1.0", nullptr));
+            bindIfExists(args, gstData.get());
+        }
+    }
+
+    GUniquePtr<char> gstCache(g_build_filename(g_get_user_cache_dir(), "gstreamer-1.0", nullptr));
+    bindIfExists(args, gstCache.get(), BindFlags::ReadWrite);
+
+    // /usr/lib is already added so this is only requried for other dirs
+    const char* scannerPath = g_getenv("GST_PLUGIN_SCANNER") ?: "/usr/libexec/gstreamer-1.0/gst-plugin-scanner";
+    const char* helperPath = g_getenv("GST_INSTALL_PLUGINS_HELPER ") ?: "/usr/libexec/gst-install-plugins-helper";
+
+    bindIfExists(args, scannerPath);
+    bindIfExists(args, helperPath);
+}
+
+static void bindOpenGL(Vector<CString>& args)
+{
+    args.appendVector(Vector<CString>({
+        "--dev-bind-try", "/dev/dri", "/dev/dri",
+        // Mali
+        "--dev-bind-try", "/dev/mali", "/dev/mali",
+        "--dev-bind-try", "/dev/mali0", "/dev/mali0",
+        "--dev-bind-try", "/dev/umplock", "/dev/umplock",
+        // Nvidia
+        "--dev-bind-try", "/dev/nvidiactl", "/dev/nvidiactl",
+        "--dev-bind-try", "/dev/nvidia0", "/dev/nvidia0",
+        "--dev-bind-try", "/dev/nvidia", "/dev/nvidia",
+        // Adreno
+        "--dev-bind-try", "/dev/kgsl-3d0", "/dev/kgsl-3d0",
+        "--dev-bind-try", "/dev/ion", "/dev/ion",
+#if PLATFORM(WPE)
+        "--dev-bind-try", "/dev/fb0", "/dev/fb0",
+        "--dev-bind-try", "/dev/fb1", "/dev/fb1",
+#endif
+    }));
+}
+
+static void bindV4l(Vector<CString>& args)
+{
+    args.appendVector(Vector<CString>({
+        "--dev-bind-try", "/dev/v4l", "/dev/v4l",
+        // Not pretty but a stop-gap for pipewire anyway.
+        "--dev-bind-try", "/dev/video0", "/dev/video0",
+        "--dev-bind-try", "/dev/video1", "/dev/video1",
+    }));
+}
+
+static void bindSymlinksRealPath(Vector<CString>& args, const char* path)
+{
+    char realPath[PATH_MAX];
+
+    if (realpath(path, realPath) && strcmp(path, realPath)) {
+        args.appendVector(Vector<CString>({
+            "--ro-bind", realPath, realPath,
+        }));
+    }
+}
+
+static int setupSeccomp()
+{
+    // NOTE: This is shared code (flatpak-run.c - LGPLv2.1+)
+    // There are today a number of different Linux container
+    // implementations. That will likely continue for long into the
+    // future. But we can still try to share code, and it's important
+    // to do so because it affects what library and application writers
+    // can do, and we should support code portability between different
+    // container tools.
+    //
+    // This syscall blacklist is copied from linux-user-chroot, which was in turn
+    // clearly influenced by the Sandstorm.io blacklist.
+    //
+    // If you make any changes here, I suggest sending the changes along
+    // to other sandbox maintainers. Using the libseccomp list is also
+    // an appropriate venue:
+    // https://groups.google.com/forum/#!topic/libseccomp
+    //
+    // A non-exhaustive list of links to container tooling that might
+    // want to share this blacklist:
+    //
+    //  https://github.com/sandstorm-io/sandstorm
+    //    in src/sandstorm/supervisor.c++
+    //  http://cgit.freedesktop.org/xdg-app/xdg-app/
+    //    in common/flatpak-run.c
+    //  https://git.gnome.org/browse/linux-user-chroot
+    //    in src/setup-seccomp.c
+    struct scmp_arg_cmp cloneArg = SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER);
+    struct scmp_arg_cmp ttyArg = SCMP_A1(SCMP_CMP_EQ, (int)TIOCSTI);
+    struct {
+        int scall;
+        struct scmp_arg_cmp* arg;
+    } syscallBlacklist[] = {
+        // Block dmesg
+        { SCMP_SYS(syslog), nullptr },
+        // Useless old syscall.
+        { SCMP_SYS(uselib), nullptr },
+        // Don't allow disabling accounting.
+        { SCMP_SYS(acct), nullptr },
+        // 16-bit code is unnecessary in the sandbox, and modify_ldt is a
+        // historic source of interesting information leaks.
+        { SCMP_SYS(modify_ldt), nullptr },
+        // Don't allow reading current quota use.
+        { SCMP_SYS(quotactl), nullptr },
+
+        // Don't allow access to the kernel keyring.
+        { SCMP_SYS(add_key), nullptr },
+        { SCMP_SYS(keyctl), nullptr },
+        { SCMP_SYS(request_key), nullptr },
+
+        // Scary VM/NUMA ops 
+        { SCMP_SYS(move_pages), nullptr },
+        { SCMP_SYS(mbind), nullptr },
+        { SCMP_SYS(get_mempolicy), nullptr },
+        { SCMP_SYS(set_mempolicy), nullptr },
+        { SCMP_SYS(migrate_pages), nullptr },
+
+        // Don't allow subnamespace setups:
+        { SCMP_SYS(unshare), nullptr },
+        { SCMP_SYS(mount), nullptr },
+        { SCMP_SYS(pivot_root), nullptr },
+        { SCMP_SYS(clone), &cloneArg },
+
+        // Don't allow faking input to the controlling tty (CVE-2017-5226)
+        { SCMP_SYS(ioctl), &ttyArg },
+
+        // Profiling operations; we expect these to be done by tools from outside
+        // the sandbox. In particular perf has been the source of many CVEs.
+        { SCMP_SYS(perf_event_open), nullptr },
+        // Don't allow you to switch to bsd emulation or whatnot.
+        { SCMP_SYS(personality), nullptr },
+        { SCMP_SYS(ptrace), nullptr }
+    };
+
+    scmp_filter_ctx seccomp = seccomp_init(SCMP_ACT_ALLOW);
+    if (!seccomp)
+        g_error("Failed to init seccomp");
+
+    for (auto& rule : syscallBlacklist) {
+        int scall = rule.scall;
+        int r;
+        if (rule.arg)
+            r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), scall, 1, rule.arg);
+        else
+            r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), scall, 0);
+        if (r == -EFAULT) {
+            seccomp_release(seccomp);
+            g_error("Failed to add seccomp rule");
+        }
+    }
+
+    int tmpfd = memfd_create("seccomp-bpf", 0);
+    if (tmpfd == -1) {
+        seccomp_release(seccomp);
+        g_error("Failed to create memfd: %s", g_strerror(errno));
+    }
+
+    if (seccomp_export_bpf(seccomp, tmpfd)) {
+        seccomp_release(seccomp);
+        close(tmpfd);
+        g_error("Failed to export seccomp bpf");
+    }
+
+    if (lseek(tmpfd, 0, SEEK_SET) < 0)
+        g_error("lseek failed: %s", g_strerror(errno));
+
+    seccomp_release(seccomp);
+    return tmpfd;
+}
+
+GRefPtr<GSubprocess> bubblewrapSpawn(GSubprocessLauncher* launcher, const ProcessLauncher::LaunchOptions& launchOptions, char** argv, GError **error)
+{
+    ASSERT(launcher);
+
+    // It is impossible to know what access arbitrary plugins need and since it is for legacy
+    // reasons lets just leave it unsandboxed.
+    if (launchOptions.processType == ProcessLauncher::ProcessType::Plugin64
+        || launchOptions.processType == ProcessLauncher::ProcessType::Plugin32)
+        return adoptGRef(g_subprocess_launcher_spawnv(launcher, argv, error));
+
+    // For now we are just considering the network process trusted as it
+    // requires a lot of access but doesn't execute arbitrary code like
+    // the WebProcess where our focus lies.
+    if (launchOptions.processType == ProcessLauncher::ProcessType::Network)
+        return adoptGRef(g_subprocess_launcher_spawnv(launcher, argv, error));
+
+    Vector<CString> sandboxArgs = {
+        "--die-with-parent",
+        "--unshare-pid",
+        "--unshare-uts",
+
+        // We assume /etc has safe permissions.
+        // At a later point we can start masking privacy-concerning files.
+        "--ro-bind", "/etc", "/etc",
+        "--dev", "/dev",
+        "--proc", "/proc",
+        "--tmpfs", "/tmp",
+        "--unsetenv", "TMPDIR",
+        "--dir", "/run",
+        "--symlink", "../run", "/var/run",
+        "--symlink", "../tmp", "/var/tmp",
+        "--ro-bind", "/sys/block", "/sys/block",
+        "--ro-bind", "/sys/bus", "/sys/bus",
+        "--ro-bind", "/sys/class", "/sys/class",
+        "--ro-bind", "/sys/dev", "/sys/dev",
+        "--ro-bind", "/sys/devices", "/sys/devices",
+
+        "--ro-bind-try", "/usr/share", "/usr/share",
+        "--ro-bind-try", "/usr/local/share", "/usr/local/share",
+        "--ro-bind-try", DATADIR, DATADIR,
+
+        // We only grant access to the libdirs webkit is built with and
+        // guess system libdirs. This will always have some edge cases.
+        "--ro-bind-try", "/lib", "/lib",
+        "--ro-bind-try", "/usr/lib", "/usr/lib",
+        "--ro-bind-try", "/usr/local/lib", "/usr/local/lib",
+        "--ro-bind-try", LIBDIR, LIBDIR,
+        "--ro-bind-try", "/lib64", "/lib64",
+        "--ro-bind-try", "/usr/lib64", "/usr/lib64",
+        "--ro-bind-try", "/usr/local/lib64", "/usr/local/lib64",
+
+        "--ro-bind-try", PKGLIBEXECDIR, PKGLIBEXECDIR,
+
+        "--setenv", "GTK_USE_PORTAL", "1",
+    };
+    // We would have to parse ld config files for more info.
+    bindPathVar(sandboxArgs, "LD_LIBRARY_PATH");
+
+    bindSymlinksRealPath(sandboxArgs, "/etc/resolv.conf");
+    bindSymlinksRealPath(sandboxArgs, "/etc/localtime");
+
+    // NOTE: This has network access for HLS via GStreamer.
+    if (launchOptions.processType == ProcessLauncher::ProcessType::Web) {
+        static XDGDBusProxyLauncher proxy;
+
+        // If Wayland in use don't grant X11
+#if PLATFORM(WAYLAND) && USE(EGL)
+        if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland) {
+            bindWayland(sandboxArgs);
+            sandboxArgs.append("--unshare-ipc");
+        } else
+#endif
+            bindX11(sandboxArgs);
+
+        // NOTE: This is not a great solution but we just assume that applications create this directory
+        // ahead of time if they require it.
+        GUniquePtr<char> configDir(g_build_filename(g_get_user_config_dir(), g_get_prgname(), nullptr));
+        GUniquePtr<char> cacheDir(g_build_filename(g_get_user_cache_dir(), g_get_prgname(), nullptr));
+
+        Vector<String> extraPaths = { "applicationCacheDirectory", "waylandSocket"};
+        for (const auto& path : extraPaths) {
+            String extraPath = launchOptions.extraInitializationData.get(path);
+            if (!extraPath.isEmpty())
+                sandboxArgs.appendVector(Vector<CString>({ "--bind-try", extraPath.utf8(), extraPath.utf8() }));
+        }
+
+        sandboxArgs.appendVector(Vector<CString>({
+            "--ro-bind-try", cacheDir.get(), cacheDir.get(),
+            "--ro-bind-try", configDir.get(), configDir.get(),
+        }));
+
+        bindDBusSession(sandboxArgs, proxy);
+        // FIXME: This needs to be restricted, upstream is working on it.
+        bindDconf(sandboxArgs);
+        // FIXME: We should move to Pipewire as soon as viable, Pulse doesn't restrict clients atm.
+        bindPulse(sandboxArgs);
+        bindFonts(sandboxArgs);
+        bindGStreamerData(sandboxArgs);
+        bindOpenGL(sandboxArgs);
+        // FIXME: This is also fixed by Pipewire once in use.
+        bindV4l(sandboxArgs);
+#if PLATFORM(GTK)
+        bindA11y(sandboxArgs);
+        bindGtkData(sandboxArgs);
+#endif
+
+    if (!proxy.isRunning()) {
+        proxy.setPermissions({
+            // FIXME: Used by GTK on Wayland.
+            "--talk=ca.desrt.dconf",
+            // xdg-desktop-portal used by GTK and us.
+            "--talk=org.freedesktop.portal.Desktop",
+            // GStreamers plugin install helper.
+            "--call=org.freedesktop.PackageKit=org.freedesktop.PackageKit.Modify2.InstallGStreamerResources@/org/freedesktop/PackageKit"
+        });
+        proxy.launch();
+    }
+
+
+    } else {
+        // Only X11 users need this for XShm which is only the Web process.
+        sandboxArgs.append("--unshare-ipc");
+    }
+
+#if ENABLE(DEVELOPER_MODE)
+    const char* execDirectory = g_getenv("WEBKIT_EXEC_PATH");
+    if (execDirectory) {
+        String parentDir = FileSystem::directoryName(FileSystem::stringFromFileSystemRepresentation(execDirectory));
+        bindIfExists(sandboxArgs, parentDir.utf8().data());
+    }
+
+    CString executablePath = getCurrentExecutablePath();
+    if (!executablePath.isNull()) {
+        // Our executable is `/foo/bar/bin/Process`, we want `/foo/bar` as a usable prefix
+        String parentDir = FileSystem::directoryName(FileSystem::directoryName(FileSystem::stringFromFileSystemRepresentation(executablePath.data())));
+        bindIfExists(sandboxArgs, parentDir.utf8().data());
+    }
+#endif
+
+    int seccompFd = setupSeccomp();
+    GUniquePtr<char> fdStr(g_strdup_printf("%d", seccompFd));
+    g_subprocess_launcher_take_fd(launcher, seccompFd, seccompFd);
+    sandboxArgs.appendVector(Vector<CString>({ "--seccomp", fdStr.get() }));
+
+    int bwrapFd = argsToFd(sandboxArgs, "bwrap");
+    GUniquePtr<char> bwrapFdStr(g_strdup_printf("%d", bwrapFd));
+    g_subprocess_launcher_take_fd(launcher, bwrapFd, bwrapFd);
+
+    Vector<CString> bwrapArgs = {
+        BWRAP_EXECUTABLE,
+        "--args",
+        bwrapFdStr.get(),
+        "--",
+    };
+
+    char** newArgv = g_newa(char*, g_strv_length(argv) + bwrapArgs.size() + 1);
+    size_t i = 0;
+
+    for (auto& arg : bwrapArgs)
+        newArgv[i++] = const_cast<char*>(arg.data());
+    for (size_t x = 0; argv[x]; x++)
+        newArgv[i++] = argv[x];
+    newArgv[i++] = nullptr;
+
+    return adoptGRef(g_subprocess_launcher_spawnv(launcher, newArgv, error));
+}
+
+};
+
+#endif // ENABLE(BUBBLEWRAP_SANDBOX)
diff --git a/Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.h b/Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.h
new file mode 100644 (file)
index 0000000..550c520
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(BUBBLEWRAP_SANDBOX)
+
+#include "ProcessLauncher.h"
+
+#include <glib.h>
+
+namespace WebKit {
+
+GRefPtr<GSubprocess> bubblewrapSpawn(GSubprocessLauncher*, const ProcessLauncher::LaunchOptions&, char** argv, GError**);
+
+};
+
+#endif
diff --git a/Source/WebKit/UIProcess/Launcher/glib/FlatpakLauncher.cpp b/Source/WebKit/UIProcess/Launcher/glib/FlatpakLauncher.cpp
new file mode 100644 (file)
index 0000000..bcb139f
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FlatpakLauncher.h"
+
+#if OS(LINUX)
+
+namespace WebKit {
+
+GRefPtr<GSubprocess> flatpakSpawn(GSubprocessLauncher* launcher, const WebKit::ProcessLauncher::LaunchOptions& launchOptions, char** argv, GError **error)
+{
+    ASSERT(launcher);
+
+    // When we are running inside of flatpak's sandbox we do not have permissions to
+    // use the same sandbox we do outside but flatpak offers to create new sandboxes
+    // for us using flatpak-spawn.
+    //
+    // This is just a stub implementation atm though as the Spawn interface does not expose
+    // much outside of `--sandbox` (no permissions) and `--no-network`. We need to
+    // add some permissions in between those for this to provide meaningful security.
+
+    Vector<const char*> flatpakArgs = {
+        "/usr/bin/flatpak-spawn",
+    };
+
+    char** newArgv = g_newa(char*, g_strv_length(argv) + flatpakArgs.size() + 1);
+    size_t i = 0;
+
+    for (const auto& arg : flatpakArgs)
+        newArgv[i++] = const_cast<char*>(arg);
+    for (size_t x = 0; argv[x]; x++)
+        newArgv[i++] = argv[x];
+    newArgv[i++] = nullptr;
+
+    return adoptGRef(g_subprocess_launcher_spawnv(launcher, newArgv, error));
+}
+
+};
+
+#endif // OS(LINUX)
diff --git a/Source/WebKit/UIProcess/Launcher/glib/FlatpakLauncher.h b/Source/WebKit/UIProcess/Launcher/glib/FlatpakLauncher.h
new file mode 100644 (file)
index 0000000..75cba9f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if OS(LINUX)
+
+#include "ProcessLauncher.h"
+
+#include <glib.h>
+
+namespace WebKit {
+
+GRefPtr<GSubprocess> flatpakSpawn(GSubprocessLauncher*, const WebKit::ProcessLauncher::LaunchOptions&, char** argv, GError**);
+
+};
+
+#endif
diff --git a/Source/WebKit/UIProcess/glib/WebProcessProxyGLib.cpp b/Source/WebKit/UIProcess/glib/WebProcessProxyGLib.cpp
new file mode 100644 (file)
index 0000000..8f5fa03
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebProcessProxy.h"
+
+#if PLATFORM(WAYLAND) && USE(EGL)
+#include "WaylandCompositor.h"
+#endif
+#include "WebProcessPool.h"
+#include "WebsiteDataStore.h"
+#include <WebCore/FileSystem.h>
+#include <WebCore/PlatformDisplay.h>
+
+namespace WebKit {
+using namespace WebCore;
+
+void WebProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
+{
+    launchOptions.extraInitializationData.set("enable-sandbox", m_processPool->sandboxEnabled() ? "true" : "false");
+
+    websiteDataStore().resolveDirectoriesIfNecessary();
+    launchOptions.extraInitializationData.set("applicationCacheDirectory", websiteDataStore().resolvedApplicationCacheDirectory());
+
+#if PLATFORM(WAYLAND) && USE(EGL)
+    if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland) {
+        String displayName = WaylandCompositor::singleton().displayName();
+        String runtimeDir(g_get_user_runtime_dir());
+        String waylandSocket = FileSystem::pathByAppendingComponent(runtimeDir, displayName);
+        launchOptions.extraInitializationData.set("waylandSocket", waylandSocket);
+    }
+#endif
+}
+
+};
diff --git a/Source/cmake/FindLibseccomp.cmake b/Source/cmake/FindLibseccomp.cmake
new file mode 100644 (file)
index 0000000..e6a2280
--- /dev/null
@@ -0,0 +1,53 @@
+# - Try to find libseccomp
+# Once done, this will define
+#
+#  LIBSECCOMP_FOUND - system has libseccomp
+#  LIBSECCOMP_INCLUDE_DIRS - the libseccomp include drectories
+#  LIBSECCOMP_LIBRARIES - link these to use libseccomp
+#
+# Copyright (C) 2018 Igalia S.L.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
+# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+find_package(PkgConfig)
+pkg_check_modules(PC_LIBSECCOMP libseccomp)
+
+find_path(LIBSECCOMP_INCLUDE_DIRS
+    NAMES seccomp.h
+    HINTS ${PC_LIBSECCOMP_INCLUDEDIR}
+)
+
+find_library(LIBSECCOMP_LIBRARIES
+    NAMES seccomp
+    HINTS ${PC_LIBSECCOMP_LIBDIR}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LIBSECCOMP
+    REQUIRED_VARS LIBSECCOMP_LIBRARIES
+    FOUND_VAR LIBSECCOMP_FOUND
+    VERSION_VAR PC_LIBSECCOMP_VERSION)
+
+mark_as_advanced(
+    LIBSECCOMP_INCLUDE_DIRS
+    LIBSECCOMP_LIBRARIES
+)
\ No newline at end of file