긴 이야기 짧게
FUSE 파일 시스템에서 블록 장치를 포맷하려는 시도가 시스템 호출 EPERM
로 인해 실패했습니다. open
권한은 다음과 같이 설정됩니다.777화필요한 ioctl
s는 스텁되지만 FUSE 핸들러 내에는 로그가 인쇄되지 않습니다.
배경
가상 디스크 이미지를 생성하는 프로그램을 작성 중입니다. 내 기준 중 하나는 슈퍼유저 액세스가 전혀 없는 상태에서 실행될 수 있어야 한다는 것이었습니다. 즉, 루프백 장치를 설치할 수 없고 파일 소유자를 변경할 수 없으며 심지어 편집할 수도 없었습니다./etc/fuse.conf. 이런 이유로 내 접근 방식은 결국 매우 장황해졌습니다. 특히, 디스크의 개별 파티션을 포맷하려면 시스템 도구를 사용하고 싶습니다. 이렇게 하면 가능한 파일 시스템의 범위가 더 넓어지기 때문입니다. 여기에는 VDisk의 개별 파티션을 시스템에 블록 장치로 노출시키는 것이 포함됩니다. 그러나 내가 찾은 가능한 모든 방법에는 nbd
s 또는 루프백 장치가 필요합니다. 둘 다 슈퍼유저 액세스가 필요합니다.
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의 통찰력 덕분에 저는 혼란스러웠던 세부 사항을 더 많이 발견했습니다.
fuser
몇 가지 흥미로운 옵션을 찾았습니다.MountOption::Dev
특수 문자 및 블록 장치 활성화MountOption::DefaultPermission
커널에서 권한 확인 활성화MountOption::RW
파일 시스템 읽기 및 쓰기(물론 기본 옵션은 아닙니다)
불행히도 이러한 조합 중 어느 것도 내 문제를 해결하지 못했습니다.
로깅 함수는 즉시 호출되지 않습니다. 일종의 플러시 작업과 관련이 있는 것으로 보입니다. 명령 을 실행하고
mkfs.fat
, 한두 개의 로그를 보고, IDE로 다시 전환하고, 표시된 로그 페이지를 볼 수 있습니다.파일을 생성하는 디렉터리가 프로젝트 디렉터리 내부에 있어서 IDE에서 볼 수 있기 때문일 수 있지만 매우 이상하다고 생각됩니다.
함수 내부의 로그는
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
- 오늘 처음으로 이 로그 메시지를 보았습니다.
[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
실제로는 일반 파일일 뿐인 가짜 장치에서 일부 파티션을 가짜로 만들 수 있습니다. 이것이 도움이 될지는 모르겠지만, 명심해 두는 것이 좋습니다.