CORRECCIÓN ESTRUCTURAL del §4 (otra herencia del marco nix). El Draft 2 decía
`fs_ro: [store paths de la clausura]`. Falso: esos paths NO existen dentro del
sandbox. `Sandbox::bwrap_args` apila las deps con --overlay-src y las FUNDE en
el mismo /usr que el rootfs Alpine, a propósito, para que el compilador las
encuentre sin plumbing de flags. Medido:
/usr/include/zlib.h (dep DECLARADA) dev=63 ino=13641973
/usr/include/stdio.h (Alpine, NO declarado) dev=63 ino=4196788
/usr/include (el directorio) dev=61 ino=15 ← overlayfs, uno
Una regla sobre /usr concede las dos ⇒ la evidencia no valdría nada. Ni `dev`
distingue. ⇒ La clausura se enumera FICHERO A FICHERO (computable: en el host
sabemos qué aporta cada dep). Dos consecuencias: `list` ≠ `ro` (pkgconf NECESITA
escanear /usr/lib/pkgconfig, pero listar no es leer; Landlock separa READ_DIR de
READ_FILE) y máscara por tipo (derechos de-sólo-dir sobre un fichero ⇒ EINVAL y
la regla entera se cae).
Piezas nuevas: harkaq-policy.sh (deriva la clausura, D1) + q2-runtime-base.sh
(responde Q2 midiendo, no adivinando) + harkaq-exec con `list`/máscara por tipo.
Q2, primeros datos con un build REAL en el sandbox REAL contra la dep zlib:
estado: Impuro | canario: True | contador kernel: 3
fs.read_file /usr/bin/env
fs.read_file /usr/lib/libz.so.1.3.2 ← la zlib de ALPINE!
El build se linkaba contra la zlib de Alpine en vez de la dep declarada (que
aporta libz.a). Sin harkaq eso pasa en verde y el artefacto queda dependiendo de
Alpine. ES EXACTAMENTE EL BUG DEL §0, cazado en un build real.
Piso duro del runtime base: /bin/sh → /bin/busybox → /lib/ld-musl (sin eso ni el
canario corre ⇒ el mínimo es "lo que hace falta para que el canario pueda correr").
Dos rastrillos: el canario no puede depender de un binario (`cat` moría en
/bin/cat ⇒ ahora `read _ < $CANARY`, sólo builtins) ni vivir en /tmp (la política
concede `rw /tmp` ⇒ el canario caía DENTRO de la clausura y no denegaba nada).
El segundo lo cazó D9 MISMO: el lector se negó a certificar en vez de decir
Hermetico. El canario funcionando como se diseñó, sobre un bug de quien lo diseñó.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
52 lines
2.2 KiB
Bash
Executable File
52 lines
2.2 KiB
Bash
Executable File
#!/bin/sh
|
|
# harkaq-policy — deriva la política de la clausura declarada (SDD 16, D1).
|
|
#
|
|
# harkaq-policy.sh <dir-dep> [<dir-dep>...] > politica
|
|
#
|
|
# D1: la política NO se escribe, se DERIVA. La receta ya declara sus `deps` por hash; cada dep
|
|
# es un artefacto sellado del store (`store/<hash>-<name>/usr/...`). La clausura es, exactamente,
|
|
# el conjunto de ficheros que esas deps aportan — ni uno más.
|
|
#
|
|
# El sandbox de hammer apila cada dep con `--overlay-src` sobre el rootfs Alpine, así que el
|
|
# fichero `store/<hash>-zlib/usr/include/zlib.h` aparece dentro como `/usr/include/zlib.h`. La
|
|
# traducción es sólo quitar el prefijo del store: el resto del path YA es el path del sandbox.
|
|
#
|
|
# Por qué fichero a fichero y no por directorio: adentro, la dep declarada y el rootfs Alpine
|
|
# comparten `/usr` (medido: /usr/include/zlib.h y /usr/include/stdio.h son el mismo directorio
|
|
# overlayfs). Una regla sobre /usr concede los dos y la evidencia deja de significar algo. Los
|
|
# `list` de los directorios se emiten para que las herramientas puedan ESCANEAR (pkgconf, los
|
|
# tests de configure) sin poder LEER lo no declarado — Landlock separa READ_DIR de READ_FILE.
|
|
set -eu
|
|
|
|
emit_dirs() {
|
|
# Los directorios que contienen ficheros de la clausura: listables, no legibles.
|
|
# Se emiten deduplicados y con sus ancestros, porque un `ls /usr` también es un escaneo
|
|
# legítimo y su denegación sería un falso positivo, no deuda de de-Alpinización.
|
|
while IFS= read -r d; do
|
|
while [ "$d" != "/" ] && [ -n "$d" ]; do
|
|
echo "list $d"
|
|
d=$(dirname "$d")
|
|
done
|
|
done | sort -u
|
|
}
|
|
|
|
TMP="$(mktemp)"
|
|
trap 'rm -f "$TMP" "$TMP.d"' EXIT
|
|
: > "$TMP"
|
|
: > "$TMP.d"
|
|
|
|
for dep in "$@"; do
|
|
real=$(readlink -f "$dep")
|
|
# `.hammer/` es metadata del artefacto (recipe.toml), no parte de la clausura que el build
|
|
# consume: si el build lo leyera sería una denegación legítima que queremos ver.
|
|
find "$real" -type f -o -type l | grep -v "/\.hammer/" | while IFS= read -r f; do
|
|
inside="${f#$real}"
|
|
echo "ro $inside" >> "$TMP"
|
|
dirname "$inside" >> "$TMP.d"
|
|
done
|
|
done
|
|
|
|
echo "# harkaq-policy: clausura derivada de $# dep(s)"
|
|
sort -u "$TMP.d" | emit_dirs
|
|
sort -u "$TMP"
|