Theo de Raadt propuso incluir en OpenBSD un nuevo mecanismo para reducir la superficie de ataque, implementado a través de una extensión de las capacidades de la llamada al sistema openat. Los parches que implementan banderas adicionales para openat y open, que limitan la posibilidad de acceder a directorios superiores a través de «/..» y de referirse a rutas absolutas, están preparados para el núcleo, libc, y algunas aplicaciones del sistema base. Los cambios aún no se han incluido en OpenBSD-current y están en discusión entre los desarrolladores.
La familia de llamadas al sistema openat(2) funciona como un análogo de open(2) excepto porque si el parámetro «path» especifica una ruta relativa, el archivo que se abre se determina en relación con el directorio asociado al descriptor de archivo «fd», en lugar de estar relacionado con el directorio de trabajo actual. Si se transmite una ruta absoluta a openat, como: int dirfd = open(«/tmp», O_RDONLY | O_DIRECTORY); int hfd = openat(dirfd, «/etc/hosts», O_RDONLY);
La función openat() ignorará «dirfd» y, como consecuencia, la ruta absoluta será procesada de la manera habitual.
Por lo tanto, reemplazar open() por openat() por sí mismo no mejora la seguridad del programa. Tal llamada puede acelerar el análisis de la ruta, pero no limita el acceso al sistema de archivos. Tampoco garantizan protección las banderas que prohíben rutas absolutas (por ejemplo, RESOLVE_BENEATH y/o RESOLVE_IN_ROOT para openat2 en Linux): el programador debe agregarlas a todas las llamadas apropiadas, y si un atacante toma el control del proceso, puede aprovechar otras rutas para abrir archivos.
Durante el trabajo en la utilidad openrsync, Theo encontró la necesidad de restringir sus capacidades para navegar por el sistema de archivos, pero esto no era posible utilizando las funciones unveil() y pledge(). Así que surgió la idea de un mecanismo similar a openat(), pero con propiedades de seguridad que complementan pledge/unveil o incluso funcionan en ausencia de ellas.
La idea principal es hacer que las restricciones sean parte del mismo descriptor del directorio. Para ello, se propone la bandera F_BELOW, que se puede establecer a través de fcntl(), o la bandera O_BELOW para open(). Un descriptor "dirfd" limitado de esta manera solo permitirá transiciones hacia abajo en el árbol de directorios: las llamadas openat() con una ruta absoluta o con una transición hacia arriba a través de ".." resultarán en un error ENOENT. En caso de un ataque que conduzca a la ejecución de código, la tabla de descriptores de archivos del proceso contendrá "dirfd" menos funcionales, lo que limitará la superficie del ataque.
Fuente: opennet.ru
