Philip Withnall philip.withnall@collabora.co.uk 2015 Acessando o sistema de arquivos Rafael Fontenelle rafaelff@gnome.org 2017 Acesso ao sistema de arquivos Resumo

Há alguns antipadrões a serem considerados ao acessar o sistema de arquivos. Esse artigo presume conhecimento das APIs GFile, GInputStream e GOutputStream padrões.

Use E/S assíncrona para acesso de arquivo. ()

Sempre use funções adequadas para construir nomes e caminhos de arquivos . ()

Valide caminhos de arquivos que estão em diretórios esperados antes de usá-los. ()

Use perfis obrigatórios de controle de acesso para reforçar restrições de acesso de arquivos. ()

E/S assíncrona

Quase toda E/S deve ser feita assincronamente, ou seja, sem bloqueio do contexto principal do GLib. Isso pode ser alcançado por sempre usar as variantes *_async() e *_finish() de cada função de E/S.

Por exemplo, g_input_stream_read_async() em vez de g_input_stream_read().

E/S síncrona bloqueia o loop principal, o que significa que outros eventos, tal como entrada de usuário, chegada de pacotes de rede, expiração de tempo limite e retorno de chamada ocioso, não são tratados até que a função bloqueadora retorne.

E/S síncrona é aceitável em certas circunstâncias nas quais a sobrecarga de agendar uma operação assíncrona excede o custo de E/S síncrona local no Linux. Por exemplo, fazer uma leitura pequena de um arquivo local, ou de um sistema de arquivos virtual tal como /proc. Para tais leituras, as funções de baixo nível g_open(), read() e g_close() devem ser usadas, em vez do GIO.

Arquivos no diretório pessoal do usuário não contam como locais, pois eles podem estar em um sistema de arquivos de rede.

Note que a alternativa – executar E/S síncrona em uma thread separada – é altamente desencorajada; veja as diretrizes de thread para mais informações.

Construção de caminho de arquivo

Nomes e caminhos de arquivos não são strings normais: em alguns sistemas, eles podem usar uma codificação de caracteres diferente de UTF-8, enquanto strings normais no GLib têm a garantia de sempre usar UTF-8. Por este motivo, funções especiais devem ser usadas para compilar e tratar nomes e caminhos de arquivos. (Sistemas Linux modernos quase que universalmente usam UTF-8 para codificação de nome de arquivo, então isso não é um problema na prática, mas as funções de caminho de arquivo ainda devem ser usadas para compatibilidade com sistemas como o Windows, que usam nomes de arquivos UTF-16.)

Por exemplo, caminhos de arquivos devem ser construídos usando g_build_filename() em vez de g_strconcat().

Fazer isso deixa mais claro qual é a intenção do código e também elimina separadores duplicados de diretórios, de forma que o caminho retornado é canonical (apesar de não necessariamente absoluto).

Como um outro exemplo, caminhos devem ser desmembrados usando g_path_get_basename() e g_path_get_dirname() em vez de g_strrstr() e outras funções manuais de pesquisa.

Validação de caminho e <em>sandboxing</em>

Se um nome ou caminho de arquivo vem com uma entrada externa, tal como uma página web ou entrada de usuário, ele deve ser validado para garantir que colocá-lo em um caminho de arquivo não produzirá um caminho arbitrário. Por exemplo, se um nome de arquivo é construído a partir de uma string constante ~/ junto com alguma entrada de usuário, se o usuário insere ./../etc/passwd, eles podem (potencialmente) ganhar acesso a informação sensível de contas, dependendo de com qual usuário o programa está sendo executado e o que ele faz com os dados carregados a partir do caminho construído.

Isso pode ser evitado por meio de uma validação dos caminhos construídos antes de usá-los usando g_file_resolve_relative_path() para converter quaisquer caminhos relativos para absolutos e, então, validar se aqueles caminhos estão dentro de um diretório raiz de sandbox apropriado para a operação. Por exemplo, se um código baixa um arquivo, ele poderia validar se aqueles caminhos estejam dentro de ~/Downloads, usando g_file_has_parent().

Como uma segunda linha de defesa, todos os projetos que acessam o sistema de arquivos devem considerar fornecer um perfil obrigatório de controle de acesso, usando um sistema tal como AppArmor ou SELinux que limita os diretórios e arquivos nos quais eles podem ler de ou escrever em.