static-audit: miraba UN binario y capaba a 40 — dos pases en falso probados

Arreglando las tres hojas salio que el guardian tenia dos agujeros, y los dos
devuelven un pase en falso, que es la peor direccion posible para un gate.

1. `break` en el PRIMER ELF ejecutable. e2fsprogs: el primero que encontraba era
   `bin/lsattr` (estatico) ⇒ receta HONESTA, mientras `e2fsck` y los tres
   `fsck.ext*` eran dinamicos. 4 de 31, invisibles.

2. `find | head -40`. bash trae 42 ejecutables y CUARENTA son los modulos
   cargables `usr/lib/bash/*`, que son ELF *shared object* y no matchean
   `ELF.*executable`. El cap cortaba la lista ANTES de llegar a `bin/bash` ⇒ el
   audit concluia «sin ELF» y eso en el resumen se lee como que no hay nada que
   objetar. El shell del perfil base, dinamico, sin que nadie lo viera.

Con dwarves el `break` habia acertado de casualidad —el primero tambien era
dinamico— y por eso reportaba 1 donde habia 10.

Ahora recorre TODOS los ejecutables, sin cap, cuenta cuantos mienten sobre
cuantos hay, y nombra un ejemplo: «gtk4 dice static, 8 de 8 ejecutables
DINAMICOS (p.ej. usr/bin/gtk4-rendernode-tool)».

Barrido completo con el metodo estricto: 684 estaticos de verdad, MIENTEN 3
(gtk4, bash, e2fsprogs), 59 sin artefacto. Con el metodo viejo, sobre el mismo
store, salia 685/1/60. La diferencia son los dos que se escapaban.

Es «no comprobar no es aprobar» aplicado al propio guardian — el mismo fallo que
`hammer kernel contract` ya habia tenido que corregir en SDD 25 §4.ter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACUcwo9mZsE5ocYVE9npih
This commit is contained in:
Sergio
2026-08-31 15:04:26 +00:00
co-authored by Claude Opus 5
parent 4d70466bea
commit 5155f90ab9
+26 -10
View File
@@ -72,18 +72,34 @@ for f in $recetas; do
[ -z "${art:-}" ] && { sin=$((sin + 1)); continue; }
fi
# El primer ELF *ejecutable* del artefacto. Una `.so` tiene NEEDED por definición y no prueba
# nada; sólo el ejecutable dice si el enlace final fue estático.
bin=""
for b in $(find "$art" -type f -perm -u+x 2>/dev/null | head -40); do
if file -b "$b" 2>/dev/null | grep -q 'ELF.*executable'; then bin="$b"; break; fi
done
[ -z "$bin" ] && { sin=$((sin + 1)); continue; }
needed=$(readelf -d "$bin" 2>/dev/null | grep -oE 'Shared library: \[[^]]+\]' \
# TODOS los ELF *ejecutables* del artefacto, no el primero. Una `.so` tiene NEEDED por
# definición y no prueba nada; sólo los ejecutables dicen si el enlace final fue estático.
#
# ⚠ Antes esto miraba UNO y cortaba (`break`). Con dwarves se vio lo que eso deja pasar: sus
# DIEZ ejecutables eran dinámicos y el audit reportaba uno — acertó de casualidad, porque el
# primero también lo era. El caso que se escapaba en silencio es el inverso: primer binario
# estático y el resto no, que se leía como receta honesta. Es «no comprobar no es aprobar»
# aplicado al propio guardián (2026-08-31).
vistos=0; needed=""; primer_malo=""; malos=0
for b in $(find "$art" -type f -perm -u+x 2>/dev/null); do
file -b "$b" 2>/dev/null | grep -q 'ELF.*executable' || continue
vistos=$((vistos + 1))
nb=$(readelf -d "$b" 2>/dev/null | grep -oE 'Shared library: \[[^]]+\]' \
| sed 's/.*\[//;s/\]//' | tr '\n' ' ') || true
if [ -n "$nb" ]; then
malos=$((malos + 1))
[ -z "$primer_malo" ] && { primer_malo="${b#$art/}"; needed="$nb"; }
fi
done
[ "$vistos" -eq 0 ] && { sin=$((sin + 1)); continue; }
if [ -n "$needed" ]; then
printf ' ✗ %-18s dice static, es DINÁMICO → %s\n' "$n" "$needed"
if [ "$malos" -gt 1 ]; then
printf ' ✗ %-18s dice static, %d de %d ejecutables DINÁMICOS (p.ej. %s) → %s\n' \
"$n" "$malos" "$vistos" "$primer_malo" "$needed"
else
printf ' ✗ %-18s dice static, es DINÁMICO (%s) → %s\n' "$n" "$primer_malo" "$needed"
fi
case "$needed" in *libgcc_s*) printf ' %-18s ↑ arrastra libgcc_s de Alpine: deuda de matar-gcc no declarada\n' "" ;; esac
case "$needed" in *libc.so*) printf ' %-18s ↑ `libc.so` es la musl de zig: en el host son 255B de linker script ⇒ NO CORRE fuera del sandbox\n' "" ;; esac
mienten=$((mienten + 1))