
DR
A tentativa de formatar um dispositivo de bloco em meu sistema de arquivos FUSE falha no EPERM
syscall open
. As permissões estão definidas para777e os s necessários ioctl
são stubados, mas nenhum log é impresso no manipulador FUSE.
Fundo
Estou escrevendo um programa para criar imagens de disco virtual. Um dos meus critérios é que ele possa ser executado sem acesso de superusuário, o que significa que não posso montar dispositivos de loopback, alterar proprietários de arquivos ou até mesmo editar/etc/fuse.conf. Por esta razão, a minha abordagem acaba por ser bastante prolixa. Especificamente, para formatar as diversas partições do disco, gostaria de poder usar as ferramentas do sistema, porque isso me dá uma gama muito maior de sistemas de arquivos possíveis. Isso envolve expor as diversas partições do VDisk como dispositivos de bloco para o sistema. No entanto, todos os métodos possíveis que encontrei exigem nbd
dispositivos s ou loopback. Ambos requerem acesso de superusuário.
Implementando o FUSE sozinho
No entanto, a implementação de dispositivos de bloco no FUSE não é apenas possível, mas também suportada. Infelizmente não consegui encontrar muita documentação sobre o assunto e como estou fazendo tudo isso em Rust, o mundo da documentação para isso é ainda mais escasso.
Implementei os seguintes métodos FUSE:
init
lookup
getattr
open
read
write
readdir
ioctl
BLKGETSIZE
BLKFLSBUF
BLKSSZGET
Posso listar o conteúdo do sistema de arquivos e obter informações de diretório/arquivo. Estou ignorando deliberadamente os métodos que criam ou modificam recursos, pois isso é feito através do processo de construção.
O erro
Como mencionei, eu recebopermissão negada( EPERM
) erro. strace
A mkfs
chamada mostra que é a open
chamada para o dispositivo de bloco que falha no lado do kernel.strace
Resultado completo.
execve("/usr/sbin/mkfs.fat", ["mkfs.fat", "out/partitions/EFI"], 0x7ffd42f64ab8 /* 76 vars */) = 0
--- snip ---
openat(AT_FDCWD, "out/partitions/EFI", O_RDWR|O_EXCL) = -1 EACCES (Permission denied)
write(2, "mkfs.fat: unable to open out/par"..., 63mkfs.fat: unable to open out/partitions/EFI: Permission denied
) = 63
exit_group(1) = ?
Para maior clareza, minha estrutura de diretórios é semelhante a esta:
out
├── minimal.qcow2 [raw disk image] (shadows minimal.qcow2 [qcow2 file] with qemu-storage-daemon)
├── partitions
│ ├── EFI [Block device]
│ └── System [Block device]
└── qemu-monitor.sock [UNIX domain socket]
Claro, existem funções de registro que rastreiam cada método. Vejo logs ao listar as partições, mas não durante a formatação.
Como mencionei, encontrei muito pouca documentação sobre o que realmente poderia estar causando esse erro.
Mais informações
Graças aos insights de @orenkihon, encontrei mais alguns detalhes que me deixam perplexo.
Encontrei algumas opções
fuser
interessantes:MountOption::Dev
Habilitar caracteres especiais e bloquear dispositivosMountOption::DefaultPermission
Habilite a verificação de permissão no kernelMountOption::RW
Sistema de arquivos de leitura e gravação(aparentemente não é uma opção padrão)
Infelizmente, nenhuma combinação disso resolveu meu problema.
As funções de log não são chamadas imediatamente. Eles parecem estar ligados a algum tipo de operação de descarga. Posso executar o
mkfs.fat
comando, ver um ou dois logs, voltar para meu IDE e ver uma página com logs aparecer.Isso pode ser devido ao fato de o diretório que estou gerando os arquivos estar dentro do diretório do projeto, portanto é visível para o IDE, mas me parece muito incomum.
O log na
access
função nunca é visível, mas nastatfs
função é, mas somente semkfs
for chamado de fora doout
diretórioeé a primeira de todasmkfs
as chamadas.project > cd ./out project/out > mkfs.fat partitions/EFI mkfs.fat 4.2 (2021-01-31) mkfs.fat: unable to open partitions/EFI: Permission denied # No logs project > mkfs.fat out/partitions/EFI mkfs.fat 4.2 (2021-01-31) mkfs.fat: unable to open out/partitions/EFI: Permission denied # No logs project > cargo run ... project > mkfs.fat out/partitions mkfs.fat 4.2 (2021-01-31) mkfs.fat: unable to open out/partitions/EFI: Permission denied # Logs appear after switching to IDE
- Estou vendo esta mensagem de log pela primeira vez hoje:
[2024-04-21T16:58:24Z DEBUG fuser::mnt::fuse_pure] fusermount:
[2024-04-21T16:58:24Z DEBUG fuser::mnt::fuse_pure] fusermount: fusermount3: unsafe option dev ignored
Existe um MountOption::Dev
sepcified, que supostamente adiciona suporte para dispositivos de blocos e caracteres. No entanto, não consigo explicar por que está sendo rejeitado. Eu estava esperançoso de poder usar uma versão corrigida, libfuse3
mas parece que não.
Informações extras que podem ser úteis
Especificações do sistema
Copiado diretamente das Informações do Sistema do KDE
- Sistema operacional: Kubuntu 23.10
- Versão do KDE Plasma: 5.27.8
- Versão das estruturas do KDE: 5.110.0
- Versão Qt: 5.15.10
- Versão do kernel: 6.5.0-28 genérico (64 bits)
- Plataforma gráfica: Wayland
- Processadores: Intel® Core™ i9-13900 de 32 × 13ª geração
- Memória: 31,1 GiB de RAM
- Processador gráfico: AMD Radeon RX 7900 XT
- Fabricante: ASUS
As operações de escrita genérica também falham
Uma sugestão foi verificar se mkfs
falha caso fat32
não suporte o dispositivo de bloco. No entanto, este não parece ser o caso, pois a formatação com qualquer outro sistema de arquivos produz os mesmos resultados.
Também estou usando mkfs
como plataforma de teste porque atualmente não conheço nenhum outro utilitário de sistema disponível que grave diretamente para bloquear dispositivos e mkfs
é algo que pretendo usar de qualquer maneira.
Más notícias :(
Ao ler as páginas de manual, me depareieste parágrafoque fez meu coração afundar:
A maioria das opções genéricas de montagem descritas em mount são suportadas (ro, rw, suid, nosuid, dev, nodev, exec, noexec, atime, noatime, sync, async, dirsync). Os sistemas de arquivos são montados com nodev,nosuid por padrão, que só pode ser substituído por um usuário privilegiado.
Então parece que isso não é possível. Ainda assim, quaisquer insights aqui - qualquer esperança menor - seriam muito apreciados.
Responder1
Se bem entendi, você expõe um dispositivo de bloco por meio do sistema de arquivos FUSE, que não funciona por motivos de segurança.
Em sistemas do tipo Unix, os arquivos são muito mais do que apenas arquivos. Permitir que um usuário sem privilégios crie dispositivos de bloco arbitrários é problemático porque, ao criar um dispositivo de bloco correspondente ao dispositivo rootfs, o sistema pode ser comprometido.
Você pode querer dar uma olhada no que o programa fakeroot
faz. Ele conecta todas libc
as funções usadas pelo programa que você executa nele. Sempre que é realizada uma operação que requer root
acesso (como criar um dispositivo, por exemplo), a operação é registrada. Mais tarde fakeroot
irá falsificar a existência do arquivo proibido.
Como você deseja apenas expor as partições, você pode adotar uma abordagem semelhante e falsificar alguns dos ioctl
arquivos em seu dispositivo falso, quando na realidade é apenas um arquivo normal. Não tenho certeza se isso ajudará, mas é bom ter isso em mente.