Por que um usuário comum não pode excluir um subvolume btrfs

12

Usando um sistema de arquivos btrfs criado por usuário montado em loop, com as permissões definidas corretamente, um usuário pode criar livremente subvolumes btrfs:

user@machine:~/btrfs/fs/snapshots$ /sbin/btrfs sub create newsubvol
Create subvolume './newsubvol'

No entanto, tentar excluir o subvolume recém-criado resulta em um erro:

user@machine:~/btrfs/fs/snapshots$ /sbin/btrfs sub del newsubvol
Delete subvolume '/home/user/btrfs/fs/snapshots/newsubvol'
ERROR: cannot delete '/home/user/btrfs/fs/snapshots/newsubvol'

O usuário root, é claro, é capaz de excluí-lo:

root@machine:/home/user/btrfs/fs/snapshots# /sbin/btrfs sub del newsubvol
Delete subvolume '/home/user/btrfs/fs/snapshots/newsubvol'

Essa diferença de comportamento entre as operações de criação e exclusão parece um pouco estranha. Alguém pode lançar alguma luz sobre isso?

Aqui está a sequência exata de comandos:

user@machine:~$ dd if=/dev/zero of=btrfs_disk bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 1.2345 s, 84.9 MB/s
user@machine:~$ mkdir mountpoint
user@machine:~$ /sbin/mkfs.btrfs btrfs_disk

WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using

SMALL VOLUME: forcing mixed metadata/data groups
Created a data/metadata chunk of size 8388608
fs created label (null) on btrfs_disk
    nodesize 4096 leafsize 4096 sectorsize 4096 size 100.00MB
Btrfs Btrfs v0.19
user@machine:~$ sudo mount btrfs_disk mountpoint/
user@machine:~$ cd mountpoint/
user@machine:~/mountpoint$ /sbin/btrfs sub create test
Create subvolume './test'
user@machine:~/mountpoint$ /sbin/btrfs sub delete test
Delete subvolume '/home/user/mountpoint/test'
ERROR: cannot delete '/home/user/mountpoint/test' - Operation not permitted

Aqui estão as permissões:

user@machine:~/mountpoint$ ls -la
total 4
drwxr-xr-x 1 user user    8 Set  4 09:30 .
drwx------ 1 user user 4486 Set  4 09:29 ..
drwx------ 1 user user    0 Set  4 09:38 test

E a linha relevante sobre df -T:

Filesystem              Type     1K-blocks      Used Available Use% Mounted on
/dev/loop0              btrfs       102400        32     98284   1% /home/user/mountpoint

A distribuição é um Debian Wheezy, 3.2.0-4-686-paekernel, v0.19btrfs-tools. A situação ainda ocorre no Ubuntu Saucy, 3.11.0-4-generickernel, v0.20-rc1btrfs-tools.

goncalopp
fonte
Pelo meu entendimento, esse tipo de sistema de arquivos ainda é experimental e não está pronto para produção.
Mdpc
Você pode adicionar a saída de df -Te btrfs version? Quando tentei o mesmo, recebi o seguinte erro "ERRO: não é possível criar o subvolume - permissão negada"
bsd
@mdpc Embora isso seja verdade, o btrfs existe há alguns anos e espera-se que seja um pouco estável nesse estágio. Ainda pode ser útil entender se este é um bug ou um 'recurso', neste momento.
Goncalopp # 4/13
@bdowning Adicionei a sequência exata de comandos, df, e as versões que usei.
Goncalopp # 04/13
O kernel 3.2 já tem mais de um ano e meio. Se você quiser jogar com sistemas de arquivos experimentais, poderá executar um kernel mais atualizado.
Psusi

Respostas:

14

Bem, essa foi uma experiência de aprendizado para mim, mas eu finalmente descobri. Vou explicar meu processo aqui para que seja mais fácil saber como resolver essas coisas por conta própria (a documentação do BTRFS, como tenho certeza de que você descobriu, é relativamente incompleta no momento).

No começo, pensei que criar o subvolume era ioctlum manipulador que não fazia nenhuma verificação de capacidade (o que pode ou não ter sido um problema de segurança, dependendo da existência de alguma lógica), enquanto excluí-lo estava modificando os metadados diretamente (e, portanto, o usuário pode exigir CAP_SYS_RAWIOque funcione corretamente).

Para verificar, abri o btrfs-utilscódigo fonte e descobri:

Create subvolume, cmds-receive.c Line 180:
         ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);

Delete subvolume, cmds-subvolume.c Line 259:
         res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);

Bem, isso não ajuda, os dois são do ioctl (nota lateral interessante: "snapshot" é frequentemente usado de forma intercambiável no código fonte com "subvolume" por algum motivo). Então eu fui ao código fonte do kernel e encontrei os dois manipuladores fs/btrfs/ioctl.c.

Eventualmente, eu o rastreei até a btrfs_ioctl_snap_destroy()linha 2116:

     if (!capable(CAP_SYS_ADMIN)){

Especificamente, essa é uma verificação se eles não têm a capacidade, mas se a possuem, a lógica pula diretamente para a execução da operação. O corpo da instrução if verifica se é o usuário comum quem é o proprietário do inode do subvolume e a USER_SUBVOL_RM_ALLOWEDopção BTRFS está habilitada para continuar executando o manipulador. Se eles não tiverem, o manipulador ioctl sai com um erro.

Portanto, parece que a destruição de um "instantâneo" (também conhecido como "subvolume") geralmente requer um usuário que tenha CAP_SYS_ADMIN(ou para USER_SUBVOL_RM_ALLOWEDser ativado e o usuário "possua" o subvolume especificado). Ótimo, que tal criar um instantâneo / volume?

O manipulador para o ioctl parece ser btrfs_ioctl_snap_create()esse manipulador parece não conter nenhuma chamada capable()direta ou indiretamente. Como essa é a principal maneira de o acesso ser intermediado, estou entendendo que a criação de subvolume sempre é bem-sucedida. Isso explica em um nível funcional por que você está vendo o que está vendo.

Não posso explicar por que isso é considerado desejável fora do principal caso de uso do BTRFS, sendo um servidor com acesso restrito ao usuário. Isso não é suficiente, mas não estou vendo nenhum código para realmente parar a operação. Se você não conseguir encontrar uma resposta para o motivo (e você deseja tê-lo), pode ser necessário perguntar na lista de discussão do kernel.

Conclusão

Minha pesquisa parece indicar que qualquer pessoa pode criar subvolumes, mas para excluir um subvolume que você precisa CAP_SYS_ADMINou precisa ser verdadeiro, tanto que o usuário que chama é o proprietário do inode do subvolume e está USER_SUBVOL_RM_ALLOWEDativado.

A criação do subvolume não faz sentido, então provavelmente estou perdendo alguma maneira indireta de negar a operação, pois isso parece uma maneira fácil de fazer DoS um sistema.

Nota: não estou em um local onde posso verificar essa funcionalidade, mas, quando chego em casa, posso definir se a setcapmágica funciona como isso prevê.

Bratchley
fonte
A maneira como faz sentido (em relação à sua preocupação com DoS) é se rmdirfor permitido em subvolumes vazios. Então rm -rfuncionará de forma transparente. Infelizmente, o código simplesmente não foi desenvolvido (ainda). Parece que alguém fez três tentativas em 2010 e desistiu :(. Spinics.net/lists/linux-btrfs/msg06499.html
sourcejedi
5

A exclusão de um subvolume permite que alguém desvincule arquivos que não são de sua propriedade. Na minha opinião, os arquivos que um usuário privilegiado grava em um local escolhido por um usuário menos privilegiado são um jogo justo, mas a pessoa que contribuiu com a funcionalidade de exclusão não raiz provavelmente não se sentiu suficientemente confiante sobre o quão segura era a semântica e o conteúdo para enviá-los como uma nova opção de montagem ( mount -o user_subvol_rm_allowed).

Gabriel
fonte
1
Surpreendentemente, no UNIX®, você pode desvincular facilmente um arquivo que não possui - você só precisa ter permissão de gravação em seu diretório.
poige
Eu tenho o mesmo problema no Fedora 20, eu tenho / home em uma subvolume, eu estou usando o usuário root, mas anyaway, eu não posso apagar / home
c4f4t0r
poige, se o arquivo em questão estiver em uma pasta que você não possui, não será possível desvinculá-lo nem desvincular a própria pasta, pois ela ainda contém itens nela. Você só pode executar operações não destrutivas nesta pasta, como movê-la ou renomeá-la.
sleblanc
-1

"Não é possível excluir / home" (que é @home).

Por que você deseja excluir o subvolume no qual sua / home / conta reside, a menos que você tenha criado um snapshot / home_snapshot_yymmdd para substituir / home?

Eu sou novo no uso do btrfs, mas foi o que descobri: @ / e @home (/ e / home) são criados pelo btrfs quando ele é instalado no seu HD como sistema de arquivos. A menos que você esteja restaurando o / home de um instantâneo anterior, como eu o entendo, você estará se ajoelhando.

No entanto, você pode montar o dispositivo em que / home está, AS ROOT, usando mount / dev / sa / mnt / (ou qualquer outro dispositivo em que o sistema btrfs esteja sendo executado). Em seguida, cd para / mnt / e, a partir daí, execute o comando delete para @casa. Em seguida, você pode usar o comando mv para mover @home_snapshot_yymmdd (ou como você o nomeou) para @home. A mudança pode levar horas, dependendo do tamanho do @home. Depois, faça o CD de volta para sua própria conta e emita sudo umount / mnt / Você nunca realmente saiu do sistema ou desligou o sistema. Essa é uma beleza do btrfs.

GreyGeek
fonte
Parece que eles já o fizeram. O Btrfs não cria @ e @home, a menos que você os peça (ou sua distribuição como o Ubuntu faz isso por você).
Anthon