Backport and rebase patch to fix CVE-2021-42762 for webkitgtk 2.30.5. CVE: CVE-2021-42762 Upstream-Status: Backport [https://trac.webkit.org/changeset/284451/webkit] Ref: * https://bugs.webkit.org/show_bug.cgi?id=231479#c8 Signed-off-by: Kai Kang From 035ac439855c7bef0a4525897f783121e4a6055c Mon Sep 17 00:00:00 2001 From: Michael Catanzaro Date: Tue, 19 Oct 2021 14:27:17 +0000 Subject: [PATCH] Update seccomp filters with latest changes from flatpak https://bugs.webkit.org/show_bug.cgi?id=231479 Patch by Michael Catanzaro on 2021-10-19 Reviewed by Adrian Perez de Castro. Additionally, let's fix a minor inconsistency in our error-handling code: all but one of our codepaths carefully free and close resources, but the process is about to crash so there's not really any reason to do so. The code is slightly simpler if we don't bother. The seemingly-extraneous include order changes are required to placate the style checker. * UIProcess/Launcher/glib/BubblewrapLauncher.cpp: (WebKit::seccompStrerror): (WebKit::setupSeccomp): * UIProcess/Launcher/glib/Syscalls.h: Added. Canonical link: https://commits.webkit.org/243211@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@284451 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- .../UIProcess/Launcher/glib/BubblewrapLauncher.cpp | 139 +++++++++----- Source/WebKit/UIProcess/Launcher/glib/Syscalls.h | 200 +++++++++++++++++++++ 2 files changed, 293 insertions(+), 46 deletions(-) diff --git a/Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp b/Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp index 889388ac..c2f7e502 100644 --- a/Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp +++ b/Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp @@ -25,11 +25,18 @@ #include #include #include +#include #include #include #include #include +#if !defined(MFD_ALLOW_SEALING) && HAVE(LINUX_MEMFD_H) +#include +#endif + +#include "Syscalls.h" + #if PLATFORM(GTK) #include "WaylandCompositor.h" #endif @@ -40,13 +47,7 @@ #define BASE_DIRECTORY "wpe" #endif -#include - -#ifndef MFD_ALLOW_SEALING - -#if HAVE(LINUX_MEMFD_H) - -#include +#if !defined(MFD_ALLOW_SEALING) && HAVE(LINUX_MEMFD_H) // These defines were added in glibc 2.27, the same release that added memfd_create. // But the kernel added all of this in Linux 3.17. So it's totally safe for us to @@ -65,9 +66,7 @@ static int memfd_create(const char* name, unsigned flags) { return syscall(__NR_memfd_create, name, flags); } -#endif // #if HAVE(LINUX_MEMFD_H) - -#endif // #ifndef MFD_ALLOW_SEALING +#endif // #if !defined(MFD_ALLOW_SEALING) && HAVE(LINUX_MEMFD_H) namespace WebKit { using namespace WebCore; @@ -573,6 +572,28 @@ static void bindSymlinksRealPath(Vector& args, const char* path) } } +// Translate a libseccomp error code into an error message. libseccomp +// mostly returns negative errno values such as -ENOMEM, but some +// standard errno values are used for non-standard purposes where their +// strerror() would be misleading. +static const char* seccompStrerror(int negativeErrno) +{ + RELEASE_ASSERT_WITH_MESSAGE(negativeErrno < 0, "Non-negative error value from libseccomp?"); + RELEASE_ASSERT_WITH_MESSAGE(negativeErrno > INT_MIN, "Out of range error value from libseccomp?"); + + switch (negativeErrno) { + case -EDOM: + return "Architecture-specific failure"; + case -EFAULT: + return "Internal libseccomp failure (unknown syscall?)"; + case -ECANCELED: + return "System failure beyond the control of libseccomp"; + } + + // e.g. -ENOMEM: the result of strerror() is good enough + return g_strerror(-negativeErrno); +} + static int setupSeccomp() { // NOTE: This is shared code (flatpak-run.c - LGPLv2.1+) @@ -600,6 +621,10 @@ static int setupSeccomp() // in common/flatpak-run.c // https://git.gnome.org/browse/linux-user-chroot // in src/setup-seccomp.c + // + // Other useful resources: + // https://github.com/systemd/systemd/blob/HEAD/src/shared/seccomp-util.c + // https://github.com/moby/moby/blob/HEAD/profiles/seccomp/default.json #if defined(__s390__) || defined(__s390x__) || defined(__CRIS__) // Architectures with CONFIG_CLONE_BACKWARDS2: the child stack @@ -613,47 +638,70 @@ static int setupSeccomp() struct scmp_arg_cmp ttyArg = SCMP_A1(SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, TIOCSTI); struct { int scall; + int errnum; struct scmp_arg_cmp* arg; } syscallBlockList[] = { // Block dmesg - { SCMP_SYS(syslog), nullptr }, + { SCMP_SYS(syslog), EPERM, nullptr }, // Useless old syscall. - { SCMP_SYS(uselib), nullptr }, + { SCMP_SYS(uselib), EPERM, nullptr }, // Don't allow disabling accounting. - { SCMP_SYS(acct), nullptr }, + { SCMP_SYS(acct), EPERM, 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 }, + { SCMP_SYS(modify_ldt), EPERM, nullptr }, // Don't allow reading current quota use. - { SCMP_SYS(quotactl), nullptr }, + { SCMP_SYS(quotactl), EPERM, nullptr }, // Don't allow access to the kernel keyring. - { SCMP_SYS(add_key), nullptr }, - { SCMP_SYS(keyctl), nullptr }, - { SCMP_SYS(request_key), nullptr }, + { SCMP_SYS(add_key), EPERM, nullptr }, + { SCMP_SYS(keyctl), EPERM, nullptr }, + { SCMP_SYS(request_key), EPERM, 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 }, + { SCMP_SYS(move_pages), EPERM, nullptr }, + { SCMP_SYS(mbind), EPERM, nullptr }, + { SCMP_SYS(get_mempolicy), EPERM, nullptr }, + { SCMP_SYS(set_mempolicy), EPERM, nullptr }, + { SCMP_SYS(migrate_pages), EPERM, nullptr }, // Don't allow subnamespace setups: - { SCMP_SYS(unshare), nullptr }, - { SCMP_SYS(mount), nullptr }, - { SCMP_SYS(pivot_root), nullptr }, - { SCMP_SYS(clone), &cloneArg }, + { SCMP_SYS(unshare), EPERM, nullptr }, + { SCMP_SYS(setns), EPERM, nullptr }, + { SCMP_SYS(mount), EPERM, nullptr }, + { SCMP_SYS(umount), EPERM, nullptr }, + { SCMP_SYS(umount2), EPERM, nullptr }, + { SCMP_SYS(pivot_root), EPERM, nullptr }, + { SCMP_SYS(chroot), EPERM, nullptr }, + { SCMP_SYS(clone), EPERM, &cloneArg }, // Don't allow faking input to the controlling tty (CVE-2017-5226) - { SCMP_SYS(ioctl), &ttyArg }, + { SCMP_SYS(ioctl), EPERM, &ttyArg }, + + // seccomp can't look into clone3()'s struct clone_args to check whether + // the flags are OK, so we have no choice but to block clone3(). + // Return ENOSYS so user-space will fall back to clone(). + // (GHSA-67h7-w3jq-vh4q; see also https://github.com/moby/moby/commit/9f6b562d) + { SCMP_SYS(clone3), ENOSYS, nullptr }, + + // New mount manipulation APIs can also change our VFS. There's no + // legitimate reason to do these in the sandbox, so block all of them + // rather than thinking about which ones might be dangerous. + // (GHSA-67h7-w3jq-vh4q) + { SCMP_SYS(open_tree), ENOSYS, nullptr }, + { SCMP_SYS(move_mount), ENOSYS, nullptr }, + { SCMP_SYS(fsopen), ENOSYS, nullptr }, + { SCMP_SYS(fsconfig), ENOSYS, nullptr }, + { SCMP_SYS(fsmount), ENOSYS, nullptr }, + { SCMP_SYS(fspick), ENOSYS, nullptr }, + { SCMP_SYS(mount_setattr), ENOSYS, nullptr }, // 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 }, + { SCMP_SYS(perf_event_open), EPERM, nullptr }, // Don't allow you to switch to bsd emulation or whatnot. - { SCMP_SYS(personality), nullptr }, - { SCMP_SYS(ptrace), nullptr } + { SCMP_SYS(personality), EPERM, nullptr }, + { SCMP_SYS(ptrace), EPERM, nullptr } }; scmp_filter_ctx seccomp = seccomp_init(SCMP_ACT_ALLOW); @@ -661,29 +709,28 @@ static int setupSeccomp() g_error("Failed to init seccomp"); for (auto& rule : syscallBlockList) { - int scall = rule.scall; int r; if (rule.arg) - r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), scall, 1, *rule.arg); + r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(rule.errnum), rule.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"); - } + r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(rule.errnum), rule.scall, 0); + // EFAULT means "internal libseccomp error", but in practice we get + // this for syscall numbers added via Syscalls.h (flatpak-syscalls-private.h) + // when trying to filter them on a non-native architecture, because + // libseccomp cannot map the syscall number to a name and back to a + // number for the non-native architecture. + if (r == -EFAULT) + g_info("Unable to block syscall %d: syscall not known to libseccomp?", rule.scall); + else if (r < 0) + g_error("Failed to block syscall %d: %s", rule.scall, seccompStrerror(r)); } int tmpfd = memfd_create("seccomp-bpf", 0); - if (tmpfd == -1) { - seccomp_release(seccomp); + if (tmpfd == -1) 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 (int r = seccomp_export_bpf(seccomp, tmpfd)) + g_error("Failed to export seccomp bpf: %s", seccompStrerror(r)); if (lseek(tmpfd, 0, SEEK_SET) < 0) g_error("lseek failed: %s", g_strerror(errno)); diff --git a/Source/WebKit/UIProcess/Launcher/glib/Syscalls.h b/Source/WebKit/UIProcess/Launcher/glib/Syscalls.h new file mode 100644 index 00000000..18dea9a9 --- /dev/null +++ b/Source/WebKit/UIProcess/Launcher/glib/Syscalls.h @@ -0,0 +1,200 @@ +/* + * Copyright 2021 Collabora Ltd. + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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 . + */ + +// This file is a copy of flatpak-syscalls-private.h, reformatted a bit to placate WebKit's style checker. +// +// Upstream is here: +// https://github.com/flatpak/flatpak/blob/26b12484eb8a6219b9e7aa287b298a894b2f34ca/common/flatpak-syscalls-private.h + +#pragma once + +#include + +#if defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define FLATPAK_MISSING_SYSCALL_BASE 4000 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define FLATPAK_MISSING_SYSCALL_BASE 5000 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define FLATPAK_MISSING_SYSCALL_BASE 6000 +# else +# error "Unknown MIPS ABI" +# endif +#endif + +#if defined(__ia64__) +# define FLATPAK_MISSING_SYSCALL_BASE 1024 +#endif + +#if defined(__alpha__) +# define FLATPAK_MISSING_SYSCALL_BASE 110 +#endif + +#if defined(__x86_64__) && defined(__ILP32__) +# define FLATPAK_MISSING_SYSCALL_BASE 0x40000000 +#endif + +// FLATPAK_MISSING_SYSCALL_BASE: +// +// Number to add to the syscall numbers of recently-added syscalls +// to get the appropriate syscall for the current ABI. +#ifndef FLATPAK_MISSING_SYSCALL_BASE +# define FLATPAK_MISSING_SYSCALL_BASE 0 +#endif + +#ifndef __NR_open_tree +# define __NR_open_tree (FLATPAK_MISSING_SYSCALL_BASE + 428) +#endif +#ifndef __SNR_open_tree +# define __SNR_open_tree __NR_open_tree +#endif + +#ifndef __NR_move_mount +# define __NR_move_mount (FLATPAK_MISSING_SYSCALL_BASE + 429) +#endif +#ifndef __SNR_move_mount +# define __SNR_move_mount __NR_move_mount +#endif + +#ifndef __NR_fsopen +# define __NR_fsopen (FLATPAK_MISSING_SYSCALL_BASE + 430) +#endif +#ifndef __SNR_fsopen +# define __SNR_fsopen __NR_fsopen +#endif + +#ifndef __NR_fsconfig +# define __NR_fsconfig (FLATPAK_MISSING_SYSCALL_BASE + 431) +#endif +#ifndef __SNR_fsconfig +# define __SNR_fsconfig __NR_fsconfig +#endif + +#ifndef __NR_fsmount +# define __NR_fsmount (FLATPAK_MISSING_SYSCALL_BASE + 432) +#endif +#ifndef __SNR_fsmount +# define __SNR_fsmount __NR_fsmount +#endif + +#ifndef __NR_fspick +# define __NR_fspick (FLATPAK_MISSING_SYSCALL_BASE + 433) +#endif +#ifndef __SNR_fspick +# define __SNR_fspick __NR_fspick +#endif + +#ifndef __NR_pidfd_open +# define __NR_pidfd_open (FLATPAK_MISSING_SYSCALL_BASE + 434) +#endif +#ifndef __SNR_pidfd_open +# define __SNR_pidfd_open __NR_pidfd_open +#endif + +#ifndef __NR_clone3 +# define __NR_clone3 (FLATPAK_MISSING_SYSCALL_BASE + 435) +#endif +#ifndef __SNR_clone3 +# define __SNR_clone3 __NR_clone3 +#endif + +#ifndef __NR_close_range +# define __NR_close_range (FLATPAK_MISSING_SYSCALL_BASE + 436) +#endif +#ifndef __SNR_close_range +# define __SNR_close_range __NR_close_range +#endif + +#ifndef __NR_openat2 +# define __NR_openat2 (FLATPAK_MISSING_SYSCALL_BASE + 437) +#endif +#ifndef __SNR_openat2 +# define __SNR_openat2 __NR_openat2 +#endif + +#ifndef __NR_pidfd_getfd +# define __NR_pidfd_getfd (FLATPAK_MISSING_SYSCALL_BASE + 438) +#endif +#ifndef __SNR_pidfd_getfd +# define __SNR_pidfd_getfd __NR_pidfd_getfd +#endif + +#ifndef __NR_faccessat2 +# define __NR_faccessat2 (FLATPAK_MISSING_SYSCALL_BASE + 439) +#endif +#ifndef __SNR_faccessat2 +# define __SNR_faccessat2 __NR_faccessat2 +#endif + +#ifndef __NR_process_madvise +# define __NR_process_madvise (FLATPAK_MISSING_SYSCALL_BASE + 440) +#endif +#ifndef __SNR_process_madvise +# define __SNR_process_madvise __NR_process_madvise +#endif + +#ifndef __NR_epoll_pwait2 +# define __NR_epoll_pwait2 (FLATPAK_MISSING_SYSCALL_BASE + 441) +#endif +#ifndef __SNR_epoll_pwait2 +# define __SNR_epoll_pwait2 __NR_epoll_pwait2 +#endif + +#ifndef __NR_mount_setattr +# define __NR_mount_setattr (FLATPAK_MISSING_SYSCALL_BASE + 442) +#endif +#ifndef __SNR_mount_setattr +# define __SNR_mount_setattr __NR_mount_setattr +#endif + +#ifndef __NR_quotactl_fd +# define __NR_quotactl_fd (FLATPAK_MISSING_SYSCALL_BASE + 443) +#endif +#ifndef __SNR_quotactl_fd +# define __SNR_quotactl_fd __NR_quotactl_fd +#endif + +#ifndef __NR_landlock_create_ruleset +# define __NR_landlock_create_ruleset (FLATPAK_MISSING_SYSCALL_BASE + 444) +#endif +#ifndef __SNR_landlock_create_ruleset +# define __SNR_landlock_create_ruleset __NR_landlock_create_ruleset +#endif + +#ifndef __NR_landlock_add_rule +# define __NR_landlock_add_rule (FLATPAK_MISSING_SYSCALL_BASE + 445) +#endif +#ifndef __SNR_landlock_add_rule +# define __SNR_landlock_add_rule __NR_landlock_add_rule +#endif + +#ifndef __NR_landlock_restrict_self +# define __NR_landlock_restrict_self (FLATPAK_MISSING_SYSCALL_BASE + 446) +#endif +#ifndef __SNR_landlock_restrict_self +# define __SNR_landlock_restrict_self __NR_landlock_restrict_self +#endif + +#ifndef __NR_memfd_secret +# define __NR_memfd_secret (FLATPAK_MISSING_SYSCALL_BASE + 447) +#endif +#ifndef __SNR_memfd_secret +# define __SNR_memfd_secret __NR_memfd_secret +#endif + +// Last updated: Linux 5.14, syscall numbers < 448