Обработка управления
Значительным источником проблем безопасности в драйверах является использование дескрипторов, передаваемых между компонентами пользовательского режима и режима ядра. Существует ряд известных проблем с обработкой использования в среде ядра, включая следующие:
Приложение, которое передает неправильный тип дескриптора драйверу ядра. Драйвер ядра может завершить работу, пытаясь использовать объект события, в котором требуется файловый объект.
Приложение, которое передает дескриптор объекту, для которого у него нет необходимого доступа. Драйвер ядра может выполнять операцию, которая работает, так как вызов поступает из режима ядра, даже если у пользователя нет достаточных разрешений для этого.
Приложение, которое передает значение, которое не является допустимым дескриптором в адресном пространстве, но помечается как системный дескриптор для выполнения вредоносной операции в системе.
Приложение, которое передает значение, которое не является подходящим дескриптором для объекта устройства (дескриптор, который этот драйвер не создавал).
Чтобы защититься от этих проблем, драйвер ядра должен быть особенно осторожным, чтобы убедиться, что дескриптор, переданный в него, является допустимым. Самая безопасная политика — создать все необходимые дескрипторы в контексте драйвера. Эти дескрипторы, созданные драйверами ядра, должны указывать параметр OBJ_KERNEL_HANDLE, который создаст дескриптор допустимый в произвольном контексте процесса и один из которых можно получить доступ только из вызывающего объекта в режиме ядра.
Для драйверов, использующих дескрипторы, созданные программой приложения, использование этих дескрипторов должно выполняться с крайней осторожностью:
Рекомендуется преобразовать дескриптор в указатель объекта, вызвав ObReferenceObjectByHandle, указав правильный AccessMode (обычно из Irp-RequestorMode>), DesiredAccess и ObjectType, например IoFileObjectType или ExEventObjectType.
Если дескриптор должен использоваться непосредственно в вызове, рекомендуется использовать варианты функций NT, а не варианты функций Zw. Это приведет к применению параметра проверка и обработке проверки операционной системой, так как предыдущий режим будет UserMode и, следовательно, ненадежным. Обратите внимание, что параметры, передаваемые в функции Nt, которые являются указателями, могут завершиться ошибкой, если предыдущий режим — UserMode. Подпрограммы Nt и Zw возвращают параметр IoStatusBlock с сведениями об ошибке, которые следует проверка для ошибок.
Ошибки должны быть соответствующим образом захвачены, а также использовать __try и __except по мере необходимости. Многие из диспетчера кэша (Cc), диспетчер памяти (мм) и подпрограммы библиотеки среды выполнения файловой системы (FsRtl) вызывают исключение при возникновении ошибки.
Ни один драйвер никогда не должен полагаться на дескриптора или параметры, передаваемые из приложения пользовательского режима, не принимая соответствующие меры предосторожности.
Обратите внимание, что если для открытия файла используется вариант Nt, для закрытия файла также необходимо использовать вариант Nt.