3 puntos por GN⁺ 2023-09-25 | 3 comentarios | Compartir por WhatsApp
  • 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-build para la configuración de compilación de WDK, wdk-sys para bindings FFI directos de la API de WDK, wdk para bindings seguros e idiomáticos de la API de WDK, wdk-panic para el panic handler, wdk-alloc para soporte de alloc, y wdk-macros, un conjunto de macros que facilita el uso de los bindings directos de wdk-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.io actualmente solo soporta KMDF v1.33; los bindings para otras configuraciones pueden generarse clonando windows-drivers-rs y modificando la configuración de build.rs de wdk-sys
  • El flujo de uso consiste en crear un paquete Cargo lib, agregar las dependencias wdk-build, wdk, wdk-sys, wdk-alloc, wdk-panic, configurar cdylib, definir los metadatos de WDK, llamar a wdk_build::configure_wdk_binary_build() en build.rs, agregar DriverEntry y ejecutar cargo 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 alloc de la librería estándar de Rust, es necesario configurar el allocator global wdk_alloc::WdkAllocator
  • Los requisitos de compilación son libclang para bindgen, cargo-make para tareas posteriores a la compilación y un entorno WDK válido; la forma recomendada es entrar al developer prompt de eWDK
  • cargo make compila y empaqueta el driver de forma predeterminada, y como resultado genera un paquete de driver firmado y el archivo WDRLocalTestCert.cer en target/<Cargo profile>/package o 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 .sys y .cat generados con la configuración WDK_BUILD_ENABLE_SIGNTOOL_VERIFY=true
  • La nueva extensión de Cargo cargo-wdk está en desarrollo en estado Preview para reemplazar a cargo-make como 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

 
GN⁺ 2023-09-25
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?

    • Creo que Apple hizo algo parecido. La documentación interna de Apple no era gran cosa comparada con los libros de Jonathan Levin, así que dicen que Apple compraba esos libros con frecuencia para sus ingenieros de OS.
      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
    • No se puede hablar de él sin mencionar Sysinternals. Dependo de ese conjunto de herramientas en mi trabajo diario.
      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.
    • Las herramientas de Sysinternals deberían venir incluidas por defecto en toda instalación de Windows. En mi entorno son imprescindibles, y cuando arreglo o depuro la computadora de un amigo se extrañan muchísimo si no están.
      Quizá por eso MSFT hizo un acquihire de Mark Russinovich y su equipo.
    • Es un buen programador, pero después de leer sus libros no me parece que vaya a ser un buen CEO.
      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...

  • 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,
    }

    • La mayoría de esas cosas al final apuntan a tipos enteros de FFI. Así es como se usa la API de drivers de Windows.
      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.
    • Para eliminar eso, creo que habría que reescribirlo todo.
  • ¿Saben qué sería mejor? Escribir drivers de dispositivos en un lenguaje con gestión de memoria como C#.

    • Microsoft está empujando cada vez más código al espacio de usuario. Entre los cambios recientes, exige a los fabricantes de impresoras que usen apps de impresora UWP, no drivers, cuando quieran agregar funciones personalizadas a una impresora. Esas apps normalmente se escriben en lenguajes 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.
    • No sé si realmente sería mejor. No tengo experiencia desarrollando drivers, pero los drivers de dispositivos son componentes centrales de bajo nivel de un sistema operativo en funcionamiento, así que no parecen encajar bien con un modelo en el que la recolección de basura interrumpe la ejecución según su propio calendario.
    • No quiero que el mouse se trabe porque el driver se detuvo para ejecutar el garbage collector.
    • Microsoft ya lo intentó y fracasó estrepitosamente. Creo que nunca explicaron el motivo, pero supongo que en el hardware de principios de los 2000 habría habido demasiadas pausas por la recolección de basura.
    • Incluso con C++ es muy difícil escribir drivers de dispositivos y a la vez conservar la capacidad de crear drivers de kernel paginables.
      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.
 
bungker 2023-11-30

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.

 
botplaysdice 2023-12-01

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.