🛡️ sandbox-labs GitHub ↗

đź”§ Cuando algo falla#

Los fallos de este proyecto no son aleatorios: casi todos vienen de que el equipo no puede aplicar un control que la polĂ­tica pide. Y eso es informaciĂłn, no una averĂ­a.

Este documento reúne los fallos que afectan a cualquier caso. Cada ficha de caso tiene además su propia sección «Si algo falla» con lo específico suyo.

La regla que explica casi todo lo de aquí. Si una política estricta pide un control obligatorio que este equipo no puede aplicar, la ejecución no ocurre: falla cerrada y dice qué falta. Eso es el comportamiento correcto. La alternativa —ejecutar con menos controles de los pedidos— es exactamente cómo se construyen sistemas que parecen seguros.

Lo primero, siempre#

cargo run -p sandboxctl -- doctor

Enumera qué runtimes hay en tu equipo, qué controles puede aplicar cada uno aquí, y cuáles se pedirán pero no se podrán aplicar. Nueve de cada diez fallos se explican con esa salida.


ĂŤndice#


No se puede crear el sandbox#

bwrap: No permissions to creating new namespace
bwrap: setting up uid map: Permission denied

Qué pasa. El sistema no permite crear namespaces de usuario sin privilegios. Es la base de todo el aislamiento sin root, así que sin esto no hay jaula.

Alternativas, de la mejor a la peor:

AlternativaCómoQué pierdes
1. Habilitarlos (recomendado)En Debian/Ubuntu antiguo: sudo sysctl -w kernel.unprivileged_userns_clone=1. En Ubuntu 23.10+ además: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0Nada. Es la vía prevista
2. Usar el runtime unshare--runtime unshareEs más débil: no aísla el sistema de ficheros. El proyecto lo declara así, no lo disimula
3. Planificar sin ejecutar--runtime dry-runNo se ejecuta nada: se genera el plan y la evidencia de lo que habrĂ­a ocurrido
4. Una máquina virtual desechableCualquier VM LinuxNada, salvo comodidad. Es lo correcto para cargas desconocidas de verdad

Lo que no debes hacer: ejecutar el proyecto como root para saltarte el lĂ­mite. Un sandbox creado por root es un sandbox del que se sale siendo root.


No hay lĂ­mites de memoria, CPU o procesos#

systemd-run: Failed to connect to bus
Los controles memory, cpu y processes no aparecen en effectiveControls

Qué pasa. Los tres límites se piden con systemd-run --user --scope, que necesita systemd en modo usuario y cgroups v2. En WSL2 sin systemd, o en contenedores, no está.

Por qué no se escriben los cgroups directamente: en WSL2 /init.scope no es escribible. Pasar por systemd-run funciona en los dos entornos.

Alternativas:

AlternativaCómoQué pierdes
1. Activar systemd en WSL2En /etc/wsl.conf: [boot] y systemd=true. Después wsl --shutdown desde WindowsNada
2. Aceptar que no hay lĂ­mitesNada: el proyecto no los declara en la evidenciaEl techo de memoria y CPU. Sigue habiendo aislamiento de red, ficheros, entorno y capacidades
3. Usar una polĂ­tica no estrictaQuitar el modo strict de la polĂ­ticaLa garantĂ­a de que se aplica lo pedido. Ăšsalo solo para probar

Cuidado con el caso 11 y el caso 12. AhĂ­ memory.max no es un lujo: sin techo de memoria, una imagen de dimensiones absurdas o un notebook mal escrito se llevan el equipo por delante. Con polĂ­tica estricta, esos casos deben negarse a ejecutar si no hay cgroups, y eso es lo correcto.


Un puerto está ocupado#

Address already in use (os error 98)

Qué pasa. Casi siempre es un reenviador de puertos de una sesión anterior que sigue vivo, no otro programa.

cargo run -p sandboxctl -- service down --all

Ese comando baja también los huérfanos: procesos que quedaron vivos sin registro. Si aun así sigue ocupado, mira quién lo tiene:

ss -ltnp | grep 880

Un servicio se levanta y se muere solo#

Qué pasa. Lo más común es una incoherencia entre el transporte que declara el servicio y la red que le concede la política: un servicio con transport: tcp dentro de una jaula con network: none no tiene dónde escuchar.

El proyecto lo comprueba antes de arrancar y lo dice, en vez de dejarlo morir en silencio.

Alternativas:

SituaciónQué hacer
El servicio necesita publicar un puerto y quieres que no tenga redtransport: unix-socket y publish: proxy. El servicio escucha en un socket Unix dentro de la jaula, y un reenviador de fuera publica el puerto. Es lo que hacen los casos 01, 02, 03 y 05
El servicio necesita red de verdadPolítica con network: unrestricted — y que quede escrito, porque deja de estar contenido en esa dimensión
Necesita salir solo a unos destinosnetwork: allowlist. Se le da un namespace propio y un proxy con lista, que además registra cada intento

Quedaron procesos vivos que no aparecen en la lista#

PasĂł de verdad en este proyecto: tres sandboxes sobrevivieron cuatro horas sin que nada pudiera encontrarlos, porque se habĂ­a quitado --die-with-parent y un script de limpieza habĂ­a borrado sus registros.

cargo run -p sandboxctl -- service down --all

El barrido busca dos clases de huérfano: la jaula (bwrap con

comandos). Si sospechas que queda algo:

ps -eo pid,args | grep -E '[b]wrap|[s]andboxctl' 

Y no borres .sandbox-data a mano mientras haya servicios levantados: ahĂ­ viven los registros que permiten encontrarlos. scripts/cleanup-test-state.mjs se niega a hacerlo por ese motivo.


Errores de compilaciĂłn#

En Windows: dlltool.exe: CreateProcess#

La cadena de compilaciĂłn de GNU incompleta. Este proyecto se compila en WSL2, no en Windows nativo:

wsl
cargo build --release

error: the lock file needs to be updated#

construcciĂłn. No lo borres.

cargo metadata --locked --format-version 1 > /dev/null

pnpm: command not found#

corepack enable pnpm

No uses npm. El proyecto usa pnpm y conserva su fichero de bloqueo; mezclar gestores produce árboles de dependencias distintos entre tu equipo y CI.


Problemas del sistema de ficheros en WSL2#

Trabajando sobre /mnt/c puede aparecer algo desconcertante: mkdir responde «File exists» y ls dice que no existe. Es una desincronización de la caché de DrvFs, el puente entre Windows y Linux.

Alternativas:

AlternativaCĂłmo
1. ReintentarEl proyecto ya tolera este caso en dirs.rs, que trata «existe» como éxito
2. Trabajar desde el sistema de ficheros de LinuxClonar en ~/ en vez de en /mnt/c. Además es bastante más rápido
3. Reiniciar WSLwsl --shutdown desde Windows

La verificaciĂłn de evidencia falla#

cargo run -p sandboxctl -- evidence verify

Cada tipo de fallo significa algo distinto, y solo dos son problemas:

Lo que diceQué significa¿Es un problema?
Huella SHA-256 no coincideEl fichero de evidencia se modificĂłSĂ­
Firma Ed25519 inválidaAlguien rehízo el documento y recalculó la huellaSí
Cadena rotaFalta un informe intermedioSĂ­, salvo que lo borraras tĂş
Hash de polĂ­tica o de carga distintoEl cĂłdigo cambiĂł desde aquella ejecuciĂłnNo. Es un informe viejo diciendo con razĂłn que ya no describe el cĂłdigo de hoy

Ese último caso es el que más confunde. Vuelve a ejecutar para generar evidencia del código actual.

La firma no es una notarización. La clave la guarda la misma máquina que ejecuta, así que prueba que el informe no cambió tras escribirse, no que la ejecución ocurriera.

Los diagramas del sitio no se ven#

Los diagramas se dibujan con una biblioteca que se descarga de un CDN. Sin red, con el CDN caĂ­do o con un bloqueador de por medio, el diagrama se queda como cĂłdigo legible en vez de desaparecer. No es un fallo que haya que arreglar: es la degradaciĂłn prevista.


Funciona en local y falla en CI#

Suele ser una diferencia de configuraciĂłn del kernel del runner, no del cĂłdigo. Casos reales de este proyecto:

SĂ­ntomaCausaSoluciĂłn aplicada
La sonda de seccomp daba resultados distintosperf_event_paranoid cambia el error que devuelve perf_event_open entre máquinasSe cambió a getcpu, que siempre funciona: si devuelve EPERM, el filtro está puesto
Variables del bus se filtraban dentro de la jaula--clearenv limpia el entorno de la carga, no el del proceso que la lanzaSe vacĂ­a el entorno entero con env -i, no variable a variable
Un git push no disparaba los workflowsComportamiento del propio GitHub Actionsgh workflow run ci.yml --ref main

Cuando nada de lo anterior sirve#

  1. Lee la evidencia de la ejecución. Está en evidence/runs/ y distingue

requestedControls, effectiveControls, unsupportedControls, failedControls y observedControls. La diferencia entre las dos primeras listas suele ser la respuesta entera.

  1. Ejecuta la suite de contenciĂłn: cargo run -p sandboxctl -- escape. Si

las sondas fallan, el problema es del entorno y no de tu caso.

  1. Comprueba el catálogo: pnpm config:check valida que políticas, cargas y

casos están bien declarados.

  1. Abre una incidencia con la salida de doctor y la evidencia de la

ejecuciĂłn. Sin esas dos cosas, cualquier diagnĂłstico es adivinar.


Ver también: Estado del proyecto · Catálogo completo · Fichas de los casos · Runbook · Referencia de políticas