
TL;DR
Попытка форматирования блочного устройства в моей файловой системе FUSE завершается ошибкой EPERM
при open
системном вызове. Разрешения установлены на777и необходимые ioctl
s заглушены, но журналы не выводятся из обработчика FUSE.
Фон
Я пишу программу для создания виртуальных образов дисков. Одним из моих критериев является то, что она должна работать с нулевым доступом суперпользователя, то есть я не могу монтировать устройства loopback, менять владельцев файлов или даже редактировать/etc/fuse.conf. По этой причине мой подход оказывается довольно длинным. В частности, для форматирования различных разделов на диске я хотел бы иметь возможность использовать системные инструменты, поскольку это дает мне гораздо больший диапазон возможных файловых систем. Это подразумевает предоставление различных разделов на VDisk в качестве блочных устройств для системы. Однако все возможные методы, которые я нашел, требовали либо nbd
s, либо устройств loopback. Оба из которых требуют доступа суперпользователя.
Реализую 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
sepcified, который якобы добавляет поддержку блочных и символьных устройств. Однако я не могу объяснить, почему его отклоняют. Я надеялся, что смогу использовать пропатченную версию, libfuse3
но, похоже, нет.
Дополнительная информация, которая может быть полезна
Характеристики системы
Скопировано непосредственно из системной информации KDE
- Операционная система: Kubuntu 23.10
- Версия KDE Plasma: 5.27.8
- Версия фреймворков KDE: 5.110.0
- Версия Qt: 5.15.10
- Версия ядра: 6.5.0-28-generic (64-бит)
- Графическая платформа: Wayland
- Процессоры: 32 × Intel® Core™ i9-13900 13-го поколения
- Память: 31,1 ГиБ ОЗУ
- Графический процессор: AMD Radeon RX 7900 XT
- Производитель: ASUS
Операции общей записи также не работают
Было предложено проверить, mkfs
не срабатывает ли в случае, если fat32
не поддерживает блочное устройство. Однако, похоже, это не так, поскольку форматирование с помощью любой другой файловой системы дает те же результаты.
Я также использую его mkfs
в качестве платформы для тестирования, поскольку в настоящее время не знаю других легкодоступных системных утилит, которые напрямую записывают данные на блочные устройства, а mkfs
я в любом случае собираюсь использовать именно их.
Плохие новости :(
Читая man-страницы, я наткнулся наэтот абзацчто заставило мое сердце замереть:
Поддерживается большинство общих параметров монтирования, описанных в 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
s на вашем поддельном устройстве, в то время как на самом деле это просто обычный файл. Я не уверен, что это поможет, но хорошо иметь это в виду.