From 8fe1de2fdcdf03cd3f460e6abc5eb3a09fdbaa43 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 3 Mar 2022 21:16:04 +0100 Subject: Add qt.chromium.sandboxing setting and sandboxing test --- doc/changelog.asciidoc | 1 + doc/help/settings.asciidoc | 25 ++++++++++++++++++++++ qutebrowser/config/configdata.yml | 30 ++++++++++++++++++++++++++ qutebrowser/config/qtargs.py | 5 +++++ tests/end2end/test_invocations.py | 45 +++++++++++++++++++++++++++++++++++++++ tests/unit/config/test_qtargs.py | 22 +++++++++++++++++++ 6 files changed, 128 insertions(+) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index 3c462ad4b..9df2ce00c 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -60,6 +60,7 @@ Added which shows relative tab numbers. - New `input.mode_override` option which allows overriding the current mode based on the new URL when navigating or switching tabs. +- New `qt.chromium.sandboxing` setting which allows to disable Chromium's sandboxing (mainly intended for development and testing) Fixed ~~~~~ diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 8623bd15e..2e51ecc7f 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -289,6 +289,7 @@ |<>|Additional arguments to pass to Qt, without leading `--`. |<>|When to use Chromium's low-end device mode. |<>|Which Chromium process model to use. +|<>|What sandboxing mechanisms in Chromium to use. |<>|Additional environment variables to set. |<>|Force a Qt platform to use. |<>|Force a Qt platformtheme to use. @@ -3814,6 +3815,30 @@ Valid values: Default: +pass:[process-per-site-instance]+ +[[qt.chromium.sandboxing]] +=== qt.chromium.sandboxing +What sandboxing mechanisms in Chromium to use. +Chromium has various sandboxing layers, which should be enabled for normal browser usage. Mainly for testing and development, it's possible to disable individual sandboxing layers via this setting. +Open `chrome://sandbox` to see the current sandbox status. +Changing this setting is only recommended if you know what you're doing, as it **disables one of Chromium's security layers**. To avoid sandboxing being accidentally disabled persistently, this setting can only be set via `config.py`, not via `:set`. +See the Chromium documentation for more details: - Linux: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/linux/sandboxing.md - Windows: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox.md - FAQ (Windows-centric): https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox_faq.md + +This setting requires a restart. + +This setting can only be set in config.py. + +This setting is only available with the QtWebEngine backend. + +Type: <> + +Valid values: + + * +enable-all+: Enable all available sandboxing mechanisms. + * +disable-seccomp-bpf+: Disable the Seccomp BPF filter sandbox (Linux only). + * +disable-all+: Disable all sandboxing (**not recommended!**). + +Default: +pass:[enable-all]+ + [[qt.environ]] === qt.environ Additional environment variables to set. diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 5d3099e79..e4caf05af 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -290,6 +290,36 @@ qt.chromium.low_end_device_mode: This improves the RAM usage of renderer processes, at the expense of performance. +qt.chromium.sandboxing: + type: + name: String + valid_values: + - enable-all: Enable all available sandboxing mechanisms. + - disable-seccomp-bpf: Disable the Seccomp BPF filter sandbox (Linux only). + - disable-all: Disable all sandboxing (**not recommended!**). + default: enable-all + backend: QtWebEngine + restart: true + no_autoconfig: true # due to it being dangerous + desc: >- + What sandboxing mechanisms in Chromium to use. + + Chromium has various sandboxing layers, which should be enabled for normal + browser usage. Mainly for testing and development, it's possible to disable + individual sandboxing layers via this setting. + + Open `chrome://sandbox` to see the current sandbox status. + + Changing this setting is only recommended if you know what you're doing, as + it **disables one of Chromium's security layers**. To avoid sandboxing being + accidentally disabled persistently, this setting can only be set via + `config.py`, not via `:set`. + + See the Chromium documentation for more details: + - Linux: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/linux/sandboxing.md + - Windows: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox.md + - FAQ (Windows-centric): https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox_faq.md + qt.highdpi: type: Bool default: false diff --git a/qutebrowser/config/qtargs.py b/qutebrowser/config/qtargs.py index 165bdba5f..9e7f2620d 100644 --- a/qutebrowser/config/qtargs.py +++ b/qutebrowser/config/qtargs.py @@ -338,6 +338,11 @@ def _qtwebengine_settings_args(versions: version.WebEngineVersions) -> Iterator[ True: '--force-prefers-reduced-motion', False: None, }, + 'qt.chromium.sandboxing': { + 'enable-all': None, + 'disable-seccomp-bpf': '--disable-seccomp-filter-sandbox', + 'disable-all': '--no-sandbox', + } } qt_514_ver = utils.VersionNumber(5, 14) diff --git a/tests/end2end/test_invocations.py b/tests/end2end/test_invocations.py index b860feed0..0e252b741 100644 --- a/tests/end2end/test_invocations.py +++ b/tests/end2end/test_invocations.py @@ -826,3 +826,48 @@ def test_json_logging_without_debug(request, quteproc_new, runtime_tmpdir): quteproc_new.exit_expected = True quteproc_new.start(args, env={'XDG_RUNTIME_DIR': str(runtime_tmpdir)}) assert not quteproc_new.is_running() + + +@pytest.mark.qtwebkit_skip +@pytest.mark.parametrize('sandboxing, has_namespaces, has_seccomp, has_yama, expected_result', [ + ('enable-all', True, True, True, "You are adequately sandboxed."), + ('disable-seccomp-bpf', True, False, True, "You are NOT adequately sandboxed."), + ('disable-all', False, False, False, "You are NOT adequately sandboxed."), +]) +def test_sandboxing( + request, quteproc_new, sandboxing, + has_namespaces, has_seccomp, has_yama, expected_result, +): + args = _base_args(request.config) + [ + '--temp-basedir', + '-s', 'qt.chromium.sandboxing', sandboxing, + ] + quteproc_new.start(args) + + quteproc_new.open_url('chrome://sandbox') + text = quteproc_new.get_content() + print(text) + header, *lines, empty, result = text.split("\n") + + assert header == "Sandbox Status" + assert not empty + + status = dict(line.split("\t") for line in lines) + + bpf_text = "Seccomp-BPF sandbox" + yama_text = "Ptrace Protection with Yama LSM" + expected_status = { + "Layer 1 Sandbox": "Namespace" if has_namespaces else "None", + + "PID namespaces": "Yes" if has_namespaces else "No", + "Network namespaces": "Yes" if has_namespaces else "No", + + bpf_text: "Yes" if has_seccomp else "No", + f"{bpf_text} supports TSYNC": "Yes" if has_seccomp else "No", + + f"{yama_text} (Broker)": "Yes" if has_yama else "No", + f"{yama_text} (Non-broker)": "No", + } + + assert status == expected_status + assert result == expected_result diff --git a/tests/unit/config/test_qtargs.py b/tests/unit/config/test_qtargs.py index bc4029b3d..076ff6e3c 100644 --- a/tests/unit/config/test_qtargs.py +++ b/tests/unit/config/test_qtargs.py @@ -277,6 +277,28 @@ class TestWebEngineArgs: else: assert arg in args + @pytest.mark.parametrize('sandboxing, arg', [ + ('enable-all', None), + ('disable-seccomp-bpf', '--disable-seccomp-filter-sandbox'), + ('disable-all', '--no-sandbox'), + ]) + def test_sandboxing(self, config_stub, parser, sandboxing, arg): + config_stub.val.qt.chromium.sandboxing = sandboxing + parsed = parser.parse_args([]) + args = qtargs.qt_args(parsed) + + remaining_flags = { + '--no-sandbox', + '--disable-seccomp-filter-sandbox', + } + if arg is not None: + remaining_flags.remove(arg) + + if arg is not None: + assert arg in args + + assert not set(args) & remaining_flags + @pytest.mark.parametrize('qt_version, referer, arg', [ # 'always' -> no arguments ('5.15.0', 'always', None), -- cgit v1.2.3-54-g00ecf