Поделиться через


Обработка управления

Значительным источником проблем безопасности в драйверах является использование дескрипторов, передаваемых между компонентами пользовательского режима и режима ядра. В среде ядра существует ряд известных проблем с использованием дескрипторов, включая следующие:

  • Приложение, которое передает неправильный тип дескриптора драйверу ядра. Драйвер ядра может завершить работу, пытаясь использовать объект события там, где требуется файловый объект.

  • Приложение, которое передает дескриптор объекту, к которому у него нет необходимых прав доступа. Драйвер ядра может выполнять операцию, которая работает, так как вызов поступает из режима ядра, даже если у пользователя нет достаточных разрешений для этого.

  • Приложение, которое передает значение, которое не является допустимым дескриптором в адресном пространстве, но помечается как системный дескриптор для выполнения вредоносной операции в системе.

  • Программа, которая передает значение, не являющееся корректным дескриптором для объекта устройства (то есть дескриптор, не созданный этим драйвером).

Чтобы защититься от этих проблем, драйвер ядра должен быть особенно осторожным, чтобы убедиться, что дескрипторы, передаваемые ему, являются допустимыми. Самая безопасная политика — создавать необходимые дескрипторы в контексте драйвера. Эти дескрипторы, созданные драйверами ядра, должны указывать параметр 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.