VBoxGuest драйвер и VBoxCtrl управление #352
Open
lex_coder
wants to merge 7 commits from
lex_coder/kolibrios:VBoxGuest into main
pull from: lex_coder/kolibrios:VBoxGuest
merge into: KolibriOS:main
KolibriOS:main
KolibriOS:wolf3d-launcher
KolibriOS:kterm-upload
KolibriOS:app/socketdbg_fix1
KolibriOS:hdaudio-add-ring-buffer-for-unsolicied-events
KolibriOS:workflow-fuse
KolibriOS:add-license-file-header-to-guide
KolibriOS:blocks-add-models
KolibriOS:shell-improve-cpuid
KolibriOS:rewrite_ide_drv
KolibriOS:qrcodegen
KolibriOS:ci/update
KolibriOS:laser-tank-fix-win-height
KolibriOS:improvement/commit-and-branch-styles
KolibriOS:docs/libs
Dismiss Review
Are you sure you want to dismiss this review?
Labels
Clear labels
C
Category/Applications
Category/Drivers
Category/General
Category/Kernel
Category/Libraries
Eolite
FASM
FS
GSoC
HardwareTested
HLL
Influence/Settings
Influence/Text/TYPO
IRCC
Kernel
Pay for the code
This issue in GSoC program
Kind
Breaking
Breaking change that won't be backward compatible
Kind
Bug
Something is not working
Kind
Build
Kind
Documentation
Documentation changes
Kind
Enhancement
Improve existing functionality
Kind
Feature
New functionality
Kind
Security
This is security issue
Kind
Testing
Issue or pull request related to testing
Paid task
PR
Conflicts
PR conflicts with main
PR
Dependent
This PR is dependent on another PR
Priority
Critical
The priority is critical
Priority
High
The priority is high
Priority
Low
The priority is low
Priority
Medium
The priority is medium
PR
Ready to merge
Pull request is ready for merge
PR
Request changes
Changes requested in pull request
PR
Review required
Reviewed
Confirmed
Issue has been confirmed
Reviewed
Duplicate
This issue or pull request already exists
Reviewed
Invalid
Invalid issue
Reviewed
Won't Fix
This issue won't be fixed
Status
Abandoned
Somebody has started to work on this but abandoned work
Status
Blocked
Something is blocking this issue or pull request
Status
Need More Info
Feedback is required to reproduce issue or to continue work
Milestone
No items
No Milestone
Projects
Clear projects
No project
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: KolibriOS/kolibrios#352
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "lex_coder/kolibrios:VBoxGuest"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Реализовано:
Mouse - абсолютное позиционирование мыши
Display - синхронизация разрешения экрана
Clipboard - общий буфер обмена
Shared Folders - общие папки
Heartbeat - мониторинг состояния гостя
Guest Properties - свойства гостевой машины
Timesync - синхронизация времени (отключена)
Seamless - бесшовный режим окон (отключен)
и известное количество багов
@lex_coder Hi!
I see that you have done a titanic job and your solution is extremely structured. This is worthy of all praise and respect.
What problems have I noticed:
vboxctrl всё же следует перенести из директории drivers в programs/system например, так как это пользовательское приложение и не обязательная часть драйвера
to fix the build, add the "-m 65536" argument to the Tupfile.lua
@@ -0,0 +69,4 @@.output dd ?.out_size dd ?.size = $end virtualThe macros.inc file includes the connection of the struct.inc file, which allows you to declare this structure through the "struct" macro.
Изменил
@dunkaist please check the file system driver code
@@ -0,0 +8,4 @@vbox_irq_count dd 0; vbox_irq_handler - Top-half IRQ handlerproc vbox_irq_handler stdcallincorrect function declaration
int32_t __cdecl irq_handler(uint32_t userdata);Внеси правку
@@ -0,0 +67,4 @@; Validate IRQ (must be 0-15)cmp eax, 16jae .invalid_irqIs this check really necessary?
Убрал)
@@ -0,0 +17,4 @@out dx, eax; Spin-wait (~1ms): gives the host time to process the requestmov ecx, 1000000немного похоже на костыль
Да, убрал
@@ -0,0 +56,4 @@cmp dword [clip_state.listen_pkt_virt], 0jne .pkt_readyinvoke KernelAlloc, 4096instead of this magic number, it is better to use the PAGE_SIZE constant.
Заменил везде на PAGE_SIZE
@@ -0,0 +58,4 @@je .already_connected; --- Allocate buffers ---invoke KernelAlloc, 4096 ; gp_enum_buf (page-aligned for HGCM)instead of this magic number, it is better to use the PAGE_SIZE constant.
@@ -0,0 +42,4 @@jae .error; Allocate memory for SF_FOLDERinvoke KernelAlloc, 4096instead of this magic number, it is better to use the PAGE_SIZE constant.
@@ -0,0 +198,4 @@je .already_connected; --- Allocate init buffers ---invoke KernelAlloc, 4096 ; sf_packetinstead of this magic number, it is better to use the PAGE_SIZE constant.
@@ -0,0 +22,4 @@DEBUGF 2, "[VBoxGuest] [VMMDev] Init packets (dynamic)\n"; --- Allocate page ---invoke KernelAlloc, 4096instead of this magic number, it is better to use the PAGE_SIZE constant
The reason is described in the comments above.
Sounds amazing, I'll test it soon.
Any particular reason virtio network was skipped? Is it part of a separate logical module?
VirtIO isn't included in the VirtualBox Guest Additions because the Guest Additions aren't related to VirtIO. The Guest Additions are VBoxClipBoard, VBoxSF, VBoxMouse and other
Я ревьюшнул нейронкой этот ПР, и нашёл несколько проблем.
Автор подтвердил их актуальность и сказал, что займётся исправлением в ближайшее время.
Поэтому на всякий случай оставляю этот ревью здесь.
🔴 Критические - память и безопасность
1. IOCTL: указатели
input/outputот пользователя не валидируются → произвольная запись/чтение в ring0drivers/vboxguest/sys/ioctl.inc:51-54и все обработчики clipboard.Ядро (
srv_handlerEx) проверяет только сам IOCTL-структуру (< OS_BASE), но не указателиinput/outputвнутри неё — они приходят от недоверенного приложения. Драйвер разыменовывает их без проверки диапазона:То же в
svc_enable(чтение[input]),clip_ioctl_read/write/status. Проверяются только размеры, не принадлежность памяти вызывающему. Это классический примитив записи/чтения в ядре для любого процесса, открывшего сервис.Исправление: проверять каждый
input/outputвместе сinp_size/out_sizeна принадлежность user space (без переполнения) до разыменования.2. Длина имени файла от хоста копируется без ограничения → переполнение буфера
drivers/vboxguest/services/shared_folders/vboxsf.inc:732-735+drivers/vboxguest/common/utils.inc:7-133sf_utf8_to_cp866не принимает размер приёмника и не проверяет границуdst— пишет по байту на символ плюс терминатор. Имя длиннее поля BDFE переполняет буфер вызывающего VFS. Антипаттерн «данные хоста как длина копирования».Исправление: добавить параметр
dst_lenвsf_utf8_to_cp866и обрезатьecx(например, ≤255) до вызова. Тот же отсутствующий клэмпu16Lengthот хоста — вshared_folders.inc(null-запись по индексу от хоста).3. HGCM page-list буфер физически не непрерывен, но отправляется хосту как единый >4 КБ запрос
drivers/vboxguest/hgcm/hgcm.inc:60-66,drivers/vboxguest/hgcm/call.inc:282-303HGCM_PL_BUF_SIZE(~8620 байт → 3 страницы) выделяется черезKernelAlloc. По исходнику ядраkernel/trunk/core/heap.inc:493-505: для 3 страниц (pages_count>>3 == 0) все страницы выделяются поодиночке черезalloc_page— виртуально непрерывны, но физически разбросаны. Хосту передаётся только физ. адрес начала (hgcm.inc:131-139), и он читает весь запрос (header.sizeбайт) как непрерывный блок. Проверка.buffer_overflowразрешаетdata_tailдо ~8620 байт, т.е. запрос может выходить за первую страницу. Тогда хост читает страницу 2 по неверному физ. адресу → массивaPages[]указывает на чужие фреймы → повреждение памяти.Латентно: проявляется на крупных передачах (page-list, занимающий >4096 байт, ≈ буфер >1.8 МБ за один HGCM-вызов).
Исправление: выделять PL-буфер физически непрерывно (через
alloc_pages/CreateRingBuffer-эквивалент) либо гарантировать, что запрос не пересекает первую физ. страницу.4. Константы full-state-protocol мыши коллизируют → ломаются кнопки и колесо
drivers/vboxguest/data/mouse/constants.inc:18-25В реальном VBox это разные биты (
0x400/0x800).mouse.inc:69проверяет& 0x100— но этоHOST_WANTS_ABSOLUTE, который при включённой интеграции мыши выставлен почти всегда → драйвер всегда уходит в extended-режим и отключает PS/2 IRQ12 (mouse.inc:83). На хостах без full-state-протокола кнопки и колесо молча перестают работать.Исправление: задать корректные значения битов VBox и сделать все четыре
equразличными.5. IRQ-обработчик не отсоединяется при выгрузке → use-after-free
drivers/vboxguest/sys/shutdown.inc:23-24call vbox_irq_detachзакомментирован, а самой процедуры/DetachIntHandlerв дереве нет. НаDRV_EXITосвобождаются HGCM/VMMDev-пакеты (shutdown.inc:37-41), пока ISR ещё подключён. Собственный комментарий кода (стр. 21-22) требует detach до освобождения буферов — но код выключен. Прерывание после освобождения = UAF в ядре. (Срабатывает только при реальной выгрузке драйвера.)Исправление: реализовать detach (
DetachIntHandler+ маскирование IRQ устройства) и вызвать его до освобождения пакетов.6.
vboxctrl:rhc_bufsizeне обновляется после реаллокации → зависание при буфере обмена >64 КБprograms/system/vboxctrl/vboxctrl.asm:508-570При переполнении утилита аллоцирует больший буфер (
rhc_target_size) и прыгает на.rhc_retry, ноout_sizeпересчитывается изrhc_bufsize, которое осталосьMAX_CLIP_BUF(64 КБ). Драйвер снова возвращает overflow → реаллокация → повтор… бесконечный цикл. Поскольку это вызывается в обработчике опроса буфера обмена, утилита (а с ней и интеграция clipboard) зависает на любом содержимом >64 КБ.Исправление: в
.rhc_alloc_okдобавитьmov eax,[rhc_target_size]; mov [rhc_bufsize],eaxпередjmp .rhc_retry.🟠 Средние
7. Защита от реентерабельности HGCM отключена + общие одиночные буферы → гонка
drivers/vboxguest/hgcm/call.inc:284,377,382,386Все
lock bts [hgcm_pl_busy]и сбросы закомментированы,.busyнедостижим.hgcm_call32_pagelistиспользует один общийhgcm_call_pl_virt; connect/disconnect — тоже общая страница. Clipboard работает в отдельном потоке-слушателе, shared_folders/guest_props — в контексте VFS; одновременные HGCM-вызовы реальны и затрут пакеты друг друга (окно велико из-за долгого ожидания, см. п. 11).Исправление: вернуть флаг занятости (со сбросом на всех выходах, включая
.bad/.buffer_overflow/.send_failed) либо использовать буферы на вызов / блокировку.8. Несогласованные границы массива shared folders → латентное переполнение
drivers/vboxguest/services/shared_folders/shared_folders.inc:41,62-63,drivers/vboxguest/data/shared_folders/structs.inc:82Массив
folders rd SHFL_MAX_FOLDERS(=10 вconfig.inc), ноvboxsf_add_folderпроверяет лимит против литерала32и пишет[folders + ecx*4]дляecxдо 31 → запись за пределы массива (наcount,disk_handleи дальше), если вadd_folderдойдёт >10 папок. Безопасность сейчас держится только на клэмпе на стороне вызова — defense-in-depth нарушен.Исправление: заменить
32наSHFL_MAX_FOLDERSи согласовать с размером массива.9.
sys_init: нет отката при частичной инициализации; утечка MMIOdrivers/vboxguest/sys/init.inc:68-69,drivers/vboxguest/core/mmio.inc:30-32Все ветки
.failделают голыйretбезunmap/KernelFree/остановки таймера.mmio_map_vmmdev.version_check_failedвозвращается, не размапивmmio_virt. Если инициализация упала послеvmmdev_irq_install, IRQ остаётся подключённым (усугубляет п. 5).Исправление: добавить раскрутку в обратном порядке на каждой метке отказа; сделать shutdown идемпотентным.
10.
clip_ioctl_write/clip_ioctl_read: данные хоста/пользователя без верхнего пределаdrivers/vboxguest/services/clipboard/clipboard_listener.inc:407-427,clipboard_listener.inc:456-489data_size(изinp_size) иactual_size(от хоста) принимаются без разумного максимума и идут вKernelAlloc. Само по себе переполнение при округлении вверх безопасно (даётKernelAlloc(0), который корректно падает — см. ниже), но отсутствие верхней границы и проверки источника[input](см. п. 1) стоит закрыть.11. HGCM async-ожидание — busy-poll, игнорирующий IRQ-событие
drivers/vboxguest/hgcm/async.inc:19-39Ожидание крутит
pause/loopпо флагуVBOX_HGCM_REQ_DONE, не уступая планировщику и не дожидаясь событияRaiseEvent, которое поднимает IRQ-обработчик (irq.inc:50-81) — механизм пробуждения по факту не используется. KolibriOS вытесняющая, так что это не зависание, но напрасный расход CPU и риск ложного таймаута под нагрузкой.Исправление: ждать на
hgcm_wakeup_eventс перепроверкой флага (паттерн condition variable), убрать busy-loop.🟡 Мелочи/Стиль
__DEBUG__ = 1вconfig.inc:31и вvboxctrl— лог в debug-board каждую секунду. Для релиза0.VERR_TIMEOUTиVERR_NOT_FOUNDоба= -78(errors.inc:27,40) — различить нельзя. Сверить с upstreamerr.h.jnzвместоjs(seamless.inc) — положительные предупрежденияVINF_*трактуются как ошибки.GetTimerTicks(TOCTOU) и неинициализированныйlast_send_time— первый тик срабатывает не от момента init.hgcm_init(hgcm.inc:113-121) пропагирует ошибку только потому, что промежуточныйDEBUGFотключён (уровень 0). Хрупко: при включении__DEBUG_HGCM__eaxбудет затёрт. Стоит явноtest eax,eax / jnz.service_procбезuses ebx esi edi(ioctl.inc:28) — для пути syscall 68.17 безопасно (ядро восстанавливает кадр), но расходится с конвенцией.core/pci.inc) — для фиксированного VMMDev работает, но хрупко.🔵 Требует подтверждения автором
core/irq.inc:14-24): обработчик читает порт+VMMDEV_PORT_OFF_REQUEST_FASTдля получения и подтверждения событий, ноVMMDEV_HF_FAST_IRQ_ACKнигде с хостом не согласуется. Если хост не активировал fast-ACK, прерывание может не сниматься (риск IRQ-шторма в ring0). Дополнительно вызывает сомнениеout dx, eax(стр. 24), записывающий маску событий в порт запроса. Нужно сверить с поведением VMMDev конкретных версий VBox.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.