¿Qué son las funciones anidadas en C y por qué importan para la seguridad?
Las funciones anidadas son una extensión histórica de GNU C que permite definir una función dentro de otra y capturar las variables locales del ámbito padre. El soporte clásico de GCC para esta característica se apoya en trampolines: pequeños fragmentos de código máquina que el compilador coloca en la pila en tiempo de ejecución para conectar la función hija con el marco (stack frame) del padre.
El problema de seguridad es conocido: para que esos trampolines sean ejecutables, el kernel debe marcar la pila como ejecutable. Eso abre la puerta a técnicas de explotación si un atacante consigue desviar el flujo de control hacia la pila. La nota publicada el 29 de agosto por Martin Uecker en su blog técnico propone una vía para conservar la potencia expresiva de las funciones anidadas sin necesidad de mantener la pila ejecutable en el binario final.
¿Cómo resuelve Martin Uecker el dilema en GCC sin trampolines activos?
El artículo explica el mecanismo paso a paso. En x86_64, GCC genera una secuencia corta en el trampolín que carga dos punteros en registros antes de saltar a la función anidada: la dirección de código de la función y la dirección del marco estático que contiene las variables capturadas. El truco consiste en leer esos dos punteros directamente de la memoria del trampolín y luego invocar la función con __builtin_call_with_static_chain, sin saltar jamás a la zona ejecutable del trampolín.
👥 ¿Quieres ir más allá de la noticia?
En nuestra comunidad discutimos las tendencias, compartimos oportunidades y nos ayudamos entre emprendedores. Sin humo, solo acción.
👥 Unirme a la comunidadEn la práctica esto se traduce en pasos como:
- Extraer, con utilidades como
peekyarray_slicede la librería experimental noplate, los 8 bytes que contienen la dirección de código y los 8 bytes del puntero al static chain. - Llamar a la función con
__builtin_call_with_static_chain(((typeof(bar)*)code)(arg), chain), reutilizando el camino que GCC 17 habilitará de forma nativa mediante__builtin_call_static_chainy__builtin_call_code_address. - Tras la compilación, aplicar
patchelf --clear-execstack programapara borrar el flag ejecutable del header GNU_STACK del ELF.
Como señala Uecker, la pila sigue marcada como ejecutable en el binario, pero como nunca se ejecuta realmente código en ella, basta con limpiarla con patchelf para cerrar el vector de ataque. El autor lo describe como un mecanismo de fallback para versiones de GCC anteriores a la 17, donde las nuevas builtins aún no están disponibles.
La alternativa de interpretar el trampolín en el call site
Hay una segunda idea en la nota que merece atención por su elegancia. En lugar de extraer los punteros cuando se crea el trampolín, se puede pasar el puntero al trampolín tal cual y, en cada punto de llamada, comprobar si apunta a un trampolín; si es así, decodificar la secuencia inlineada de instrucciones para obtener el código y el static chain y ejecutar la llamada con __builtin_call_with_static_chain.
Uecker lo define como un intérprete diminuto inlinable: tan simple que cabe en el propio call site y solo entiende una secuencia concreta de instrucciones x86_64. Las ventajas son claras:
- No se rompe la ABI habitual de pasar punteros de función.
- El código que invoca la función anidada queda totalmente devirtualizado respecto al camino inseguro original.
- Permite, en el futuro, soportar nuevas arquitecturas añadiendo el mini-intérprete correspondiente.
El autor implementa esta idea en noplate, su librería experimental publicada en Codeberg, donde un wide pointer se construye a partir del par (code, static chain).
¿Qué cambia con GCC 17 y por qué importa a los que mantienen código C antiguo?
GCC 16.1 se released el 30 de abril de 2026 según la documentación oficial del proyecto GNU, y la versión 17 está en camino. Cuando esté disponible, los builtins __builtin_call_static_chain y __builtin_call_code_address harán innecesario el hack descrito en el post: se podrá invocar directamente la función anidada con el puntero de código y el static chain sin necesidad de generar trampolines.
Para equipos que mantienen bases de código con muchos años de vida, esto abre dos preguntas prácticas:
- ¿Vale la pena migrar a GCC 17 para eliminar las llamadas indirectas a trampolines inseguros?
- ¿Es aceptable seguir usando GCC 14 o 15 si se aplica
patchelf --clear-execstackcomo mitigación?
La respuesta depende del perfil de riesgo del producto. En binarios que se distribuyen a terceros (herramientas CLI, agentes, runtimes), dejar la pila ejecutable es una superficie de ataque evitable. En entornos cerrados y firmware embebido donde el flujo de control está muy controlado, el autor recuerda que no es tan terrible como a veces se presenta, una posición alineada con el debate recurrente en la lista de correo de GCC.
¿Qué significa esto para tu startup?
Si tu stack incluye código C con funciones anidadas o lo mantiene como dependencia, hay tres acciones concretas que puedes tomar esta semana:
- Audita tus binarios con
patchelf --print-execstack. Si reporta la pila como ejecutable, ya tienes una pista de dónde se está generando un trampolín. Es un comando no destructivo y tarda milisegundos. - Aplica
--clear-execstacken tu pipeline de release para los artefactos que se distribuyen a clientes o corren en entornos multi-tenant. Es una línea en el CI/CD que elimina un vector de ataque completo. - Evalúa moverte a GCC 17 cuando esté disponible si dependes fuertemente de las funciones anidadas. Las nuevas builtins prometen el mismo modelo de uso sin necesidad de mitigaciones posteriores en el binario.
El artículo también es un buen recordatorio de que la seguridad a nivel binario suele resolverse en el último 10% del pipeline, no en el código fuente. Tener un paso de hardening con patchelf (o alternativas como hardening-check de Debian) es una inversión barata con retorno alto para productos que tocan código nativo.
Fuentes
- Indirect Calling of Nested Functions on GCC Without Executable Stack (fuente original)
- Downloading GCC – GNU Project
- GNU Compiler Collection – Wikipedia
- patchelf(1) – Arch manual pages
- patchelf – MyNixOS
👥 ¿Quieres ir más allá de la noticia?
En nuestra comunidad discutimos las tendencias, compartimos oportunidades y nos ayudamos entre emprendedores. Sin humo, solo acción.
👥 Unirme a la comunidad













