為什麼普通使用者不能刪除 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.19
btrfs-tools。在 Ubuntu Saucy、3.11.0-4-generic
kernel、v0.20-rc1
btrfs-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_ALLOWED
BTRFS 選項啟用它繼續執行處理程序。如果它們都沒有,則 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
魔術是否起作用,這如何預測。