Главная > Программирование > “Чужие” spinlock’и

“Чужие” spinlock’и

Иногда приходится делать хаки при написании драйверов, для того чтобы иметь возможность работать со какими-то недокументированными фичами ядра. И для того чтобы обеспечить синхронизацию, приходится использовать чужие объекты синхронизации. Это, как оказалось, вместо стабильности может наоборот привнести хаоса в код. Я хочу рассказать как я обжегся на спинлоках.

Для работы со спинлоком есть целый набор функций:

Before calling any support routine that requires access to a caller-supplied executive spin lock, a driver must call KeInitializeSpinLock to initialize the corresponding executive spin lock. Support routines that require an initialized executive spin lock include the following:

KeAcquireSpinLock and, subsequently, KeReleaseSpinLock
KeAcquireSpinLockAtDpcLevel and, subsequently, KeReleaseSpinLockFromDpcLevel
KeAcquireInStackQueuedSpinLock and, subsequently, KeReleaseInStackQueuedSpinLock
KeAcquireInStackQueuedSpinLockAtDpcLevel and, subsequently, KeReleaseInStackQueuedSpinLockFromDpcLevel

Но не пишется о том, что будет если вы используете разные функции на одном и том же спинлоке. Как показал опыт, ничего не будет, ровно до того момента пока не будет захвачен спинлок и начнется ожидание.
Например, ОС инициализирует спинлок через KeInitializeSpinLock, и дальше использует пару KeAcquireSpinLock/KeReleaseSpinLock для работы с ним. Тут вы своим кодом начинаете пытаться лочить его через KeAcquireInStackQueuedSpinLock/KeReleaseInStackQueuedSpinLock. И вот если лок был уже захвачен через KeAcquireSpinLock, KeAcquireInStackQueuedSpinLock рухнет, потому что KeAcquireSpinLock хранит в SPIN_LOCK просто DWORD равный 0 или 1. А KeAcquireInStackQueuedSpinLock хранит там указатель на очередь. Спинлок один и тот же данные абсолютно разные. Соответственно, в спинлоке, залоченом через KeAcquireSpinLock хранится число 1, а KeAcquireInStackQueuedSpinLock попытается прочитать по указателю = 1.

В моем случае все оказалось еще веселее, в одних версии ОС для этого спинлока использовались KeAcquireSpinLock/KeReleaseSpinLock, а в других KeAcquireInStackQueuedSpinLock/KeReleaseInStackQueuedSpinLock. Баг получился плавающим.

Вывод: при использовании чужих спинлоков обязательно проверьте какими функциями пользуется ОС.

Рубрики:Программирование Метки: ,

Добавить комментарий

Fill in your details below or click an icon to log in:

Логотип WordPress.com

You are commenting using your WordPress.com account. Log Out / Изменить )

Фотография Twitter

You are commenting using your Twitter account. Log Out / Изменить )

Фотография Facebook

You are commenting using your Facebook account. Log Out / Изменить )

Connecting to %s

Follow

Get every new post delivered to your Inbox.