在 FUSE 文件系统上格式化块设备时的 EPERM

在 FUSE 文件系统上格式化块设备时的 EPERM

长话短说

尝试格式化 FUSE 文件系统上的块设备EPERMopen系统调用时失败。权限设置为第777章并且必要的ioctls 已被存根,但 FUSE 处理程序内不会打印任何日志。

背景

我正在编写一个程序来创建虚拟磁盘映像。我的标准之一是它必须能够以零超级用户访问权限运行,这意味着我无法安装环回设备、更改文件所有者甚至编辑/etc/fuse.conf。出于这个原因,我的方法最终变得相当冗长。具体来说,为了格式化磁盘上的各个分区,我希望能够使用系统工具,因为这为我提供了更大范围的可能文件系统。这涉及将VDisk上的各个分区作为块设备暴露给系统。然而,我发现的所有可能的方法都需要nbds 或环回设备。两者都需要超级用户访问权限。

自己实现FUSE

然而,在 FUSE 中实现块设备不仅是可能的,而且是受支持的。不幸的是,我无法找到关于此事的太多文档,而且由于我是在 Rust 中完成所有这些工作,因此相关文档更加稀缺。

我已经实现了以下 FUSE 方法:

  • init
  • lookup
  • getattr
  • open
  • read
  • write
  • readdir
  • ioctl
    • BLKGETSIZE
    • BLKFLSBUF
    • BLKSSZGET

我可以列出文件系统的内容并获取目录/文件信息。我故意忽略创建或修改资源的方法,因为这是通过构建过程完成的。

错误

如前所述,我得到没有权限EPERM) 错误。strace调用该mkfs调用表明对open块设备的调用在内核端失败。完整strace结果

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)                           = ?

为了清楚起见,我的目录结构如下所示:

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]

当然,有跟踪每个方法的日志记录功能。我在列出分区时确实看到了日志,但在格式化时却看不到日志。

正如我所提到的,我发现关于实际可能导致此错误的原因的文档很少。

进一步的见解

感谢@orenkishon 的见解,我发现了更多令我困惑的细节。

  1. fuser我发现了一些有趣的选项:

    • MountOption::Dev 启用特殊字符和块设备
    • MountOption::DefaultPermission 在内核中启用权限检查
    • MountOption::RW 读写文件系统(显然不是默认选项)

    不幸的是,这些组合都没有解决我的问题。

  2. 不会立即调用日志函数。它们似乎与某种冲洗操作有关。我可以运行该mkfs.fat命令,查看一两个日志,切换回 IDE,然后查看显示的一页日志。

    这可能是因为我生成文件的目录位于项目目录内,因此它对 IDE 是可见的,但它让我觉得非常不寻常。

  3. 函数中的日志access永远不可见,但在statfs函数中是可见的,但仅当从目录mkfs外部调用时才可见out是所有呼叫中的第一个mkfs

    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
    
  1. 我今天第一次看到这条日志消息:
[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

有一个MountOption::Dev特定的,据说它增加了对块和字符设备的支持。但我似乎无法解释为什么它被拒绝。我希望我可以使用修补版本,libfuse3但似乎没有。

可能有用的额外信息

系统规格

直接从 KDE 的系统信息复制

  • 操作系统:Kubuntu 23.10
  • KDE 等离子版本:5.27.8
  • KDE 框架版本:5.110.0
  • Qt 版本:5.15.10
  • 内核版本:6.5.0-28-generic(64位)
  • 图形平台:Wayland
  • 处理器:32 个第 13 代智能英特尔® 酷睿™ i9-13900
  • 内存:31.1 GiB RAM
  • 图形处理器:AMD Radeon RX 7900 XT
  • 制造商: 华硕

通用写入操作也会失败

一个建议是检查是否在不支持块设备的mkfs情况下失败。fat32然而,情况似乎并非如此,因为使用任何其他文件系统进行格式化都会产生相同的结果。

我还使用它mkfs作为测试平台,因为我目前不知道有任何其他现成的系统实用程序可以直接写入块设备,并且mkfs无论如何我都打算使用它。

坏消息 :(

在阅读手册页时我遇到了这一段这让我的心沉了下去:

支持 mount 中描述的大多数通用挂载选项(ro、rw、suid、nosuid、dev、nodev、exec、noexec、atime、noatime、sync、async、dirsync)。文件系统默认使用nodev,nosuid挂载,只能由特权用户覆盖。

所以看起来这是不可能的。尽管如此,这里的任何见解——任何一线希望——都将受到高度赞赏。

答案1

如果我理解正确的话,您通过 FUSE 文件系统公开了一个块设备,出于安全原因,这不起作用。

在类 Unix 系统中,文件不仅仅是文件。让非特权用户创建任意块设备是有问题的,因为通过创建与 rootfs 设备对应的块设备,系统可能会受到损害。

您可能想看看该程序的作用fakeroot。它挂钩libc您在其下运行的程序所使用的每个函数。每当完成需要访问的操作root(例如创建设备)时,都会记录该操作。稍后fakeroot将伪造禁止文件的存在。

由于您只想公开分区,因此您可以采取类似的方法并ioctl在假设备上伪造一些分区,而实际上它只是一个常规文件。我不确定这会有帮助,但记住这一点是件好事。

相关内容