LINUX.ORG.RU

«Authentication failed» в wayland-приложении

 , ,


1

2

Заранее прошу прощения за потенциально ламерский вопрос. Это мой первый опыт работы с Wayland.

Система, которую я разрабатываю, очень критична по времени запуска графической подсистемы, поэтому возникла идея запускать Weston и нужное приложение ещё на этапе initramfs. Желаемое получилось, но внезапно появилась проблема запуска остальных приложений, из «основного» юзерспейса, а именно они отказываются запускаться, возвращая ошибку «Authentication Failed» под номером 3.

Вот подробности.

Initramfs была собрана вручную, на базе busybox. Weston с приложением и либами были тоже скопированы (включая либы PAM и прочий мусор, без которого не взлетело). /dev статичен, с минимумом необходимых нод. /init представляет собой маленький sh-скрипт, который монтирует /proc, /run, /sys, запускает Weston и приложение, а потом монтирует основной корень и передаёт туда управление через switch_root(). Помимо этого, я монтирую в новую ФС существующий /run под именем /run_old, чтобы спасти сокет Wayland’a. Я не уверен, что последнее сделано правильно, но systemd в основной ФС затирает содержимое /run, а до сервера надо как-то достучаться, а этот костыль, вроде как, работает.

В основной ФС я линкую сокет wayland-0 и wayland-0.lock из /run_old в /run.

Всякий диагностический софт (LayerManagerControl, weston-info) работает и показывает инфу по поводу сервера, но всё, что пытается выводить картинку (и использует /dev/dri/card0), валится с вышеназванной ошибкой.

Вот кусочек strace клиентского приложения:

https://pastebin.com/1K3EDUhB

Видно, что оно цепляется корректно к /run/user/0/wayland-0, потом шлёт ioctl DRM_IOCTL_GET_MAGIC к /dev/dri/card0, дальше шлёт (?) magic в сокет сервера, который уже посылает приложение нафиг.

Со стороны сервера всё выглядит так:

https://pastebin.com/jkmeMzH7

Интересна строка:

[pid  1107] ioctl(14, DRM_IOCTL_AUTH_MAGIC, 0xfffff92b32d0) = -1 EACCES (Permission denied)

Хендл 14 указывает на (уже удалённый) /dev/dri/card0. Вот список всех открытых хендлов сервера:

https://pastebin.com/RTFNbEDW.

Единственная зацепка, которая у меня есть, это то, что switch_root() перед переключением на основную ФС рекурсиво удаляет все файлы в initramfs, включая /dev/dri/card0 (это видно выше по пометке «(deleted)»). И по факту новые приложения уже общаются с другим, динамически созданным devtmpfs. Но я не понимаю, как это должно влиять, так как хендл-то у нас всё равно жив, да и какая разница, какая у нас нода устройства и когда она примонтирована, если Major/Minor номера совпадают! В общем, зацепка так себе, и я даже не знаю, как её нормально проверить. Неактуально

Кстати, вот ещё грепнутый кусок трассировки сервера:

$ grep "AUTH_MAGIC" strace-wayland-log
[pid  1107] ioctl(14, DRM_IOCTL_AUTH_MAGIC, 0xfffff92b32d0) = 0
[pid  1107] ioctl(14, DRM_IOCTL_AUTH_MAGIC, 0xfffff92b32d0) = -1 EACCES (Permission denied)
[pid  1107] ioctl(14, DRM_IOCTL_AUTH_MAGIC, 0xfffff92b32d0) = -1 EACCES (Permission denied)
[pid  1107] ioctl(14, DRM_IOCTL_AUTH_MAGIC, 0xfffff92b32d0) = -1 EACCES (Permission denied)
[pid  1107] ioctl(14, DRM_IOCTL_AUTH_MAGIC, 0xfffff92b32d0) = -1 EACCES (Permission denied)
[pid  1107] ioctl(14, DRM_IOCTL_AUTH_MAGIC, 0xfffff92b32d0) = -1 EACCES (Permission denied)

Видно, что первое граф. приложение (из initramfs) авторизуется нормально, но не последующие.

Есть идеи, куда копать?

UPD: в общем, я монтирую devtmpfs вместо статического /dev, оно правильно переносится в основную rootfs, все хендлы живы, в /proc/x/FD никаких удалённых файлов. Тем не менее, продолжаем иметь ту же проблему

Предположу, что ответ придется искать в коде композитора, который отказывает новым клиентам, если девайс файл DRM ноды, на которой он запущен, уже удален. Но сначала стоит сделать дамп обмена по Wayland-протоколу между клиентом и композитором.

shatsky ★★ ()

Помимо этого, я монтирую в новую ФС существующий /run под именем /run_old, чтобы спасти сокет Wayland’a. Я не уверен, что последнее сделано правильно, но systemd в основной ФС затирает содержимое /run, а до сервера надо как-то достучаться, а этот костыль, вроде как, работает.

доки systemd утверждают, что

The initrd should mount /run/ as a tmpfs and pass it pre-mounted when jumping into the main system when executing systemd. The mount options should be mode=755,nodev,nosuid,strictatime

может, у тебя какие-то другие опции, и они ему не нравятся?

Lrrr ()
Ответ на: комментарий от Lrrr

Нет, опции именно эти самые. Прям скопипащенные. Но и без опций он точно так же себя вёл. Тут ещё сложность, что systemd монтирует /run/user/X как ещё одну tmpfs, а вырезать этот кусок уже стрёмно.

В systemd я тоже не сильно спец :). Мне казалось, что он должен был сохранять старое содержимое /run, но нет.

Vshmuk ()

Система, которую я разрабатываю, очень критична по времени запуска графической подсистемы, поэтому возникла идея запускать Weston и нужное приложение ещё на этапе initramfs.

странное решение - для чего вообще нужна initramfs, сколько по времени допустима загрузка ? Не проще ли первым загружать weston из основной корневой. Из своих экспериментов замечаю - дольше всего ядро инициализируется, вестон махом стартует, потом тормозят толстожопые Qt-приложения. На новых ядрах тормозит генератор случайных чисел из-за нехватки энтропии.

anonymous ()
Ответ на: комментарий от anonymous

сколько по времени допустима загрузка ?

Чем меньше, тем лучше. Сейчас - 2 секунды. 200 мс на копирование ядра, 200 - на копирование initramfs. Экран инициализируется на 0.7 от начала загрузки ядра, на 0.9 управление передаётся юзерспейсу. Там ещё много оптимизаций. Можно подвинуть инициализацию drm в ядре, перейти с arm на thumb для уменьшения времени копирования, попробовать стартовать с NOR Flash (если осилю написание линкерного скрипта для платформы)… Но это всё оффтопик, и к вопросу не имеет отношения

UPD:

Не проще ли первым загружать weston из основной корневой

Ну тут ведь как. Сначала инициализация блочного устройства. Потом монтирование (с проигрыванием журнала!), потом раскочегаривается systemd. Так что да, проще. Но дольше :). У нас получалось 1.6 секунды с момента старта.

Vshmuk ()
Последнее исправление: Vshmuk (всего исправлений: 3)
Ответ на: комментарий от Vshmuk

Если под дампом протокола имеется ввиду то, что вываливается при дебаге, то ничего нового не выводится.

Как так? Вот, например, со стороны клиента:

...
[4085642.926] wl_drm@22.device("/dev/dri/card0")
[4085642.987]  -> wl_drm@22.authenticate(19)
...
[4085644.492] wl_display@1.error(wl_drm@22, 0, "authenicate failed")
wl_drm@22: error 0: authenicate failed
...

(это при попытке запустить приложение из иксов под композитором, запущенном на другом tty, насколько я понимаю, вследствие того, что в этот момент нода карты недоступна для какой-то операции)

shatsky ★★ ()
Ответ на: комментарий от Vshmuk

Если ты про то, что сообщение об ошибке в целом повторяет сообщение, полученное от композитора по Wayland-протоколу - во всяком случае, можно зацепиться за это сообщение и искать в исходниках композитора (или libwayland-server) логику, которая приводит к его передаче.

shatsky ★★ ()
Ответ на: комментарий от Vshmuk

Сначала инициализация блочного устройства. Потом монтирование

посмотри про паралельную инициализацию драйверов в ядре

.probe_type = PROBE_PREFER_ASYNCHRONOUS,

«Driver asynchronous probing»

https://www.linuxplumbersconf.org/event/4/contributions/281/attachments/216/617/LPC_2019_kernel_fastboot_on_the_way.pdf

потом раскочегаривается systemd

пользуюсь busybox init, но что-то подсказывает systemd тоже можно сконфигурировать для быстрой загрузки

anonymous ()
Ответ на: комментарий от t184256

Можно поподробнее, со ссылками?

Как же задолбали кернел девелоперы или 'random: crng init done'

об этом все знают. Подробности - из-за уязвимости в криптографии отключили быстрый инит пула при инициализации ядра. Меня частично спасает

https://wiki.archlinux.org/index.php/Haveged

anonymous ()
Ответ на: комментарий от anonymous

На новых ядрах

4.14

А. Ты бы это, не вводил в заблуждение что ли. Где-то в районе 5.3 завезли jitterentropy, в 5.7 тоже че-то улучшали. Я очень сомневаюсь, что в сколь-либо новых ядрах у тебя будет entropy starvation при загрузке.

t184256 ★★★★★ ()
Ответ на: комментарий от anonymous

Камрад, спасибо за флаг, но монтирование ФС ограничено скоростью ввода-вывода в устройство и временем на инициализацию структур, и это время пусть и маленькое, но ненулевое.

По поводу systemd, мы довели время инициализации до 1.6 секунды. Это очень неплохо для systemd. Вот только в случае initramfs мы имеем 0.2 секунды оверхеда, но потом мгновенный старт.

ЗЫ. Я не очень понимаю, что ты мне хочешь сказать. Ты намекаешь на то сакральное «нинужно!»? Если тебя смущает выбранная стратегия оптимизации, то давай вообразим, что это, ну не знаю, лабораторная работа такая, и я не могу менять её условие. Может быть, это поможет закончить оффтопик.

Vshmuk ()
Ответ на: комментарий от shatsky

Там вообще мистика.

Я догуглился до файла «wayland-kms.c», ф-я kms_authenticate(). Оттуда - ф-я kms_auth_request() из «wayland-kms-auth.c», которая вызывает wl_kms_authenticate(), и эта функция не гуглится совсем! То ли это проприетарный кусок, то ли хрен знает

Vshmuk ()

Если уже на этапе initramfs должен запускаться Weston и какие-то приложения для него, и они должны жить до остановки системы, может быть, не делать switch_root вообще? Просто вынести минимально необходимую часть системы в initramfs, а с диска примонтировать всё остальное поверх этой системы через overlayfs.

А то ведь эта вся ситуация ненормальна: получается, в штатном режиме полсистемы должно продолжать работать, будучи удалённым из файловой системы. А если потом вдруг плагины PAM или ещё что-нибудь будет подгружаться через dlopen?

proud_anon ★★★★★ ()
Ответ на: комментарий от proud_anon

Там помимо этого запускается много всякого говна, и тащить всё в initramfs значит увеличивать время на копирование её в память. И так уже 8 мегабайт набралось. Поэтому сначала запускаем критичные задачи, потом остальные.

Твой второй абзац я не понял совсем.

Ты вторишь Анонимусу, обсуждая детали реализации. Попробуй представить, что эта задача существует в вакууме. Если ты спец по Wayland, буду рад услышать твои мысли касательно его поведения.

UPD: Прости, я перечитал твой пост. Ты имеешь ввиду не тащить всё в initramfs, а монтировать поверх. Да, это реально, и в параллельной вселенной я бы так и сделал (нарвавшись бы на другие грабли, пришёл бы сюда, а мне бы навтыкали, схрена ли я так всё усложнил). Но имеем то, что имеем, на чистом ext4.

Vshmuk ()
Последнее исправление: Vshmuk (всего исправлений: 2)
Ответ на: комментарий от Vshmuk

А если запустить Wayland с диска — вот просто перенести строчку, которая его запускает, после switch_root, чисто ради эксперимента — тогда всё работает или тоже нет?

proud_anon ★★★★★ ()
Ответ на: комментарий от proud_anon

Такое я не пробовал, ибо не было смысла. Хотелось как раз сэкономить время на монтирование.

Ты имеешь ввиду, после switch_root запускать Weston вместо systemd? :). Можно попробовать, но как тогда systemd запускать?

Vshmuk ()
Ответ на: комментарий от Vshmuk

Нет, зачем вместо? Форкнуть shell, запустить Weston, потом сделать exec systemd. Точно так же, как у тебя, как я понимаю, делается сейчас, только чтобы Weston запускался с диска, где, я так понимаю, лежит его копия.

Так можно будет понять, в чём конкретно проблема: в конфигурации системы или только в том, что у тебя Weston фактически должен продолжать работать после rm -rf /

proud_anon ★★★★★ ()

Пока что я вижу только возможность убивать сервер, запущенный из initramfs, и запускать уже новый штатными средствами. Но это очень некрасиво, да и интерфейс будет моргать

Vshmuk ()
Ответ на: комментарий от Vshmuk

Поверх пусть монтирует всё равно все системы которые обновлены с прошлого года дырявые и находятся уже как год под пристальным вниманием корпорации. Единственное спасение OS8.0 как и сказал анонимус

anonymous ()
Ответ на: комментарий от proud_anon

Имеешь ввиду, смонтировать новую rootfs и запустить из chroot? Ну можно попробовать, только надо будет очень аккуратно с окружением.

Только не троллинга ради, и вообще, спасибо за помощь, но: а что это нам даст? Ну запустится он, например. Но вот как узнать, чего ему не хватало? Сравнивать простыни вывода strace?

Vshmuk ()
Ответ на: комментарий от Vshmuk

но монтирование ФС ограничено скоростью ввода-вывода в устройство

initramfs видимо из вакуума грузится ? она на том же носителе

Вот только в случае initramfs мы имеем 0.2 секунды оверхеда, но потом мгновенный старт.

насколько я вижу с initramfs вы имеете мгновенный п..ец после switch_root

ЗЫ. Я не очень понимаю, что ты мне хочешь сказать

убери initramfs, загружай драйверы диска, фс, графической системы параллельно - сэкономишь намного больше чем потеряешь при монтировании корня на диске, сделай минимальный корневой раздел чтобы сэкономить на монтировании, если нужен старт сначала своей программы а потом systemd - перенеси свой скрипт init из initramfs в корень и укажи его ядру как init=/sbin/vasyaninit, а в конце его вместо switch_root - exec /sbin/init

ну не знаю, лабораторная работа такая

да пох что там у тебя - не тупи

anonymous ()
Ответ на: комментарий от proud_anon

Короче, я сделал немного по-другому. Weston запускается как обычно, из initramfs, но вместо systemd я передаю управление /bin/bash в основной ФС.

Далее, я монтирую /dev,/sys,/proc,/run,/run/user/0, линкую wayland-0 и wayland-0.lock, в общем, повторяю начальные шаги systemd.

И, о чудо! - клиент аутентифицируется!

Внимание, вопрос. Что такого гадкого делает systemd, что аутентификация становится невозможной?

Vshmuk ()
Ответ на: комментарий от Vshmuk

Ну да. Потом я киляю клиент, говорю exec /bin/init, логинюсь, запускаю то же самое и вижу тот же фейл. Я понимаю, что система у всех разная, но есть идеи, куда примерно смотреть внутри systemd? Что портится, учитывая, что и сервер и клиент запускаются от рута?

Vshmuk ()
Ответ на: комментарий от Vshmuk

См. https://github.com/systemd/systemd/commit/118ecf32425a590ea266b5c2b6de7962bb242356 и комменты к вызовам sd_drmdropmaster() в коде. Полагаю, нужно либо запихнуть в initramfs вот это все и запускать свое приложение после запуска logind, либо отключить logind (полагаю, если у тебя однопользовательская система без хотплага, должно быть несложно сделать все без него).

shatsky ★★ ()
Ответ на: комментарий от shatsky

Спасибо. В общем, я окончательно разобрался. Был виноват splash-screen, который незатейливо отбирал Мастера, но при этом на экран ничего не выводил.

logind я тоже отключал, не помогло, поэтому стал рыться дальше

Будет мне уроком изучать возможные ioctl. Топик закрываю.

Камрадам @shatsky и @proud_anon спасибо за подсказки.

Vshmuk ()
Последнее исправление: Vshmuk (всего исправлений: 1)