harkaq: el runtime base DERIVADO (§4.3) + el diagnóstico sobre un configure real (§4.4)
harkaq-base-closure.py: deriva el cierre dinámico del runtime base. Es D1
aplicado a la base — mantenerla a mano sería el "alguien mantiene un perfil de
permisos" que D1 dice que mata a todos los sandboxes. No usa ldd (resolvería
contra el HOST, no contra el rootfs Alpine): lee los DT_NEEDED del ELF y
resuelve dentro del rootfs por las rutas de musl. Emite symlink Y destino: el
kernel denuncia el fichero real (libz.so.1.3.2) pero el build abre por el nombre
corto (libz.so.1).
VALIDACIÓN: el cierre derivado de {sh,busybox,bash,coreutils,env} reproduce
EXACTAMENTE las 7 librerías que las rondas 2-3 habían descubierto a mano, en una
sola pasada, y además caza los symlinks y libc.musl-x86_64.so.1 que se habían
escapado. El método es computable, no adivinado.
§4.4 — con el entorno del Sandbox real replicado (CC="zig cc -mcpu=baseline",
AR, SOURCE_DATE_EPOCH, LC_ALL=C), configure llega mucho más lejos: 205
denegaciones del kernel, y clasificadas:
esperadas (170): /usr/bin/gcc, /usr/bin/ldd ← sondas de compilador
DEUDA (34) en 8 paths:
/usr/bin/{ld,nm,objdump,strip} ← binutils de ALPINE
/usr/bin/{make,getconf}
/usr/lib/gcc/x86_64-alpine-linux-musl ← libdir del gcc de ALPINE
/opt ← bug de política
Es la tesis del §0 hecha dato: un configure que se creía hermético va a buscar
los binutils y el libdir de gcc de Alpine. Y la clasificación es lo que lo hace
legible — sin ella son 205 denegaciones planas y el hallazgo queda enterrado;
con ella son 8 paths accionables. Coincide con los swaps del selfhost-verify y
con la campaña "matar gcc" (recipes/binutils.toml existe justo porque zig provee
as/ld/ar pero el resto se toma de Alpine).
Bug de política encontrado por el propio experimento: /opt sale como deuda
porque la política concede `ro /opt/zig` pero no deja LISTAR el padre. Regla
general: todo directorio concedido necesita `list` en sus ancestros, o el escaneo
del padre es un falso positivo. harkaq-policy.sh ya lo hace para la clausura de
las deps; falta para las superficies de contrato.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+39
-2
@@ -461,8 +461,45 @@ no 5. Pero las tres cosas que importan salieron bien:
|
||||
plausible.
|
||||
3. **El runtime base no es una lista de binarios: es su CIERRE de `.so`.** Conceder `/bin/bash`
|
||||
arrastra `libreadline`+`libncursesw`; conceder `/bin/coreutils` arrastra `libacl`+`libattr`.
|
||||
Eso es *computable* (`ldd`), no adivinable ⇒ `harkaq-policy` debe derivar también el cierre
|
||||
dinámico del runtime base, igual que deriva la clausura de las deps. Misma idea, otro origen.
|
||||
Eso es *computable*, no adivinable ⇒ **ya está derivado** (`harkaq-base-closure.py`). Es D1
|
||||
aplicado al runtime base: mantenerlo a mano sería exactamente el "alguien mantiene un perfil
|
||||
de permisos" que D1 dice que mata a todos los sandboxes.
|
||||
|
||||
No usa `ldd` (resolvería contra el host, no contra el rootfs Alpine): lee los `DT_NEEDED` del
|
||||
ELF y resuelve dentro del rootfs por las rutas de musl. **Validación:** el cierre derivado de
|
||||
`{sh, busybox, bash, coreutils, env}` reproduce **exactamente** las 7 librerías que las rondas
|
||||
2 y 3 habían descubierto a mano, en una sola pasada, y además caza los symlinks y
|
||||
`libc.musl-x86_64.so.1` que se habían escapado. Emite symlink **y** destino: el kernel denuncia
|
||||
el fichero real (`libz.so.1.3.2`, no `libz.so.1`), pero el build abre por el nombre corto.
|
||||
|
||||
### 4.4 El diagnóstico sobre un `configure` real, con el entorno fiel
|
||||
|
||||
Con el entorno del sandbox real replicado (`CC="zig cc -mcpu=baseline"`, `AR`, `SOURCE_DATE_EPOCH`,
|
||||
`LC_ALL=C`…), `configure` llega mucho más lejos y el diagnóstico se vuelve el que el proyecto
|
||||
prometía. **205 denegaciones del kernel**, y tras clasificar:
|
||||
|
||||
```
|
||||
esperadas (170): /usr/bin/gcc, /usr/bin/ldd ← sondas de compilador
|
||||
DEUDA (34) en 8 paths:
|
||||
/usr/bin/ld /usr/bin/nm /usr/bin/objdump /usr/bin/strip ← binutils de ALPINE
|
||||
/usr/bin/make /usr/bin/getconf
|
||||
/usr/lib/gcc/x86_64-alpine-linux-musl ← libdir del gcc de ALPINE
|
||||
/opt ← (bug de política, ver abajo)
|
||||
```
|
||||
|
||||
**Esto es la tesis del §0 hecha dato.** Un `configure` que se creía hermético está yendo a buscar
|
||||
los binutils y el libdir de gcc de Alpine. Y la clasificación es lo que lo hace legible: sin ella
|
||||
son 205 denegaciones planas y el hallazgo queda enterrado; con ella son **8 paths accionables**.
|
||||
|
||||
Conecta con dos frentes abiertos, y en ambos la lista coincide: los swaps del `selfhost-verify`
|
||||
(`SWAP_COREUTILS`, las herramientas en el path) y la campaña *matar gcc* (`recipes/binutils.toml`
|
||||
existe justamente porque zig provee `as/ld/ar` pero el resto se toma de Alpine).
|
||||
|
||||
**Bug de política encontrado por el propio experimento:** `/opt` aparece como deuda porque la
|
||||
política concede `ro /opt/zig` pero no deja **listar** el padre. Regla general: **todo directorio
|
||||
concedido necesita `list` en sus ancestros**, o el escaneo del padre es un falso positivo.
|
||||
`harkaq-policy.sh` ya lo hace para la clausura de las deps; falta hacerlo para las superficies de
|
||||
contrato.
|
||||
|
||||
**Y el residuo es todo significativo, ninguno ruido:**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user