Files
takana/scripts/harkaq
sergioandClaude Opus 4.8 6419f2a952 harkaq: Q1b CERRADA — la evidencia cruza el userns y el canario es la clave primaria
Banco: scripts/harkaq/q1b-attrib.c. Dos builds CONCURRENTES en bwrap
--unshare-all (los ns de Sandbox::bwrap_args), sin privilegio (uid 1000),
canarios con nonce distinto, lector en el host como root.

(a)  Los registros CRUZAN el userns/pidns/mountns (6 registros llegaron al
    lector del host) y cruzan con builds SIN privilegio, que es como corren de
    verdad. ⇒ harkaq-audit vive en el host junto a hammerd; la arquitectura
    del §4 se sostiene.
(b)  El canario con nonce ATRIBUYE: AAAA=1 BBBB=1, cero cruces con 2 builds
    en paralelo. ⇒ la granja puede construir en paralelo sin contaminarse la
    evidencia entre builds.

Tres hallazgos colaterales que valen más que el veredicto:
  - El contador quedó VALIDADO: dos `deallocated denials=1`, uno por dominio,
    cuadrando con 1 ACCESS cada uno ⇒ el chequeo anti-pérdida (nº ACCESS ==
    denials) está medido, no supuesto.
  - La identidad sobrevive a los ns: pid=8498 uid=1000 son del HOST (adentro
    del pidns la víctima es pid 1).
  - dev+ino identifican el OBJETO, no el BUILD: los 2 canarios dan el mismo
    ino=4457713 (ambos bindean /etc/hostname). Atribuir por dev/ino habría
    fundido dos builds leyendo el mismo fichero no declarado — el caso más
    común que harkaq va a ver. La clave es domain=, y el canario la revela.

⇒ D9 hace TRES trabajos con un mecanismo: honestidad (§3.4), clave primaria
(§3.5) y, vía el contador, detección de pérdida.

Nota de método: esta corrida también falló 2 veces más, y las 2 el banco
afirmó algo falso con total confianza. (1) `cat $canario >/dev/null` — /dev no
estaba en la clausura ⇒ sh fallaba en el REDIRECT y cat no corría; el rc=1 no
era del canario. (2) Como root, bwrap no pudo ni ejecutar el binario y el
veredicto imprimió "NADA cruzó ⇒ replantear la arquitectura" a partir de cero
estímulo (causa: --unshare-all mapea sólo uid 0→0; CAP_DAC_OVERRIDE en userns
sólo vale sobre uids MAPEADOS ⇒ root-en-userns no atraviesa un home
drwx------). Fix: drop_privs() + gate de estímulo (exit 4 si una víctima no
sale con status 0).

Van 3 veces en una sesión que un cero fue el instrumento y no el kernel, con
quien escribía el banco mirando de frente ese riesgo. harkaq sin canario no es
un riesgo de configuración: es el comportamiento por defecto.

Quedan Q1c (privilegio de harkaq-audit: mejor un helper acotado que hammerd
entero) y Q1d (qué ruta reporta exe= con --bind /src).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 14:42:12 -04:00
..

harkaq — banco de pruebas

Ver docs/16-harkaq-jaula.md. Acá viven los experimentos que sostienen las afirmaciones del SDD: si el doc dice "medido", el que lo midió está en este directorio.

q1-audit.c — el gate del proyecto (Q1, cerrado 2026-07-15)

Responde: ¿llegan los registros AUDIT_LANDLOCK_* a un lector? Todo harkaq cuelga de eso — su producto es la evidencia, no la jaula.

gcc -O1 -Wall -o q1-audit q1-audit.c
for s in same-exec new-exec new-exec-logon; do sudo ./q1-audit $s; done

Necesita root (CAP_AUDIT_READ para leer el multicast, CAP_AUDIT_CONTROL para encender el audit). Enciende audit_enabled=1 globalmente y no lo restaura — reversible, no persiste al reboot (no toca el cmdline), pero deja dmesg más ruidoso mientras tanto.

Resultados en el laptop (ABI 10, kernel 7.2.0-rc3)

Escenario Registros ACCESS Qué prueba
same-exec 2 el kernel loguea por defecto sin execve
new-exec 0 flags por defecto ⇒ ciego tras execve — el caso real de harkaq
new-exec-logon 4 LOG_NEW_EXEC_ON lo arregla

Los registros traen blockers=fs.read_file path="/etc/passwd" dev="nvme1n1p6" ino=4458369 y el exe= que lo intentó. Análisis completo en docs/16-harkaq-jaula.md §3.4.

Por qué aborta con código 4

Si no puede confirmar audit_enabled=1, aborta en vez de reportar 0 registros. No es paranoia: la primera corrida dio 0 en los tres escenarios y parecía confirmar la hipótesis. Era un bug del instrumento (AUDIT_GET con NLM_F_ACK → el ACK llegaba antes que la respuesta → nunca se encendía el audit). Se detectó sólo porque el control (same-exec) también dio 0, y eso era imposible.

Es el modo de falla de harkaq sobre su propio banco de pruebas: un sistema cuyo producto es la ausencia de algo no falla ruidosamente — dice que todo está bien. De ahí sale D9 (el canario deliberado), y de ahí sale la regla de este directorio: todo experimento lleva un control que debe dar positivo. Un experimento sin control no mide, tranquiliza.

q1b-attrib.c — userns y atribución (Q1b, cerrado 2026-07-15)

Responde: ¿el lector del host ve las denegaciones de adentro de bwrap, y se puede atribuir cada registro a SU build con la granja en paralelo?

gcc -O1 -Wall -o ~/.cache/harkaq/q1b q1b-attrib.c   # NO compilar bajo /tmp: --tmpfs /tmp lo tapa
sudo ~/.cache/harkaq/q1b

Lanza 2 víctimas concurrentes en bwrap --unshare-all (los ns de Sandbox::bwrap_args), cada una con un canario de nonce distinto, y escucha desde el host. Las víctimas bajan a $SUDO_UID: el despliegue real es lector privilegiado + builds sin privilegio.

Resultado: los registros cruzan el userns/pidns/mountns, y el canario con nonce atribuye sin ambigüedad (AAAA=1 BBBB=1, cero cruces). Análisis en docs/16-harkaq-jaula.md §3.5.

Los tres rastrillos de este banco, para el próximo que lo toque

  1. No compilar bajo /tmp: el sandbox hace --tmpfs /tmp y tapa el binario.
  2. El canario necesita un punto de montaje escribible. Con --ro-bind / /, bwrap no puede crear /harkaq-canary-X en la raíz de sólo lectura (el sandbox real usa --tmp-overlay / y no tendría el problema). Va bajo /tmp, y por eso /tmp no entra en la clausura de la víctima.
  3. Root + --unshare-all no atraviesa un home drwx------. bwrap mapea sólo uid 0→0; los ficheros de uid 1000 quedan sin mapear y CAP_DAC_OVERRIDE en un userns sólo vale sobre uids mapeados. De ahí drop_privs().

Por qué también aborta con código 4

Mismo gate que q1-audit, más uno: si alguna víctima no sale con status 0, aborta en vez de contar registros. La corrida que lo motivó imprimió "NADA cruzó ⇒ harkaq-audit no puede vivir en el host: replantear" cuando bwrap ni siquiera había podido ejecutar el binario. Una conclusión arquitectónica falsa, a partir de cero estímulo.

Van tres veces en una sola sesión (NLM_F_ACK, el redirect a /dev/null, el exec) que un cero resultó ser el instrumento y no el kernel. Un veredicto que no verifica su propio estímulo es el falso Hermetico de D9, pero del lado del banco.