diff --git a/crates/hammer-build/src/sandbox.rs b/crates/hammer-build/src/sandbox.rs index 5cc6fb64..f9d69187 100644 --- a/crates/hammer-build/src/sandbox.rs +++ b/crates/hammer-build/src/sandbox.rs @@ -253,6 +253,10 @@ impl Sandbox { fn contratos_harkaq(&self) -> Vec { let mut v: Vec = [ "rw /src", "rw /out", "rw /tmp", "rw /dev/null", "ro /dev/urandom", "ro /opt/zig", + // `--proc /proc`: bwrap monta un /proc FRESCO dentro del pidns del sandbox. No sale + // del rootfs Alpine y no ve al host ⇒ contrato, no deuda. Lo destapó brotli, cuyo + // configure lee /proc/cpuinfo y /proc/meminfo para dimensionar el paralelismo. + "ro /proc", "list /", "list /opt", ] .iter() diff --git a/docs/16-harkaq-jaula.md b/docs/16-harkaq-jaula.md index d680c8cd..f981f9fd 100644 --- a/docs/16-harkaq-jaula.md +++ b/docs/16-harkaq-jaula.md @@ -808,6 +808,78 @@ el silencio de un lector roto. --- +### 4.9 Matar gcc: la última milla, cerrada + +El primer barrido (§4.6) dejó **un solo** caso irreducible: brotli pidiendo +`libstdc++.so.6.0.34` + `libgcc_s.so.1`. brotli es **C**, no C++ — la libstdc++ no era suya. + +Era de `cmake`, su dep de build. El artefacto que **hammer construye**: + +``` +store/99864dcc…-cmake/usr/bin/cmake + NEEDED: libstdc++.so.6, libgcc_s.so.1, libc.so +``` + +Y la receta lo explicaba sin verlo: `CC=gcc CXX=g++` *"el cmake mínimo que `bootstrap` compila con +`zig c++` SEGFAULTEA al correr"*. O sea que "gcc retenido para {kernel, cmake}" no era una +concesión de *build-time* como sonaba: **el artefacto de cmake arrastraba el runtime C++ de Alpine +hacia dentro de cada build que lo declarara como dep**. Un agujero de soberanía que viajaba por el +grafo de deps, invisible en la receta del consumidor. + +**El arreglo no toca el compilador** — gcc sigue compilando cmake, que es el camino conocido-bueno. +Sólo deja de enlazar su runtime en dinámico: + +``` +CXX='g++ -static-libstdc++ -static-libgcc' LDFLAGS='-static-libstdc++ -static-libgcc' +``` + +Medido: + +| | NEEDED | | +|---|---|---| +| antes | `libstdc++.so.6`, `libgcc_s.so.1`, `libc.so` | arrastra el runtime de gcc de Alpine | +| después | `libc.musl-x86_64.so.1` | **y corre: `cmake version 3.31.6`** | + +**Y el pago:** brotli —el único irreducible del barrido— pasa a **`Hermetico` ×3 fases**, artefacto +sellado `b3:bc900676…`. Su deuda restante (`ld`, `make`) era declarable y se declaró. + +El barrido queda **0 irreducibles de 6**. El caso que iba a contar contra el <5% no era una receta +mal escrita: era una herramienta de hammer filtrando Alpine, y harkaq la señaló desde el consumidor. + +**Costo del rollout, a decidir:** cambiar `recipes/cmake.toml` re-hashea cmake y sus 3 consumidores +(brotli, libjpeg-turbo, libtiff = 6 artefactos sellados). Radio chico, pero **libjpeg-turbo y +libtiff son la cadena GUI**, y la regla del proyecto es no rebuildearla en el laptop (el zig-skew +rompe cairo). El rebuild va al worker. + +**Lo que NO cierra esto:** `/usr/bin/gcc`, `c89`, `c99`, `ldd` y el plugin LTO de §4.7 siguen +siendo *sondas* — la jaula las deniega, los builds completan igual, y denegarlas es lo correcto. +El gcc de Alpine sigue en el rootfs y sigue haciendo falta para {kernel, cmake} **en build-time**. +Lo cerrado es la filtración a *runtime*, que es la que contaminaba artefactos. + +### 4.8 El barrido NO sale por la granja VPS (todavía): la imagen golden es ABI 4 + +Medido en `hworker-4` (2026-07-15) con el syscall, que es la única vía válida: + +``` +kernel 6.8.0-134-generic (Ubuntu 24.04) → LANDLOCK ABI = 4 +CONFIG_SECURITY_LANDLOCK=y CONFIG_AUDIT=y sin auditd compitiendo +``` + +Landlock está compilado y el audit también, y no hay `auditd` peleando por el netlink — pero +**ABI 4 < 7 ⇒ no hay audit de denegaciones**. Por D7 la granja correría la jaula y emitiría +`SinEvidencia` en **todos** los builds: exactamente lo que el diseño manda hacer, y exactamente lo +que no sirve para medir. + +**El arreglo es chico y está identificado:** `linux-image-generic-hwe-24.04` → **6.17.0-40** está +en el archivo estándar de Ubuntu 24.04 (no hace falta PPA ni cambiar de distro). Un `apt install` ++ reboot + verificar ABI + re-snapshot de la imagen golden (`IMAGE=405120842`). El barrido grande +depende de ese bump, no de más diseño. + +Nota operativa: `hworker-4` está vivo con la campaña KDE; el bump conviene hacerlo en un worker +efímero nuevo (`farm-up 1`) y re-snapshotear desde ahí, sin tocarlo. + +--- + **Fase 2 — `harkaq-policy` completo + medir la brecha.** Clausura real, `/src`, `/out`, `/tmp`, `/cache`, `/proc` y `/dev` mínimos, y el **runtime base** (sin `/bin/sh` ni la libc del rootfs no arranca nada — ver Q3). Correr contra N recetas del catálogo y medir la tasa de falsos positivos. diff --git a/recipes/cmake.toml b/recipes/cmake.toml index aa523d21..341229de 100644 --- a/recipes/cmake.toml +++ b/recipes/cmake.toml @@ -11,6 +11,14 @@ # auto-configura. Enlace dinámico (un cmake estático con libc++/libstdc++ es impráctico y no aporta # nada a una herramienta de build-time; la VM ya tiene libstdc++ runtime). # +# -static-libstdc++ -static-libgcc: MATAR GCC, la última milla (SDD 16 §4.9). gcc sigue siendo el +# COMPILADOR (ver abajo: zig c++ segfaultea el cmake mínimo), pero su runtime C++ se hornea DENTRO +# del binario en vez de enlazarse dinámico. Sin esto el artefacto pedía libstdc++.so.6+libgcc_s.so.1 +# de Alpine EN TIEMPO DE EJECUCIÓN, y como cmake es dep de build de otras recetas, arrastraba el +# runtime de gcc de Alpine hacia dentro de CADA build que lo declarara — harkaq lo cazó como la +# única deuda IRREDUCIBLE del primer barrido (brotli). Medido: NEEDED pasó de +# [libstdc++.so.6, libgcc_s.so.1, libc.so] a [libc.musl-x86_64.so.1] y brotli pasó a Hermetico ×3. +# # CC=gcc/CXX=g++ (NO zig): el cmake mínimo que `bootstrap` compila con `zig c++` SEGFAULTEA al correr # ("Problem while running initial CMake") — interacción libc++/musl de zig. Alpine mismo compila cmake # con gcc; el toolchain trae gcc/g++ (añadidos para mrustc) y funcionan nativos dentro del sandbox @@ -32,6 +40,6 @@ link = "dynamic" [build.phases] # bootstrap = configure de CMake. --parallel acelera el cmake mínimo. -- pasa flags al cmake final; # CMAKE_USE_OPENSSL=OFF evita depender de openssl-dev (el bootstrap de rust no usa el https de cmake). -configure = "CC=gcc CXX=g++ ./bootstrap --prefix=/usr --parallel=\"$(nproc)\" -- -DCMAKE_BUILD_TYPE=Release -DCMAKE_USE_OPENSSL=OFF" -compile = "CC=gcc CXX=g++ make -j\"$(nproc)\"" +configure = "CC=gcc CXX='g++ -static-libstdc++ -static-libgcc' LDFLAGS='-static-libstdc++ -static-libgcc' ./bootstrap --prefix=/usr --parallel=\"$(nproc)\" -- -DCMAKE_BUILD_TYPE=Release -DCMAKE_USE_OPENSSL=OFF" +compile = "CC=gcc CXX='g++ -static-libstdc++ -static-libgcc' LDFLAGS='-static-libstdc++ -static-libgcc' make -j\"$(nproc)\"" install = "make install DESTDIR=/out"