diff --git a/src/ClawdDotNet.Core/Sandbox/BwrapSandbox.cs b/src/ClawdDotNet.Core/Sandbox/BwrapSandbox.cs index 382a936..3f5898f 100644 --- a/src/ClawdDotNet.Core/Sandbox/BwrapSandbox.cs +++ b/src/ClawdDotNet.Core/Sandbox/BwrapSandbox.cs @@ -62,8 +62,13 @@ public sealed class BwrapSandbox : ISandboxRunner return new NoSandbox("bubblewrap (bwrap) is not installed — 'apt install bubblewrap'"); var help = RunQuiet(bwrap, ["--help"]); - var probe = RunQuiet(bwrap, ["--unshare-all", "--die-with-parent", "--ro-bind", "/usr", "/usr", - "--symlink", "usr/bin", "/bin", "--symlink", "usr/lib", "/lib", "--proc", "/proc", "--dev", "/dev", "/bin/true"]); + // The probe mounts the system exactly as a real run does — a missing /lib64 (the + // dynamic loader) looks like "no such file" and would pass for a broken sandbox. + var probeArgs = new List { "--unshare-all", "--die-with-parent", "--ro-bind", "/usr", "/usr" }; + foreach (var (path, link) in HostLayout.Read().TopLevel) + probeArgs.AddRange(link is not null ? ["--symlink", link, path] : ["--ro-bind-try", path, path]); + probeArgs.AddRange(["--proc", "/proc", "--dev", "/dev", "/usr/bin/true"]); + var probe = RunQuiet(bwrap, probeArgs); if (probe.ExitCode != 0) return new NoSandbox($"bwrap cannot create a sandbox here ({probe.Output.Trim()}) — user namespaces may be disabled");