Skip to content

Commit e04e105

Browse files
linesightclaude
andcommitted
refactor(linux): drop sandbox-availability probe; --no-sandbox unconditionally
Revert Linux sandbox handling to the minimal change needed for CEF 147. The old code set no_sandbox=1 in CefSettings, which in 147 makes BasicStartupComplete() append --no-sandbox before the Mojo bootstrap fd (GlobalDescriptors key 7) is registered, crashing every subprocess with "Failed global descriptor lookup: 7". Linux now passes the --no-sandbox command-line switch unconditionally instead -- the same "sandbox off" behavior cefpython has always had, via the mechanism 147 requires. Removes the runtime sandbox-availability probe (sandbox_linux.cpp/.h/ .pxd, the cimport, the window_utils_linux.pyx conditional and its Knowledge-Base section). Keeping the sandbox enabled where the system supports it belongs in a separate change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 42a42bf commit e04e105

6 files changed

Lines changed: 12 additions & 227 deletions

File tree

docs/Knowledge-Base.md

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ Table of contents:
1818
* [Windows XP support](#windows-xp-support)
1919
* [Mac 32-bit support](#mac-32-bit-support)
2020
* [Security](#security)
21-
* [Linux: the Chromium sandbox](#linux-the-chromium-sandbox)
2221

2322

2423
## Notifications about new releases / commits
@@ -376,60 +375,3 @@ A quote by Marshall Greenblatt:
376375
Reference: [Question on browser security](http://magpcss.org/ceforum/viewtopic.php?f=10&t=10222)
377376
on the CEF Forum.
378377

379-
380-
### Linux: the Chromium sandbox
381-
382-
cefpython keeps the Chromium sandbox **enabled** whenever the system can
383-
support it, and passes `--no-sandbox` only as a fallback when no usable
384-
sandbox is detected (`_linux_apply_initialize_defaults` /
385-
`_linux_sandbox_available` in `src/window_utils_linux.pyx`).
386-
387-
At `cef.Initialize()` cefpython decides as follows:
388-
1. If `CHROME_DEVEL_SANDBOX` points to an existing SUID-root helper, the
389-
sandbox is kept.
390-
2. Else, if a kernel switch disables unprivileged user namespaces
391-
(`kernel.apparmor_restrict_unprivileged_userns=1` — the default on
392-
Ubuntu 23.10+/Debian 12+; `kernel.unprivileged_userns_clone=0`;
393-
`user.max_user_namespaces=0`), `--no-sandbox` is added.
394-
3. Else a real `unshare(CLONE_NEWUSER)` probe is run in a forked child (this
395-
also catches container seccomp policies, e.g. Docker's default, that block
396-
the syscall without setting any of the switches above). If it fails,
397-
`--no-sandbox` is added.
398-
399-
When cefpython falls back to `--no-sandbox` it emits a `UserWarning` so the
400-
security downgrade is visible; renderer processes then run unsandboxed
401-
(seccomp-bpf still applies).
402-
403-
Why not just ship the sandbox: a pip wheel cannot install a
404-
chown-root + chmod-4755 `chrome-sandbox` helper (pip runs as the user and has
405-
no postinst hook), so on systems where unprivileged user namespaces are
406-
restricted the only out-of-box option is `--no-sandbox`.
407-
408-
**Forcing the sandbox off.** Pass `switches={"no-sandbox": ""}` to
409-
`cef.Initialize()`; an explicit value is respected and the auto-detection is
410-
skipped.
411-
412-
**Enabling the sandbox on a restricted system.** If your app loads untrusted
413-
web content on a distro where unprivileged user namespaces are disabled,
414-
install the SUID-root helper and point `CHROME_DEVEL_SANDBOX` at it — no
415-
source patch or extra switches needed, cefpython will then keep the sandbox:
416-
417-
```bash
418-
sudo cp /path/to/cef_binary_<ver>_linux64/Release/chrome-sandbox \
419-
/opt/cef/chrome-sandbox
420-
sudo chown root:root /opt/cef/chrome-sandbox
421-
sudo chmod 4755 /opt/cef/chrome-sandbox
422-
```
423-
424-
```python
425-
import os
426-
os.environ["CHROME_DEVEL_SANDBOX"] = "/opt/cef/chrome-sandbox"
427-
```
428-
429-
Verify Chromium subprocesses launched under the sandbox (no `--no-sandbox`
430-
in their argv, no `FATAL: No usable sandbox!`):
431-
432-
```bash
433-
ps -Af | grep "type=gpu" | grep -v "no-sandbox"
434-
```
435-

src/cefpython.pyx

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,6 @@ from task cimport *
225225

226226
IF UNAME_SYSNAME == "Linux":
227227
cimport x11
228-
cimport sandbox_linux
229228

230229
from cef_string cimport *
231230
cdef extern from *:
@@ -618,15 +617,12 @@ def Initialize(applicationSettings=None, commandLineSwitches=None, **kwargs):
618617

619618
cdef CefSettings cefApplicationSettings
620619
IF UNAME_SYSNAME == "Linux":
621-
# On Linux, leave no_sandbox=0 so Chrome's startup code registers the
622-
# Mojo IPC bootstrap fd (GlobalDescriptors key 7) for every subprocess.
623-
# Setting no_sandbox=1 would cause BasicStartupComplete() to append
624-
# --no-sandbox before fd registration, causing all subprocesses to crash
625-
# with "Failed global descriptor lookup: 7". Sandbox behaviour is instead
626-
# controlled by the --no-sandbox command-line switch, which
627-
# _linux_apply_initialize_defaults() adds only when no usable sandbox is
628-
# detected (see the native LinuxSandboxAvailable() in
629-
# src/client_handler/sandbox_linux.cpp).
620+
# On Linux, leave no_sandbox=0 here. Setting no_sandbox=1 would cause
621+
# BasicStartupComplete() to append --no-sandbox before Chrome's startup
622+
# code registers the Mojo IPC bootstrap fd (GlobalDescriptors key 7),
623+
# crashing every subprocess with "Failed global descriptor lookup: 7".
624+
# The sandbox is instead disabled via the --no-sandbox command-line
625+
# switch added in _linux_apply_initialize_defaults().
630626
pass
631627
ELSE:
632628
# On Windows/macOS the sandbox helper binary is not shipped with

src/client_handler/sandbox_linux.cpp

Lines changed: 0 additions & 94 deletions
This file was deleted.

src/client_handler/sandbox_linux.h

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/extern/sandbox_linux.pxd

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/window_utils_linux.pyx

Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -150,47 +150,10 @@ def _linux_apply_initialize_defaults(app_settings, cmd_switches):
150150
# False — no delete_event would be dispatched on a windowed popup.
151151
app_settings.setdefault("windowless_rendering_enabled", True)
152152

153-
# Chromium's Linux sandbox — keep it when possible, disable only if unusable.
154-
#
155-
# CEF Linux builds default sandbox-ON and refuse to start unless either a
156-
# SUID-root chrome-sandbox helper is installed or --no-sandbox is passed.
157-
# A pip wheel cannot install a chown-root + chmod-4755 helper, so cefpython
158-
# relies on Chromium's unprivileged-user-namespace sandbox instead. That
159-
# path works on most systems, but modern distros (Ubuntu 23.10+, Debian 12+)
160-
# set kernel.apparmor_restrict_unprivileged_userns=1 by default, and
161-
# containers often block the unshare() syscall via seccomp — in those cases
162-
# Chromium aborts with "FATAL: No usable sandbox!" unless --no-sandbox is
163-
# passed.
164-
#
165-
# So probe for a usable sandbox and only fall back to --no-sandbox when none
166-
# is available, keeping renderers confined wherever the namespace sandbox
167-
# works. Historically cefpython passed --no-sandbox unconditionally, which
168-
# silently disabled the sandbox even on capable systems. A user can force
169-
# the sandbox off by passing switches={"no-sandbox": ""} explicitly, or
170-
# enable it on a restricted system by installing the SUID helper and setting
171-
# CHROME_DEVEL_SANDBOX (see docs/Knowledge-Base.md "Linux: enabling the
172-
# Chromium sandbox").
153+
# Chromium's Linux sandbox. CEF Linux builds default sandbox-ON and refuse
154+
# to start unless a SUID-root chrome-sandbox helper is installed or
155+
# --no-sandbox is passed. A pip wheel cannot install a chown-root helper,
156+
# so cefpython disables the sandbox on Linux, as it always has. Added only
157+
# when the caller has not set the switch explicitly.
173158
if "no-sandbox" not in cmd_switches:
174-
# Some switches turn off the zygote / multiprocess model, which
175-
# Chromium requires for the sandbox — it refuses to start otherwise
176-
# with "Zygote cannot be disabled if sandbox is enabled". When the
177-
# caller has opted into any of these, pair them with --no-sandbox.
178-
_needs_no_sandbox = any(
179-
_sw in cmd_switches
180-
for _sw in ("no-zygote", "disable-zygote", "single-process"))
181-
if _needs_no_sandbox:
182-
cmd_switches["no-sandbox"] = ""
183-
elif not sandbox_linux.LinuxSandboxAvailable():
184-
cmd_switches["no-sandbox"] = ""
185-
import warnings
186-
warnings.warn(
187-
"cefpython: Chromium sandbox disabled (--no-sandbox). No usable "
188-
"sandbox was detected — unprivileged user namespaces appear to "
189-
"be restricted (e.g. kernel.apparmor_restrict_unprivileged_userns"
190-
"=1 on Ubuntu 23.10+/Debian 12+, or a container seccomp policy) "
191-
"and no CHROME_DEVEL_SANDBOX helper is configured. Renderer "
192-
"processes will run without the sandbox. See "
193-
"docs/Knowledge-Base.md 'Linux: enabling the Chromium sandbox' "
194-
"to enable it.",
195-
stacklevel=2,
196-
)
159+
cmd_switches["no-sandbox"] = ""

0 commit comments

Comments
 (0)