Theo de Raadt propôs incluir um novo mecanismo no OpenBSD para reduzir a superfície de ataque, implementado por meio da extensão das funcionalidades da chamada de sistema openat. Os patches com a implementação de flags adicionais para openat e open, que limitam a possibilidade de atravessar para diretórios acima através de "../" e de acessar caminhos absolutos, foram preparados para o núcleo, libc, e também para alguns aplicativos do sistema base. As mudanças ainda não foram incluídas na versão OpenBSD-current e estão em discussão entre os desenvolvedores.
A família de chamadas de sistema openat(2) funciona como um equivalente a open(2), exceto que, se o parâmetro "path" contiver um caminho relativo, o arquivo aberto é determinado em relação ao diretório associado ao descritor de arquivo "fd", e não em relação ao diretório de trabalho atual. Se um caminho absoluto for passado para openat, como: int dirfd = open("/tmp", O_RDONLY | O_DIRECTORY); int hfd = openat(dirfd, "/etc/hosts", O_RDONLY);
a função openat() ignorará "dirfd" e, como resultado, o caminho absoluto será tratado normalmente.
Portanto, a substituição de open() por openat() não aumenta a segurança do programa por si só. Essa chamada pode acelerar a análise do caminho, mas não limita o acesso ao sistema de arquivos. As flags que proíbem caminhos absolutos (como RESOLVE_BENEATH e/ou RESOLVE_IN_ROOT para openat2 no Linux) também não garantem proteção: o programador deve adicioná-las a todas as chamadas apropriadas, e, ao assumir o controle do processo, um invasor pode explorar outros caminhos para abrir arquivos.
Durante o desenvolvimento da ferramenta openrsync, Theo se deparou com a necessidade de restringir suas capacidades de navegação no sistema de arquivos, mas não foi possível fazer isso usando as funções unveil() e pledge(). Então, surgiu a ideia de um mecanismo semelhante ao openat(), mas com propriedades de segurança que complementam pledge/unveil ou até mesmo funcionam na ausência delas.
A ideia principal é fazer com que as limitações façam parte do próprio descritor do diretório. Para isso, é proposto o sinalizador F_BELOW, que pode ser configurado por meio de fcntl(), ou o sinalizador O_BELOW para open(). Um descritor «dirfd» limitado dessa forma permitirá apenas transições para baixo na árvore de diretórios: chamadas openat() com um caminho absoluto ou que subam pela árvore usando «..» resultarão em erro ENOENT. Em caso de ataque que leve à execução de código, a tabela de descritores de arquivos do processo conterá «dirfd» menos funcionais, o que limitará a superfície de ataque.
Fonte: opennet.ru
