FUSE 파일 시스템에서 블록 장치를 포맷할 때 EPERM

FUSE 파일 시스템에서 블록 장치를 포맷할 때 EPERM

TL;DR

FUSE 파일 시스템에서 블록 장치를 포맷하려는 시도가 syscall EPERM에서 실패합니다 open. 권한은 다음과 같이 설정됩니다.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경우에만 해당됩니다.mkfsout그리고전화 중 첫 번째입니다 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의 시스템 정보에서 직접 복사됨

  • 운영 체제: 쿠분투 23.10
  • KDE 플라즈마 버전: 5.27.8
  • KDE 프레임워크 버전: 5.110.0
  • Qt 버전: 5.15.10
  • 커널 버전: 6.5.0-28-일반(64비트)
  • 그래픽 플랫폼: Wayland
  • 프로세서: 32 × 13세대 Intel® Core™ i9-13900
  • 메모리: 31.1GiB RAM
  • 그래픽 프로세서: AMD Radeon RX 7900 XT
  • 제조사 : ASUS

일반 쓰기 작업도 실패합니다.

블록 장치를 지원하지 않는 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가짜 장치에서 일부를 위조할 수 있지만 실제로는 일반 파일일 뿐입니다. 이것이 도움이 될지는 모르겠지만, 이 점을 염두에 두는 것이 좋습니다.

관련 정보