Tiempo de entrar en profundidad técnica sobre mi proyecto. En la entrega anterior expliqué mi recorrido de forma accesible para principiantes mostrando cómo es un camino realista desde la preparación e ideación hasta la aceptación y finalización. Este será mi último artículo dedicado a mi experiencia en GSoC 25 con The FreeBSD Project. A continuación detallo las decisiones de diseño, los retos de implementación y las soluciones que desarrollé al mejorar mac_do(4) en el kernel y la utilidad de usuario mdo(1). Si te interesan sistemas operativos, kernels, concurrencia o gestión de memoria este artículo te resultará interesante; si lo tuyo es la práctica profesional como empresa que ofrece desarrollo de software a medida y soluciones de inteligencia artificial, encontrarás referencias útiles al final.
Resumen del proyecto. Trabajé en dos subproyectos principales: mejoras en mac_do(4) y mejoras en mdo(1). mac_do(4) es un módulo de seguridad del kernel que autoriza transiciones controladas de credenciales de procesos para, por ejemplo, cambiar uid o gid a valores permitidos sin necesidad de setuid suid binarios. El objetivo fue modernizar la flexibilidad y cobertura de autorizaciones y permitir configuración por jail, además de autorizar llamadas POSIX tradicionales como setuid, setgid y setgroups, no solo el sistema setcred(2).
Objetivo 1 en mac_do(4): lista de ejecutables configurable por jail. El módulo original solo permitía procesos que procedieran de /usr/bin/mdo, lo que impedía su uso desde otros binarios. La solución fue introducir una estructura unificada de configuración que encapsula tanto las reglas de transición como la lista de rutas ejecutables autorizadas y que mantiene los mecanismos de contaje de referencias para actualizaciones atómicas. Crear struct conf permitió manejar la vida completa de la configuración y soportar herencia de jails con copias independientes en lugar de referencias compartidas.
Gestión de memoria y vida de objetos. Migrar la lógica de vida desde la entidad rules hacia conf supuso reimplementar funciones de asignación, retención y liberación asegurando que la limpieza también gestionara correctamente las estructuras embebidas. La clave fue que conf posee la semántica de ciclo de vida de rules y por tanto su liberación debe invocar la limpieza de las reglas internas antes de liberar el contenedor.
Copia profunda frente a copia superficial. Para soportar herencia de jails y actualizaciones sin compartir memoria, fue necesario implementar clonación profunda de las reglas y sus arrays dinámicos de uids y gids. No es seguro usar bcopy para estructuras con punteros a arrays dinámicos, por lo que cada regla se clona alocando memoria nueva para sus arrays y copiando los valores, garantizando independencia entre jails.
Concurrencia y bloqueo de prison. El kernel exige cuidado con bloqueos. La infraestructura existente usa el prison lock para proteger datos por jail. Implementé una función find_conf que sube por la cadena de jails hasta encontrar la configuración efectiva, reteniendo el prison que la contiene y devolviéndolo al llamador para desbloquearlo una vez finalizado el uso. Este patrón asegura que la config no cambie durante su uso y evita condiciones de carrera y deadlocks.
Integración con parámetros de jail y sysctl. Añadir las rutas ejecutables supuso extender los manejadores sysctl y los hooks de administración de jails para exponer y permitir la modificación de la lista por jail. El handler lee la configuración bajo el prison lock y realiza la lógica de actualización con copia y reemplazo atómico, preservando coherencia en entornos multiprocesador.
Transformando check_proc de estático a dinámico. El chequeo que antes comparaba contra la ruta fija se sustituyó por un algoritmo que obtiene la ruta completa del binario del proceso y la compara contra las rutas autorizadas en conf. Si hay coincidencia la autorización continúa, de lo contrario se niega el permiso. Esto habilita personalización por jail y una política más flexible sin perder el modelo de seguridad.
OSD y configuración por defecto. La integración con OSD del subsistema de jails implicó actualizar los hooks de ciclo de vida para crear y propagar conf por defecto compatible con la configuración histórica, de forma que un sistema antiguo siga funcionando con /usr/bin/mdo como valor por omisión pero permita sobreescrituras por jail.
Objetivo 2 en mac_do(4): soportar syscalls POSIX de cambio de credenciales. El segundo bloque de trabajo fue interceptar y autorizar las llamadas tradicionales setuid, seteuid, setreuid, setresuid, setgid, setegid, setregid, setresgid y setgroups. Para ello extendí la infraestructura existente basada en datos por hilo con cabeceras comunes y estructuras específicas para cada familia de syscalls que contienen los parámetros objetivo necesarios para la decisión de autorización.
Estructuras y patrón de triplete de hooks. Siguiendo la arquitectura MAC se implementan tres hooks por syscall: enter, check y exit. En enter se crea y adjunta la estructura por hilo cuando el ejecutable está autorizado; en check se rellenan los parámetros objetivo para la validación; en exit se limpian y liberan los datos por hilo. Este patrón asegura aislamiento por hilo y limpieza en todos los caminos, incluidas las excepciones.
Lógica de concesión de privilegios. Extendí la función de concesión de privilegios para manejar nuevos identificadores como PRIV_CRED_SETUID y PRIV_CRED_SETGROUPS. La rutina itera sobre las reglas y aplica la comparación sobre el destino solicitado, reutilizando la misma sintaxis de reglas que ya se usa para setcred. Para setgroups se implementó rule_grant_setgroups que valida cada gid en la lista propuesta contra la política definida.
Manejo de parámetros complejos. Algunas llamadas admiten valores especiales como -1 para indicar sin cambio. Implementé lógica para derivar el target efectivo por syscall, priorizando euid cuando corresponde y aplicando reglas coherentes con la semántica POSIX. Esto fue especialmente importante para setreuid y setresuid.
Extensiones en el framework MAC. Para exponer los nuevos puntos de entrada añadí nuevos mpo_ hooks en la interfaz de políticas y actualicé las invocaciones en el flujo de cambio de credenciales del kernel. Finalmente registré todas las tripletas en la estructura de operaciones de la política mac_do y validé que el comportamiento fuera coherente en caminos sincrónicos y asíncronos.
Resultado para mac_do: cobertura amplia. Tras los cambios mac_do puede autorizar transiciones solicitadas por cualquier syscall POSIX relevante, no solo por setcred(2). Esto permite desplegar aplicaciones sin bits setuid y controlar las elevaciones de privilegio mediante reglas expresivas tipo uid=1000>uid=0 aplicables a setuid, seteuid o setcred indistintamente. Garantías como aislamiento por hilo, limpieza en excepciones y aplicación uniforme de reglas se mantienen gracias a la arquitectura elegida.
Mejoras en mdo(1). La utilidad de usuario mdo que invoca setcred(2) se amplió para ofrecer control fino de credenciales: establecer uid, rguid, eguid, gid primario y lista de grupos suplementarios con varias modalidades. Además añadí una opción para imprimir la porción target de la regla generada por mac_do, útil para diagnóstico y para componer reglas que luego se apliquen en jails.
Control de grupos en la utilidad. Implementé tres modos de especificar grupos: listas exactas con -G, modificaciones incrementales con -s usando tokens @ + y - para reset, añadir y eliminar respectivamente, y comportamiento por defecto que hereda del passwd o del proceso actual. Gestionar arrays dinámicos de gids, eliminar duplicados y aplicar operaciones set like requieren utilidades de realloc y ordenación segura para producir la lista final que se pasará a setcred.
Salida de regla. La opción print rule imprime la representación de destino que mac_do entiende, por ejemplo uid, gid y la lista de suplementarios en el formato usado por las reglas, facilitando su incorporación posterior en políticas por jail.
Conclusión y aprendizajes. El trabajo fue intenso y lleno de retos: fallos del kernel, reinicios de VM, depuración compleja y aprendizaje continuo. Resumir la experiencia técnica solo captura una parte del esfuerzo real. El proyecto ahora ofrece políticas por jail, mayor cobertura de syscalls y una utilidad de usuario mucho más capaz.
Sobre Q2BSTUDIO. En Q2BSTUDIO somos una empresa de desarrollo de software que ofrece soluciones a medida y aplicaciones a medida orientadas a resolver retos reales de negocio. Combinamos experiencia en software a medida con servicios de inteligencia artificial y ciberseguridad para entregar productos robustos y escalables. Si tu proyecto requiere integración con la nube, también disponemos de servicios cloud aws y azure para desplegar soluciones seguras y eficientes. Para iniciativas de datos contamos con servicios inteligencia de negocio y Power BI que ayudan en la toma de decisiones basadas en datos. Si buscas transformar procesos repetitivos en flujos automáticos confiables consultanos sobre nuestras soluciones de automatización y agentes IA. Conecta con nuestras capacidades de desarrollo de aplicaciones y software a medida y explora cómo integrar modelos y servicios con servicios de inteligencia artificial para empresas.
TLDR. Convertí mac_do(4) en configurable por jail, añadí soporte para autorizar syscalls POSIX de cambio de credenciales, y amplié mdo(1) para control fino de uid y gid. Fue el cierre de mi viaje en GSoC y una gran lección práctica en kernel programming, concurrencia y diseño de políticas de seguridad.