为什么普通用户无法删除 btrfs 子卷

为什么普通用户无法删除 btrfs 子卷

使用循环安装的用户创建的 btrfs 文件系统,并正确设置权限,用户可以自由创建 btrfs 子卷:

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

但是,尝试删除新创建的子卷会导致错误:

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'

root 用户当然可以删除它:

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

创建和删除操作之间的这种行为差异似乎有点奇怪。有人能解释一下吗?

以下是命令的确切顺序:

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

以下是权限:

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

以及相关行df -T

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

该发行版是 Debian Wheezy、3.2.0-4-686-pae内核、v0.19btrfs-tools。在 Ubuntu Saucy、3.11.0-4-generic内核、v0.20-rc1btrfs-tools上仍然出现这种情况。

答案1

嗯,这对我来说是一次学习经历,但我最终明白了。我将在这里解释我的过程,以便更容易知道如何自己解决这些问题(BTRFS 文档,我相信您已经发现,目前相对不完整)。

起初我认为创建子卷是一个ioctl没有执行任何功能检查的处理程序(这可能是也可能不是安全问题,具体取决于它是否有一些逻辑),而删除它是直接修改元数据(因此用户可能需要CAP_SYS_RAWIO正常工作)。

为了验证一下,我破解了btrfs-utils源代码,发现如下:

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);

好吧,这没有帮助,他们是两个都ioctl(有趣的旁注:由于某种原因,“快照”在源代码中经常与“子卷”互换使用)。所以我查看了内核源代码并在fs/btrfs/ioctl.c.

最终,我追溯到btrfs_ioctl_snap_destroy()第 2116 行:

     if (!capable(CAP_SYS_ADMIN)){

具体来说,这是检查他们是否有能力,但如果他们确实有能力,逻辑就会直接跳到执行操作。 if 语句的主体检查子卷 inode 的所有者是否是普通用户,并且USER_SUBVOL_RM_ALLOWEDBTRFS 选项启用后继续执行处理程序。如果它们都没有,ioctl 处理程序将退出并出现错误。

因此,看起来销毁“快照”(又名“子卷”)通常需要用户拥有CAP_SYS_ADMIN(或USER_SUBVOL_RM_ALLOWED启用并且用户“拥有”给定子卷)。太好了,创建快照/卷怎么样?

ioctl 的处理程序似乎btrfs_ioctl_snap_create()不包含直接或间接的调用capable()。由于这是代理访问的主要方式,我认为这意味着子卷创建总是成功了。这从功能层面解释了为什么您会看到您所看到的内容。

我无法说话为什么除了 BTRFS 的主要用例(即用户访问受限的服务器)之外,这被认为是可取的。这还不够,但我没有看到任何代码来实际停止操作。如果您找不到原因的答案(并且您很想得到它),您可能需要在内核邮件列表上询问。

结论

我的研究似乎表明任何人都可以创建子卷,但为了删除子卷,您要么需要拥有子卷,CAP_SYS_ADMIN要么需要调用用户是子卷 inode 的所有者并USER_SUBVOL_RM_ALLOWED启用。

子卷的创建没有意义,所以我可能错过了一些拒绝操作的间接方式,因为这似乎是 DoS 系统的一种简单方法。

注意:我无法验证此功能,但一旦我回到家,我就可以设置setcap魔法是否按预测方式工作。

答案2

删除子卷允许某人取消链接不属于他们的文件。在我看来,特权用户在特权较低的用户选择的位置写入的文件是公平的游戏,但贡献非根删除功能的人可能对这些语义的安全性和内容没有足够的信心将它们作为新的安装选项提交 ( mount -o user_subvol_rm_allowed)。

答案3

“无法删除/home”(即@home)。

为什么要删除 /home/ 帐户所在的子卷,除非您已创建 /home_snapshot_yymmdd 快照来替换 /home?

我是使用 btrfs 的新手,但这是我发现的:@/ 和 @home(/ 和 /home)是由 btrfs 在作为文件系统安装在硬盘上时创建的。据我了解,除非您要从以前的快照恢复 /home,否则您就会陷入困境。

但是,您可以使用 mount /dev/sa /mnt/ (或运行 btrfs 系统的任何设备)挂载 /home 所在的设备,作为 ROOT,然后 cd 到 /mnt/ 并从那里发出删除命令@家。然后,您可以使用 mv 命令将 @home_snapshot_yymmdd (或您命名的任何名称)移动到 @home。移动可能需要几个小时,具体取决于@home 的大小。然后 CD 返回到您自己的帐户并发出 sudo umount /mnt/ 您从未真正注销或关闭您的系统。这就是 btrfs 的美妙之处。

相关内容