Btrfs

為什麼普通使用者不能刪除 btrfs 子卷

  • December 8, 2018

使用循環安裝的使用者創建 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-generickernel、v0.20-rc1btrfs-tools 上仍然會出現這種情況。

嗯,這對我來說是一次學習經歷,但我最終想通了。我將在這裡解釋我的過程,以便更容易知道如何自己解決這些問題(我相信您已經發現,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魔術是否起作用,這如何預測。

引用自:https://unix.stackexchange.com/questions/88932