Eu uso uma distribuição baseada no Linux 4.x e recentemente notei que a open()
chamada de sistema do kernel suporta um O_PATH
sinalizador aberto.
Embora a man
página contenha uma lista de chamadas de sistema com as quais teoricamente poderia ser usada, não entendo bem qual é a ideia. Eu open(O_PATH)
apenas diretórios, em vez de arquivos? E se sim, por que quero usar um descritor de arquivo em vez do caminho do diretório? Além disso, a maioria das chamadas de sistema listadas não parece ser específica para diretórios; então, também abro arquivos regulares O_PATH
para obter seu diretório como um descritor de arquivos? Ou para obter um descritor de arquivo para eles, mas com funcionalidade limitada?
Alguém pode dar uma explicação convincente sobre o que O_PATH
é, como e para que devemos usá-lo?
Notas:
- Não há necessidade de descrever o histórico de como isso evoluiu (as páginas de manual relevantes mencionam alterações no Linux 2.6.x, 3.5 e 3.6), a menos que seja necessário - eu apenas me preocupo com como as coisas estão agora.
- Por favor, não me diga para usar apenas libc ou outras instalações de nível superior, eu sei disso.
fonte
Respostas:
A descrição na
open(2)
página do manual fornece algumas dicas para começar:Às vezes, não queremos abrir um arquivo ou diretório. Em vez disso, queremos apenas uma referência a esse objeto do sistema de arquivos para executar determinadas operações (por exemplo,
fchdir()
para um diretório referido por um descritor de arquivo que abrimos usandoO_PATH
). Portanto, um ponto trivial: se esse é o nosso objetivo, abrir comO_PATH
deve ser um pouco mais barato, pois o arquivo em si não é realmente aberto.E um ponto menos trivial: antes da existência de
O_PATH
, a maneira de obter tal referência a um objeto do sistema de arquivos era abrir o objetoO_RDONLY
. Mas o uso deO_RDONLY
requer que tenhamos permissão de leitura no objeto. No entanto, existem vários casos de uso em que não precisamos realmente ler o objeto: por exemplo, executar um binário ou acessar um diretório (fchdir()
) ou acessar um diretório para tocar em um objeto dentro do diretório.Uso com chamadas do sistema "* at ()"
O comum, mas não o único, o uso de
O_PATH
é abrir um diretório, a fim de ter uma referência a esse diretório para uso com o "* a" chamadas de sistema, comoopenat()
,fstatat()
,fchownat()
e assim por diante. Esta família de chamadas de sistema, que podemos mais ou menos pensam como os sucessores modernos para as chamadas de sistema mais velhos com nomes semelhantes (open()
,fstat()
,fchown()
e assim por diante), servem para dois propósitos, o primeiro dos quais você tocar em quando você perguntar " por que eu quero usar um descritor de arquivo em vez do caminho do diretório? ". Se olharmos mais abaixo naopen(2)
página de manual, encontramos este texto (em um subtítulo com a justificativa para as chamadas do sistema "* at"):Para tornar isso mais concreto ... Suponha que tenhamos um programa que deseja executar várias operações em um diretório que não seja o diretório de trabalho atual, o que significa que devemos especificar algum prefixo de diretório como parte dos nomes de arquivos que usamos. Suponha, por exemplo, que o nome do caminho seja
/dir1/dir2/file
e desejemos executar duas operações:/dir1/dir2/file
(por exemplo, quem possui o arquivo ou a que horas foi modificado pela última vez)./dir1/dir2/file.new
.Agora, suponha que fizemos tudo usando chamadas de sistema tradicionais baseadas em nomes de caminhos:
Agora, além disso, suponha que no prefixo do diretório
/dir1/dir2
um dos componentes (digamosdir2
) fosse realmente um link simbólico (que se refere a um diretório) e que entre a chamada parastat()
e a chamada paraopen()
uma pessoa mal-intencionada fosse possível alterar o destino do link simbólicodir2
para apontar para um diretório diferente. Essa é uma condição clássica de corrida no momento do check-in-time. Nosso programa verificou um arquivo em um diretório, mas foi levado a criar um arquivo em um diretório diferente - talvez um diretório sensível à segurança. O ponto principal aqui é que o nome do caminho/dir/dir2
parecia o mesmo, mas o que se refere mudou completamente.Podemos evitar esse tipo de problema usando as chamadas "* at". Primeiro, obtemos um identificador referente ao diretório em que faremos nosso trabalho:
O ponto crítico aqui é que
dirfd
é uma referência estável ao diretório que foi referido pelo caminho/dir1/dir2
no momento daopen()
chamada. Se o destino do link simbólicodir2
for alterado posteriormente, isso não afetará o quedirfd
se refere. Agora, podemos fazer nossa operação de verificação + usando as chamadas "* at" equivalentes às chamadasstat()
eopen()
acima:Durante essas etapas, qualquer manipulação de links simbólicos no nome do caminho
/dir/dir2
não terá impacto: a verificação (fstatat()
) e a operação (openat()
) são garantidas no mesmo diretório.Há outro propósito em usar as chamadas "* at ()", relacionadas à idéia de "diretórios de trabalho atuais por thread" em programas multithread (e novamente poderíamos abrir os diretórios usando
O_PATH
), mas acho que esse uso provavelmente é menos relevante para sua pergunta e deixo que você leia aopen(2)
página de manual, se quiser saber mais.Uso com descritores de arquivo para arquivos regulares
Um uso de
O_PATH
arquivos regulares é abrir um binário para o qual temos permissão de execução (mas não necessariamente permissão de leitura, para que não possamos abrir o arquivoO_RDONLY
). Esse descritor de arquivo pode ser passadofexecve(3)
para executar o programa. Tudo o quefexecve(fd, argv, envp)
está fazendo com seufd
argumento é essencialmente:(Embora, começando com glibc 2.27, a implementação faça uso da
execveat(2)
chamada do sistema, nos kernels que fornecem essa chamada do sistema.)fonte
The problem is that between the existence check and the file creation step, path or to ... could be modified
- não pode analisar esta frase. Mas eu entendo, eu acho. Portanto, serve como uma espécie de mecanismo de bloqueio em um diretório. Mas por que usar oopen()
resultado em vez de um bloqueio real?