ExplicacionSeguridad

Seguridad del data plane

Los invariantes que impiden que un bug del daemon Zig escale, la capa zkit.safety que los impone y las guardas de construcción que impiden saltársela.

Qué obliga, no qué está verificado. Esta página fija el contrato de diseño de dec-0117. Qué invariantes tienen su prueba verde en el árbol actual lo dice el gate de track/byte-runtime/sec, y un invariante del diseño que el código todavía no cumple sigue siendo la obligación.

Los invariantes

Cada uno lleva su test de rotura: un test que falla si alguien lo incumple.

InvarianteObliga a
I1Ninguna operación del daemon sin capacidad verificada (SCT). El identificador de sesión no es un secreto.
I2El daemon sólo acepta sesiones creadas por playback-svc por el socket de control, y una SCT sólo vale si su sesión existe con el mismo actor y recurso.
I3Escribir (publicar en MoQT, ingestar) exige alcance de escritura y un recurso concreto; el publicador de laboratorio no va en el binario de producción.
I4Presupuestos jerárquicos (daemon, actor, sesión, conexión) de memoria, flujos, suscripciones, bytes en vuelo y sesiones. Agotarlo falla la sesión, no el daemon.
I5Los parsers de entrada no confiable son seguros por construcción: ReleaseSafe, lectores acotados, aritmética comprobada, sin unreachable alcanzable y con fuzz.
I6libav es aislable: el contrato con el motor libav es de mensajes y descriptores, para poder correrlo en un proceso trabajador sin red, con seccomp y límites.
I7Raíces de fichero fd-relativas: por el socket sólo viaja {rootId, relPath}, la apertura no sigue symlinks ni sale de la raíz y se verifica (dev, ino).
I8Contenedores con el mínimo privilegio: no root, rootfs de sólo lectura, sin capabilities, raíces de medios ro, salida de red denegada por defecto.
I9Las referencias que sobreviven a un salto asíncrono son handles con generación, no punteros.
I10Un fallo de memoria es un pánico acotado, no una primitiva de explotación; el daemon corre supervisado.
I11Sólo los niveles builtin, official y trusted-native ejecutan código en el proceso del daemon.
I12Observabilidad sin fugas: las SCT y las rutas no se registran, y cada rechazo relevante genera un evento de auditoría.

Capa 1: la biblioteca impone

zkit.safety ofrece las primitivas con las que se escriben los invariantes (ver zkit, spire y conduit): handles tipados con generación, un asignador con presupuesto anidable, raíces fd-relativas con apertura que no sigue enlaces, lectores acotados y aritmética comprobada.

Capa 2: Styx impide saltársela

Un paso de construcción, zig build audit:safety, recorre el AST de todo el código de producción de native/zig (no es un grep) y se pone en rojo si encuentra:

ReglaProhíbe
S1Funciones de la librería estándar que abren o resuelven rutas en bruto, en lugar de pasar por la raíz fd-relativa
S2Primitivas de sincronización en bruto: se usa zkit.safety.Mutex y zkit.sync
S3Errores tragados: un catch que no hace nada con el error
S4Abortar sobre entrada en módulos parser: unreachable, @panic, assert
S5Conversiones de puntero o entero sin un comentario SAFETY: que las justifique
S6El ejecutable del daemon compilado en ReleaseFast o ReleaseSmall
S7El asignador global de la librería estándar dentro de sesiones, MoQT o transportes
S8Apagar los chequeos de seguridad por bloque sin justificación (y nunca en módulos parser)
Z1Reimplementar un símbolo de zkit (check:zkit-no-reimpl)

Las reglas resuelven cada nombre por ámbito léxico hasta su declaración, así que un alias no esconde una primitiva. El guard tiene un trinquete: guarda contadores por regla y por fichero en safety_baseline.zon, que pueden bajar pero nunca subir, y un fichero nuevo parte de cero. Cada regla se demuestra con un mutante que pone el paso en rojo. Su especificación está cerrada: una regla nueva o un alcance mayor va a un ticket de seguimiento, con su test y su enmienda de dec-0117 §6. Entra en zig build test y en CI.

Subir ficheros añade superficie

Una dirección de escritura nueva se trata con el mismo rigor: capacidad de alcance ingest obligatoria en cada petición, cuotas por fichero y por actor (con tope total por raíz), preparación y renombrado relativos a la raíz de ingesta (I3, I7), conexiones acotadas por identidad antes y después de autenticar, y borde de red declarado, no deducido (dec-0121).

Qué no decide

dec-0117 deja explícitamente fuera:

  • el diseño del SDK de mensajería (lo decide dec-0119/dec-0120) y el de la ingesta (dec-0121), de los que sólo fija los requisitos de seguridad;
  • la identidad de usuarios, las sesiones web, CORS y CSP (dec-0118);
  • el cifrado de la biblioteca en reposo, porque no hay una amenaza concreta con consumidor hoy.

También declara los límites de su propia guarda (por ejemplo, un contenedor que guarda un alias en bruto y viaja como valor en tiempo de compilación), que cubren los tests de la capa 1 y el perfil seccomp del contenedor. Lo que es reversible sin ADR: nombres de módulos, duraciones de las SCT, cifras de los presupuestos y la lista exacta de llamadas del perfil seccomp.