windows-drivers-rs - plataforma que hace posible desarrollar drivers de Windows en Rust
(github.com/microsoft)- Conjunto de crates de Rust que permite desarrollar Windows Drivers en Rust, con el objetivo de dar soporte a los modelos de desarrollo de drivers WDM y WDF
- Sus componentes principales son
wdk-buildpara la configuración de compilación de WDK,wdk-syspara bindings FFI directos de la API de WDK,wdkpara bindings seguros e idiomáticos de la API de WDK,wdk-panicpara el panic handler,wdk-allocpara soporte dealloc, ywdk-macros, un conjunto de macros que facilita el uso de los bindings directos dewdk-sys - Fue creado pensando en el soporte de drivers WDM, KMDF, UMDF y Win32 Services, e incluye soporte para todas las versiones de WDF incluidas en WDK 22H2 o posterior
- El crate publicado en
crates.ioactualmente solo soporta KMDF v1.33; los bindings para otras configuraciones pueden generarse clonandowindows-drivers-rsy modificando la configuración debuild.rsdewdk-sys - El flujo de uso consiste en crear un paquete Cargo
lib, agregar las dependenciaswdk-build,wdk,wdk-sys,wdk-alloc,wdk-panic, configurarcdylib, definir los metadatos de WDK, llamar awdk_build::configure_wdk_binary_build()enbuild.rs, agregarDriverEntryy ejecutarcargo make- Los drivers KMDF y WDM, que son crates de Kernel Mode, requieren la estrategia de panic
abort,#![no_std]y la configuración de un panic handler - Para usar el módulo
allocde la librería estándar de Rust, es necesario configurar el allocator globalwdk_alloc::WdkAllocator
- Los drivers KMDF y WDM, que son crates de Kernel Mode, requieren la estrategia de panic
- Los requisitos de compilación son
libclangparabindgen,cargo-makepara tareas posteriores a la compilación y un entorno WDK válido; la forma recomendada es entrar al developer prompt de eWDK cargo makecompila y empaqueta el driver de forma predeterminada, y como resultado genera un paquete de driver firmado y el archivoWDRLocalTestCert.cerentarget/<Cargo profile>/packageo dentro de la ruta de la arquitectura objetivo- Soporta pasar argumentos como
cargo make default --target <TARGET TRIPLE>,--release,--features <FEATURES>y+<TOOLCHAIN>; también se puede activar la verificación de firma de los archivos.sysy.catgenerados con la configuraciónWDK_BUILD_ENABLE_SIGNTOOL_VERIFY=true - La nueva extensión de Cargo
cargo-wdkestá en desarrollo en estado Preview para reemplazar acargo-makecomo herramienta recomendada para compilar drivers en Rust - Hay ejemplos mínimos de WDM, KMDF y UMDF en el directorio examples, y ejemplos de creación de drivers en Windows-rust-driver-samples
- Aún está en una fase temprana de desarrollo y todavía no se recomienda para uso en producción
3 comentarios
Opiniones de Hacker News
Para quienes no lo recuerden, Mark Russinovich, antes de tomar el puesto de su jefe y de sonar como candidato a próximo CEO de MSFT, dirigía una empresa de herramientas de software y consultoría sobre el kernel NT a la que acudían los ingenieros de Redmond para aprender desarrollo del kernel NT.
También descubrió funcionalidades de protección de archivos como el rootkit DRM de Sony y el rootkit de Symantec, y atrapó a Best Buy pirateando ERD Commander.
Ahora me da un poco de pena haber borrado LinkedIn en 2014. Era la cuenta donde todo el Valley y Mark estaban como contactos de primer grado, pero aun así hay libertad y agilidad en el relativo anonimato. ¿Cómo se llamaba esa canción de reggae de Desmond Dekker sobre lo inútil que es presumir cuánto hiciste, cuánto ganaste y a quién conoces?
Es bastante interesante que empresas de ese tamaño, aun teniendo una posición mucho más ventajosa con acceso al código fuente real y a los ingenieros, no logren hacer bien estas cosas por sí mismas. Estos terceros, al menos Levin, tuvieron que depender en gran medida de la ingeniería inversa.
https://newosxbook.com
Si pensamos que casi todas las empresas del mundo que usan Windows usan al menos una herramienta de Sysinternals, quizá la influencia de Sysinternals haya sido incluso mayor que la de Azure mismo.
Quizá por eso MSFT hizo un acquihire de Mark Russinovich y su equipo.
La impresión que me dejó su primer libro fue que ve el mundo de una forma extremadamente en blanco y negro.
Tuit original: https://twitter.com/markrussinovich/status/17057307039574058...
http://farside.link/twitter.com/markrussinovich/status/17057...
Bonito /s, pero esto no es muy Rust-like:
pub struct QueueContext {
buffer: PVOID,
length: usize,
timer: wdf::Timer,
current_request: WDFREQUEST,
current_status: NTSTATUS,
spin_lock: wdf::SpinLock,
}
Al escribir drivers en Rust para el kernel de Linux hay problemas similares, y lo mismo pasa con otros proyectos que interoperan con C.
Tipos como NTSTATUS tienen bastante documentación asociada. A diferencia de C o C++, en Rust no puedes simplemente asignar un valor entero a un valor enum. Se podría crear una clase wrapper para obligar a hacer cast cada vez, pero entonces la mitad del código terminaría siendo .into() y probablemente también introduciría overhead en el driver.
A simple vista, salvo quizá el void* para buffer, no están configurando ni modificando esos valores enum, solo leyéndolos. Para NTSTATUS parece que bastaría con un bloque match {}. WDFREQUEST es un handle, así que tampoco hay mucho que puedas hacer aparte de cambiarlo por otro handle del mismo tipo.
Timer y SpinLock sí se convirtieron en objetos al estilo Rust que envuelven internamente llamadas de biblioteca unsafe. Más allá de eso, no veo una forma clara de hacer este código más Rust-like sin una carga de rendimiento considerable.
¿Saben qué sería mejor? Escribir drivers de dispositivos en un lenguaje con gestión de memoria como C#.
Coincido con el criterio de Microsoft de que lo mejor es ejecutar menos código de fabricantes dentro del kernel, en vez de hacer que el kernel sea más accesible. C# no es adecuado para situaciones como “quiero acceder a cierto buffer, pero todavía no está paginado, y estoy dentro de un manejador de interrupciones”, así que hacer correr un garbage collector dentro del kernel sin bugs parece casi imposible.
Los drivers deben controlar la disponibilidad de memoria de forma muy estricta, porque pueden acceder a memoria en momentos en los que un page fault no es posible, por ejemplo dentro de un manejador de interrupciones. El lenguaje y el runtime de C# tendrían, como mínimo, que agregar capacidades para manejar esto explícitamente.
Creo que está un poco subestimado, así que agrego esto. Russinovich es una persona que ha creado muchísimos materiales y herramientas relacionadas con el kernel de Windows. Entre los desarrolladores que trabajan con el kernel de Windows (incluidos quienes crearon rootkits), probablemente no haya nadie que no haya estudiado viendo los materiales o la documentación de Russinovich.
Se venía diciendo que estaban reescribiendo el kernel de Windows en Rust, y por fin está saliendo el SDK de drivers. Parece que pronto saldrá un aviso diciendo que, a partir de 20XX, hagan los drivers en Rust.