La informática ha ido evolucionado bajo el zumbido y el calor de los tubos de vacío del ENIAC - incluso la MANIAC de Von Neumann - el clic metálico de los relés de IBM, la revolución del transistor y la salvaje miniaturización de los chips CMOS. Cada salto iba comprimiendo la potencia poco a poco, primero era una habitación entera hasta finalmente caber en la palma de la mano. Pero hoy, estamos llevando al límite la Ley de Moore y exprimir cada nanómetro del silicio, volvemos a sentir que se acerca otro salto, uno grande y no, no hablamos de la computación cuántica (que ojo, llegará y que también tiene su versión fotónica cuántica pero eso es otro tema).
Figura 1: Los Chips Fotónicos de LightMatter revolucionan
Pero volviendo al tema de hoy, en mitad de la revolución de la Inteligencia Artificial y la computación cuántica, entra en escena la computación fotónica, un relevo sorpresa que no utiliza electrones, sino haces de luz procesar. Lightmatter acaba construir el primer procesador fotónico que ejecuta modelos complejos de IA y con la misma fidelidad que una GPU de 32 bits. Y no es un prototipo con cables colgando en un laboratorio oscuro en un sótano, es hardware ya montado en rack, terminado, funcional, con varios chips fotónicos individuales y más de un millón de componentes ópticos, listo para enchufarse.
Igual que el transistor envió al tubo de vacío al museo, los fotones pueden sacarnos del atasco actual. Puede que aún convivan con el silicio, como los motores eléctricos con los de combustión, pero el mensaje está claro: estamos delante del siguiente gran salto, el nuevo transistor.
¿Por qué es tan grande este salto?
Las barreras actuales de la microelectrónica no están en la lógica, sino en el tremendo coste que paga cada bit para moverse: la resistencia capacitancia de los interconectores y la energía que se evapora como calor al cambiar cargas a varios GHz. A cada nueva capa litográfica, los transistores mejoran muy poco mientras las líneas de cobre apenas se hacen más pequeñas, y el coste energético por trasladar datos entre memoria y cómputo ya triplica al de la operación matemática en sí.
La computación fotónica se centra justo en ese cuello de botella: dentro de una guía de onda, los fotones viajan sin cargas que cargar o descargar y admiten multiplexación por longitud de onda (WDM) (algo así como varios “colores” circulando simultáneamente), lo que dispara el ancho de banda y baja la energía por bit a niveles de femto julios (una milbillonésima parte de un julio).
Dentro del Procesador de Lightmatter: Claves Técnicas y Potencial
En el núcleo de este chip hay seis procesadores apilados en 3D que integran 50.000 millones de transistores CMOS y un millón de componentes ópticos: los photonic tensor cores, arreglos de los moduladores Mach Zehnder que antes hemos mencionado, que ejecutan multiplicaciones analógicas a la velocidad de la luz y en decenas de longitudes de onda simultáneas gracias al WDM, mientras un control digital orquesta buffers, redes en chip y conversiones AD/DA.
Para mantener la precisión de redes como ResNet 50, BERT o modelos de RL sin reentrenar, el sistema introduce el formato Adaptive Block Floating Point (ABFP), que comparte exponente por bloques y limita cada mantisa a 10–12 bits, complementado con ganancia analógica programable que amplifica la señal antes del muestreo y captura los bits más débiles sin aumantar el consumo del ADC (Analog to Digital Converter).
Todo esto cabe en un paquete tipo PCIe que ofrece 65,5 TOPS con apenas 78 W eléctricos y 1,6 W ópticos (~0,85 pJ/op), se programa desde PyTorch o TensorFlow sin cambios de modelo (es decir, los actuales sirven) y, conectado mediante la interconexión fotónica Passage, escala a racks enteros donde la luz ya no solo mueve datos también los procesa, multiplicando el ancho de banda, recortando la latencia. Creo que, llegados a este punto, tenemos más claro que estamos entrando en una era post transistor.
Impacto y futuro de la tecnología
Pero pensemos por un momento lo siguiente. Estamos hablando de una tecnología que es básicamente un rayo de luz que se convierte en cálculos y una tarjeta PCIe que es el equivalente óptico de un pequeño datacenter. Los nuevos ingenieros/as de esta tecnología tendrán que jugar con rayos de luz multicolor, los desarrolladores/as crearán programas que se compilarán en ajustes de fases y longitudes de onda, y una nueva ciberseguridad (ojo a esto) decidirá cómo proteger un recurso que viaja literalmente a la velocidad de la luz.
Y este es el verdadero impacto: si hoy aprendemos a procesar información con un coste significativo, mañana podríamos equipar cada marcapasos, cada sensor IoT y cada IA local con inteligencia de alto nivel, sin el desperdicio brutal actual de los megavatios ni al silicio cada vez más caro y limitado.
Este no es sólo el siguiente paso una la curva de rendimiento. Hablamos de imaginar aplicaciones que ya no dependen de los viejos límites térmicos, a diseñar soluciones que iluminen (nunca mejor dicho) las zonas oscuras aún no exploradas de la tecnología mientras esperamos la computación cuántica.
Figura 10: Cómo montar tu propio servidor de Inteligencia Artificial.
Apple Silicon, Ollama, LMStudio & Pinockio
Además de las alternativas descritas, tenemos también la opción Apple Silicon, que también utilizo ya que tengo un Macbook Pro M1 Max con 1TB de disco duro y 32GB de RAM - el jefe tiene un M3 - Con esta configuración puedo levantar modelos de 7B (y algunos de más billions) a una velocidad más que decente, aunque teniendo ya la generación M4 se empieza a notar. Ahora con los M4 la potencia y la velocidad como podéis imaginar es mayor, aunque como pasa siempre en Apple, tenemos que pagarla (a veces a precio de oro).
Una configuración mínima para poder ejecutar modelos decentes sería un Macbook Pro M4 con 32GB de RAM y 1TB de disco duro. Esta configuración ronda los 3.000€ pero vas a tener el rendimiento “parecido” (sólo se equipara si tienes el M4 Max) al de una 4090 a la hora de entrenar y ejecutar modelos LLMs (no hablo de juegos ni FPS). Pero recuerda el precio de una 4090 … los Silicon de Apple se han convertido en una buena opción. Pero eso sí, en principio siempre serán más rápidas las NVIDIA pero a mayor consumo energético.
Otra configuración que se está poniendo de moda es usar los Mac mini que rondan los 800€ y crear con ellos clústeres a través del puerto Thunderbolt o de red. Esto nos permite poner por ejemplo 3 Mac mini digamos 16GB por menos de 2.500€ y conectarlos entre ellos para sumar su potencia. Ojo con esto que no es del todo así (hay más factores que influyen en la velocidad que ahora veremos), no tendremos 48GB de VRAM pero sí más o menos unos 30GB. Con la opción de poder añadir nodos bajo demanda de manera muy sencilla. En este vídeo tienes un ejemplo completo de cómo se pueden conectar usando exo que te permite unir cualquier ordenador Mac Silicon en formato clúster.
Un pequeño disclaimer. No sólo es la VRAM, también tenemos que tener en cuenta parámetros tan opuestos en su naturaleza como por la velocidad el bus de memoria de los Silicon, el contexto del LLM o la cuantización. Pero sí podemos hacernos una idea del consumo de VRAM usando por ejemplo esta fórmula en este artículo o usar alguna calculadora online como esta para modelos de HuggingFace. Por ejemplo, usando la fórmula del artículo anterior, para levantar un modelo Llama 2 a 70B con cuantización de 4 bits necesitaríamos 42GB de VRAM (en principio y según esta fórmula, yo creo que con menos se podría).
Bien, pues ya tenemos nuestro servidor preparado, es hora de instalar el software necesario para ejecutar todo tipo de modelos o de utilidades que usen la IA. Se me olvidaba algo importante … el consumo eléctrico. En esto los Mac Silicon están a años luz de las gráficas NVidia. Estas requieren fuentes de alimentación mínimo de 750W para gráficas como la 4070 y de 1000W o más para las 4090 mientras que los mac consumen mucha menos electricidad.
Los tokens por segundo marcan la usabilidad
La velocidad de generación medida en tokens por segundo es el factor que define el rendimiento y usabilidad de los modelos locales de LLMs. Los tokens ya sabemos que representan las unidades mínimas en las que se descompone el texto (palabras, sílabas o incluso caracteres), y la rapidez con la que un modelo puede procesar y generar estas unidades determina su eficiencia en tareas como la creación de texto, la traducción o el análisis de datos que hagamos.
Esta velocidad depende de varios factores: la arquitectura del modelo (por ejemplo, cuántos parámetros tiene), la capacidad de cómputo (potencia de la GPU o CPU utilizada) y la optimización del software (uso de librerías como CUDA, cuDNN o frameworks optimizados como Hugging Face Transformers). En nuestro caso, para entornos locales, la limitación de recursos suele ser más estricta que en soluciones en la nube por lo que es importante justar tanto el hardware como el software para maximizar el número de tokens por segundo.
Para optimizar los tokens por segundo en un modelo local LLM, se pueden implementar diversas estrategias enfocadas en hardware y software. Por ejemplo, utilizar una buena GPU compatible con librerías como CUDA y cuDNN nos permite acelerar los cálculos matriciales de la arquitectura Transformer, optimizando la inferencia.
A nivel de software, podemos aplicar técnicas como la cuantización que ya hemos mencionado antes, que reduce la precisión de los parámetros del modelo (por ejemplo, de FP32 a INT8) sin sacrificar significativamente el rendimiento, logrando una mayor velocidad de procesamiento. Por otro lado, el uso de batching eficiente y librerías optimizadas como PyTorch con operadores adaptados a hardware específico, o herramientas como TensorRT, permite ejecutar el modelo de forma más rápida y con un menor consumo de recursos.
Por último, reducir el tamaño del modelo mediante técnicas como pruning o utilizar modelos más ligeros, como los LLMs optimizados para dispositivos locales (por ejemplo, LLaMA 7B o GPTQ), también ayuda obtener una aceptable generación de tokens por segundo en un hardware limitado.
Software a utilizar: Ollama, LMStudio & Pinockio
Lo que voy os a contar ahora es independiente de si tienes un GNU/Linux, Windows o Mac Silicon, todos sirven en las tres plataformas. Voy a centrarme solamente en tres que creo que son indispensables y sobre todo sencillas de utilizar. Vamos a empezar con dos que serán el motor principal de nuestro servidor: Ollama y LMStudio.
Ollama es una plataforma pensada para que puedas ejecutar modelos de lenguaje directamente en tu máquina de una manera sencilla y eficiente. Es como el “plug and play” de los LLMs: descargas, configuras y en unos minutos tienes funcionando modelos como LLaMA, Mistral o Vicuna. Su gran ventaja es que está optimizado para funcionar en hardware local, ya sea un Mac con Apple Silicon o una GPUNVIDIA decente, lo que te permite usar modelos bastante potentes sin depender de la nube ni complicarte con instalaciones infernales. Además, la biblioteca de modelos de Ollama ya viene ajustada y lista para usar, lo que te ahorra tiempo y dolores de cabeza.
Por otro lado, LMStudio tiene otro enfoque porque está pensado más para el fine-tuning y personalización de modelos, RAG, etcétera. Aquí no solo ejecutas un LLM, sino que lo adaptas a lo que necesitas: puedes entrenar tu propio modelo con datasets específicos y ajustar los parámetros para obtener resultados optimizados y personalizados. Es ideal si tienes un proyecto concreto y necesitas que el modelo “hable” o “sepa” del contexto que quieras.
Mientras que Ollama te permite desplegar un modelo rápidamente y sin complicaciones, LMStudio te da el control completo sobre el proceso de entrenamiento. ¿La diferencia clave? Ollama es perfecto para usar modelos preexistentes, mientras que LLMStudio es tu herramienta si quieres crear o hacer fine-tunning de un modelo a medida (aunque por supuesto, también te permite ejecutar modelos).
Pinokio es en cambio una herramienta que nos va facilitar mucho la vida. Se trata de una especie de “hub” de aplicaciones que permite instalar, ejecutar y controlar de manera programada y local cualquier aplicación de IA con un solo clic. Pinokio automatiza todo el proceso, por lo que sólo tienes que centrarte en utilizar la herramienta.
Esto sabiendo lo complicado que es a veces ejecutar entornos de IA (por ejemplo por las dependencias), la verdad es que es una gran ayuda. Pinokio tiene su propio repositorio de GitHub aunque se puede instalar directamente en MacOS, GNU/Linux o MS Windows descargando la aplicación desde su web.
A partir de este punto ya tenemos todo lo necesario para poder ejecutar todo tipo de aplicaciones de IA en local, ya sea para generar imágenes, vídeo, texto, LLMs, etcétera. Existen herramientas como OllamaWebUI (que puedes instalar desde Pinokio) que te ofrecen una interfaz parecida a ChatGPT para tus modelos locales de Ollama, puedes llamar a tu modelo a través de una API, usar RAG, etcétera.
This is the way …
El futuro, en mi humilde opinión, se basa en agentes y el uso de IA local (ambos combinados) para crear una especie de ecosistema de “microservicios” inteligentes locales creando tareas complejas partiendo de tareas más sencillas. Con la llegada de GPUs más potentes (como la RTX 5090), nuevas tecnologías de hardware como Groq, el desarrollo de clústeres accesibles (como los Mac mini) y soluciones de cuantización más eficientes, la capacidad de ejecutar modelos LLM de alta complejidad en hardware asequible será cada vez algo más habitual. Además, herramientas que faciliten el fine-tuning local y las APIs conectadas a servicios propios permitirán que cada usuario o empresa ajuste la IA a su medida.
Prácticamente cada día entramos en nueva era de la inteligencia artificial, donde la privacidad, el control de costes y la potencia accesible son cada vez más una parte importante a tener en cuenta. El hardware sigue mejorando, el software simplificándose y los modelos avanzando; el objetivo, poder controlar nosotros mismos esta tecnología (democratizarla) que está cambiando día a día toda la Humanidad (por mucho que haya gente que no crea aún en la IA o diga que estamos en un punto muerto o sin salida).
La privacidad es algo que nos preocupa (y cada vez más) en general, y en el ámbito de la Inteligencia Artificial en particular, también es importante para las personas y las organizaciones. Cada vez que escribimos un prompt y lo enviamos a servicios en la nube como ChatGPT o Claude, estamos compartiendo datos que, potencialmente, pueden almacenarse y reutilizarse.
Esto es particularmente preocupante cuando la información enviada es sensible, ya que existe el riesgo de que termine en un Data-leak, afectando tanto a empresas como a individuales. Además, algunos modelos en la nube utilizan los datos recibidos para mejorar sus sistemas mediante re-entrenamientos, lo que podría provocar que esa información apareciera inesperadamente si alguien realiza las preguntas adecuadas en el futuro.
Figura 1: Cómo montar tu propio servidor de Inteligencia Artificial.
Modelos Open Source, Parámetros y Hardware NVIDIA
Por otro lado, está, cómo no, el factor económico. Los servicios de IA en la nube suelen cobrar por uso, basándose en la cantidad de tokens procesados por cada consulta o interacción. Para desarrolladores o pequeñas empresas que quieren integrar IA en sus aplicaciones, estos costos pueden acumularse rápidamente y convertirse en una barrera complicada. En este artículo - que tiene dos partes - veremos un recorrido sobre diferentes opciones para esto.
Sin embargo, no todo está perdido: los modelos LLM de código abierto ofrecen una alternativa asequible. Estas soluciones nos permiten desplegar IA de forma local (on-premise), eliminando la dependencia de terceros y ofreciendo un control total sobre los datos y los costes (básicamente, el precio de la luz eléctrica). Algo que muchos hechos hecho también para entrenar nuestros modelos de Machine Learning, con lo que para investigadores es una solución perfecta.
Está claro que, el rendimiento de estas alternativas, dependerá del hardware disponible, pero con la infraestructura adecuada, es posible construir entornos locales que pueden ejecutar proyectos de gran complejidad sin poner en peligro nuestra privacidad y tampoco quedarnos sin fondos. Pero vayamos por partes.
Los modelos LLM Open Source
Un modelo LLM (Large Language Model) de código abierto es un modelo de IA entrenado con grandes cantidades de texto para realizar tareas de procesamiento de lenguaje natural (NLP), como generación de texto, traducción, clasificación, entre muchas otras. Al ser de código abierto, los pesos del modelo, el código fuente y, en muchos casos, los datos o el proceso de entrenamiento están disponibles públicamente, permitiendo a cualquiera personalizar, adaptar o reutilizar el modelo para sus propios proyectos.
La gran mayoría de estos modelos se basan en arquitecturas de Transformers, que ya conocemos bien, que fueron introducidas por Vaswani et al. en 2017, y que utilizan mecanismos de autoatención para analizar el contexto global de las palabras en una secuencia, capturando relaciones complejas entre términos en largos rangos de texto.
El funcionamiento de un LLM se divide en dos fases principales: preentrenamiento y ajuste fino (fine-tuning). En el preentrenamiento, el modelo aprende patrones lingüísticos generales a partir de grandes corpus de texto no supervisados, utilizando tareas como predicción de palabras “enmascaradas” (BERT) o predicción autoregresiva (GPT).
Posteriormente, en el fine-tunning, el modelo es adaptado a tareas concretas mediante conjuntos de datos etiquetados, lo que mejora su precisión en dominios específicos. Estos tienen una escalabilidad exponencial (el rendimiento tiende a mejorar con el aumento del tamaño del modelo y los datos de entrenamiento), capacidades multi-idioma, y flexibilidad para realizar múltiples tareas con el mismo modelo base.
Los “Billions” son la clave …
Es importante dejar claro un tema antes de continuar: los “Billions”. Los “billions” son esa “B” que podemos ver cuando se describe cada modelo. La “B” en los modelos LLM, como 7B, 13B o 70B, nos muestra la cantidad de billones (americanos) de parámetros que tiene el modelo, donde un parámetro es un coeficiente ajustable aprendido durante el entrenamiento.
Estos parámetros determinan cómo el modelo procesa la entrada (texto) y genera la salida (respuesta), y esto es clave para su capacidad de comprensión y generación de lenguaje natural. En términos técnicos y simplificando mucho, los parámetros son los pesos y sesgos de las capas de la arquitectura Transformer, ajustados a lo largo de millones de iteraciones de entrenamiento para minimizar la pérdida en tareas como predicción de texto. Un mayor número de parámetros permite al modelo capturar patrones más complejos y sutiles en los datos de entrenamiento, mejorando su rendimiento en tareas más complejas.
Pero claro, el aumento en el número de parámetros tiene implicaciones directas en el rendimiento, el coste y la infraestructura necesaria. Modelos más grandes, como uno de 70B, requieren una cantidad exponencialmente mayor de memoria GPU (mínimo aproximadamente 40 GB por GPU para inferencia eficiente) y un mayor tiempo de cómputo, tanto para entrenamiento como para inferencia (no os preocupéis de momento por esto, lo veremos en el siguiente apartado).
Esto impacta en la calidad de las respuestas, especialmente en contextos complejos, pero también introduce latencia y un consumo energético. En cambio, modelos más pequeños como 7B son más rápidos y pueden ejecutarse en hardware más asequible, como un Mac M1 con 16 GB de RAM o una GPU de consumo medio como una NVIDIA RTX 3060 con 12GB de VRAM. Pero mejor vamos a centramos en el hardware para ver qué necesitaremos.
El hardware: Opción NVIDIA
Ya sabemos las restricciones y características que nos ofrecen los modelos de código abierto, ahora necesitamos la electrónica para poder ejecutarlos. Aquí es donde debemos tener en cuenta varias variables. La primera es tener clara la inversión que vamos a hacer y la segunda decidir la posible arquitectura base (x86vs ARM o dicho de otra manera, NVIDIAvsApple Silicon). Como todo en la vida, a más dinero mejor ;) pero vamos a ver algunas que no sean una locura de inversión. Cada una de ellas tiene sus ventajas y sus problemas.
Si seleccionamos una arquitectura clásica basada en NVIDIA y x86, el primer paso es tener un buen ordenador. Los ordenadores tipo “gaming” son una gran opción ya que estos suelen llevar una buena configuración de hardware de base. Es importante que tengamos un buen microprocesador de arquitectura x86 ya sea Intel o AMD pero seguro que esto lo vemos mejor con un ejemplo. ¡Ojo!, por supuesto hay más opciones y más sencillas, esto es sólo una recomendación basada en mi experiencia.
Y nada mejor mi que mi caso concreto ;) que es un buen equipo para empezar. Mi servidor de IA también lo utilizo para otras tareas más genéricas (virtualización) y es un AMD Ryzen 9 3900X, con 64GB de RAM y 3TB de disco duro. La tarjeta gráfica que tengo es una RTX 4070 con 12GB de VRAM (estoy esperando a las nuevas 5090 que salen a principios de 2025). La pegatina de Alan Turing también es importante ponerla ;)
Figura 7: Mi servidor local de IA y VMs, con la pegatina de Alan Turing.
Como he comentado antes, esta configuración no la tengo exclusivamente para IA, ya que quiero aprovechar el hardware. Por eso tengo instalado Proxmox como hipervisor (consejo de mi gran amigo Rafael Troncoso, alias "Tuxotron"). La ventaja es que me sirve para gestionar máquinas virtuales y usando la característica “GPU Passthrough” puedo conectar la tarjeta gráfica a la VM que necesite ejecutar IA en local. De esta forma puedo estar levantando y apagando las VM con diferentes sistemas operativos (eso sí, sólo una VM puede gestionar la gráfica a la vez).
Esta configuración es más que suficiente para levantar modelo 7B y alguno más a una velocidad decente de ejecución. Aquí la clave está en la memoria VRAM de la tarjeta gráfica, ya que es lo que te permitirá levantar y hacer inferencias a modelos grandes.
El problema de esta configuración x86 basada en NVIDIA, como podéis haber imaginado, es el precio. Una 4090 con 24GB de VRAM está alrededor de los 2.000€ aunque es posible que el precio baje cuando salgan las nuevas 5090. De todas formas, hay soluciones decentes 3090 TI con 24GB a buen precio e incluso podrías conectarlas usado NVLink o SLI y así aumentar la VRAM y su potencia que te permitiría hasta ejecutar modelos de 70B, como puedes ver en el vídeo siguiente.
Ya si queremos opciones más profesionales como una A100 por ejemplo con 80GB de VRAM ya estamos hablando de precios que oscilan entre los 10.000 y 20.000€ aproximadamente. Pero hay otras opciones, y hay más cosas que tener en cuenta para montar tu propio servidor de Inteligencia Artificial, lo vemos en la siguiente parte que tienes aquí mismo: "Cómo montar tu propio servidor de Inteligencia Artificial: Apple Silicon, Ollama, LMStudio & Pinockio".
Hoy os voy a hablar de GhostRace, una nueva forma de explotar sistemas uniendo los ataques de Spectre y las vulnerabilidades de Use-After-Free que son tan comunes en muchos exploits como hemos visto en el pasado. Es un artículo académico muy interesante, y de muy bajo nivel, pero merece la pena que entiendas qué es lo que hace, y qué es lo que significa así que vamos a repasar un poco estas dos vulnerabilidades y cómo las utiliza GhostRace.
En el año 2018 se descubrieron los ataques de Spectre y Meltdown, donde se podría acceder a valores de memoria prohibidos, aprovechándose de la ejecución especulativa de la CPU en las arquitecturas avanzadas que tenemos hoy en día día en los microprocesadores. La idea es que la CPU, teniendo puertas lógicas en paralelo, y registros en la caché, el microprocesador puede ejecutar al mismo tiempo todas las ramas de un if.
Spectre & Spectre-PHT (Spectre v1)
Supongamos que hacemos una instrucción que sea if (X<A1+A2) then C=B1+B2 else C=B3+B4. En un entorno especulativo, para calcular C, el micro calcula en paralelo la condición y las dos ramas. Es decir, calcula X<A1+A2, C=B1+B2 y C=B3+B4, y luego, cuando tenga la respuesta a la condición, ya elige, pero eso hace que el tiempo de ejecución total del programa sea menor, porque se ha paralelizado una instrucción.
Esto, Spectre y Meltdown demostraron que podría ser un problema, si alguien ponía en una de las ramas una operación que podría ser un acceso ilegal dependiendo del valor de la condición. Por ejemplo, si tenemos una instrucción como:
if (x<100) then C=array1[X] else C=array2[X]
y la CPU hace la ejecución especulativa de las dos ramas, entonces puede ser que esté haciendo un acceso a array1[9000] cuando array1 podría tener solo 100 posiciones. Este dato, sin embargo, estará en uno de los registros de la caché, que podría ser filtrado directamente desde el registro de la caché.
Una explotación concreta de esta técnica se publicó en el año 2019, llamada Spectre-PHT o llamada como Spectre v1, que se hace con un ejemplo como este que podéis ver en la imagen siguiente. Debido a las protecciones contra Spectre y Meltdown, el ataque de Spectre-PHT, llamado también Spectre v1, hace una operación como la siguiente, en la que se hace una comparación del valor x con la longitud de un array - controlado por el atacante -, para luego ejecutar el acceso a una posición de memoria concreta.
Figura 4: Un ejemplo de Spectre-PHT
Si durante varias peticiones x está dentro de los límites de array1 y el atacante se asegura que no se ha cacheado ningún valor de array2 lo que va a suceder es que la CPU va a predecir que el valor de esa comparación podría ser True, y por tanto comenzará la ejecución especulativa de la parte del "then", metiendo en la caché del microprocesador la información de una determinada zona de memoria, asumiendo que la comparación previa va a ser True.
Cuando el atacante introduce un valor X fuera de los límites, se supone que no debería ejecutarse la parte del "then" de la comparación porque está fuera de los límites, pero en el registro de la caché estará cargado el valor de la zona de la memoria que se había especulado - y que está fuera de la memoria accesible en array1[x] - asumiendo previamente que el IF podría ser True. Esto quiere decir que en la caché está guardado el valor de array2[array1[x]*0x100] siendo array1[x] un valor cargador de dirección de memoria prohibida que se ha cargado en la caché, junto con el valor de array2[array1[x]*0x100].
Ahora, recorriendo el rango de posibles registros de memoria de array[2], se podrá saber cuál es valor de un byte que se ha leakeado, porque estará cacheado en un registro del microprocesador, y por tanto el acceso a ese array2[y] que se obtendrá será mucho menor que el acceso a las demás posiciones porque está cacheado en una zona de muy baja latencia de acceso, y por tanto se podría saber el valor que había en array1[X] (el valor prohibido), haciendo una sencilla ecuación que es y/0x100 = valor que hay en la dirección de memoria prohibida más allá de los límites de array1 que está en array1[x].
Esta técnica permite, haciendo algo como lo visto en la Figura 4, tener un SRC "Speculative Race Condition" que nos da un Information Disclosure o "Speculative Information Disclosure" para er más exactos del valor de una posición de memoria prohibida. Esa posición de memoria puede ser un puntero, con información importante para generar un exploit, o una zona de memoria que nos ancle para poder saltar el KASLR (Kernel Address Space Layaout Randomization) que aleatoriza las direcciones de carga de programas en el Kernel. Si quieres conocer más de cómo funcionan las protecciones de memoria en los sistemas operativos, te recomiendo los libros de Linux Exploiting y de Máxima Seguridad en Windows.
Use-After-Free
Las vulnerabilidades de Use-After-Free son muy comunes en muchos programas cuando no gestionan de forma segura la memoria dinámica. La idea es tan sencilla como que un programa cargue en el Heap dun segmento de código de un programa apuntado por un puntero. Después, esa zona de memoria del Heap se elimina, pero el puntero no se elimina haciéndole apuntar a NULL.
Figura 6: Ejemplo de Use-After-Free
Si esto es así, un atacante podría cargar en esa zona de memoria un programa controlado por él, y conseguir que el puntero estuviera apuntando a su programa, por lo que podría después se ejecutado haciendo que el código apuntado por ese puntero consiga la ejecución del contador de programa.
Cargar el programa a ejecutar en una zona de memoria donde se ha cargado código de la víctima previamente, ayuda a saltarse el DEP (Data Execution Prevention) al ser zonas de memoria marcadas para ejecución de código y no datos. Esta es una técnica clásica de construcción de explotis, y en el libro de Linux Exploiting se estudia en un capítulo, como podéis ver aquí en el índice.
Evitar esto, es tan sencillo como asegurase de eliminar todos los punteros al heap de ejecución y no dejarlos colgados apuntando a zonas de memoria que han sido liberadas en el heap, y para eso hay protecciones en los kernels de los sistemas operativos, con el objetivo de que no pase esto.
GhostRace
Llegados a este punto, ya podemos mezclar las dos técnicas de ataque, es decir, los ataques de Spectrev1 para saltarse mediante SRC (Speculative Race Conditions) y SID (Speculative Information Disclosures) las protecciones del kernel contra acceso concurrente sincronizados para regiones críticas como mutex o spinlocks que no aplican en ejecución especulativa, y ejecutar ataques Use-After-Free, en lo que llaman en el paper de GhostRace los Speculative Concurrent Use-After-Free (SCUAF).
Al final, para hacer un exploit hay que lograr que conseguir encontrar un punto del código que sea una vulnerabilidad de UAF, para conocer en qué posición de memoria hay que cargar el segmento de código con el exploit. Para evitar ello, el kernel tiene protecciones con los punteros que evitan que se pueda acceder al valor de esos punteros en el kernel como Kaslr, pero con una explotación especulativa con Spectre_v1 se puede conseguir una condición de carrera que consiga acceder a ese valor, tal y como se ha visto antes.
Para conseguir eso, en el artículo hacen ejemplos de construcciones de Speculative Race Conditions basadas en Spectre_v1 para lograr ataques de Speculative Information Disclosure y Speculative Hijacking Control Flow, que son piezas necesarias para hacer un exploit SCUAF funcional, que pueda ejecutar código arbitrario incluso con las protecciones contra UAF en el kernel del sistema operativo.
Conclusiones
El paper de GhostRace hace todas las primitivas en ramas especulativas, por lo que todas dependen de generar condiciones de carrera en ramas especulativas (SRC Speculative Race Conditions) con zonas de memoria prohibidas para acceder a la información almacenada en ellas. Resolver este problema implica poner protecciones extras en el microprocesador, o en el kernel para evitar las explotaciones de Spectrev1 que se pueden hacer hoy en día en las CPUs afectadas, pero esto implica una perdida masiva de rendimiento, por lo que no hay planes en Linux de hacer estos cambios. Un bonito panorama para los fabricantes de microprocesadores, programadores de hipervisores, cloud software de base y kernel de sistemas operativos.
En el año 1971Intel presentó el primer microprocesador de la historia, el Intel 4004, un procesador que poca gente entendió, de aquella, su sentido. Ya había nacido el transistor y los circuitos impresos para crear la electrónica moderna, y alejarse de las útiles, pero pesadas, válvulas de vacío. En 1971 la informática pesada, los grandes monstruos de tipo “mainframe”, estaban dejando paso a una serie de “miniordenadores”, como la serie PDP de DEC, pero la informática seguía siendo de “gigantes” y para “gigantes”.
Figura 1: El amor a la computación clásica. Imagen Dall-e:
"drawing of an Amstrad CPC 6128 made by a six years old kid"
Pero el microprocesador abrió dos puertas que juntas eran una única vital para el futuro de la informática: el propósito general y la miniaturización. Precisamente la segunda, la miniaturización, abrió un espacio, el microordenador, y un destino: el hogar o la población en general, como ustedes prefieran llamarlo. Pero ninguna gran empresa apostó por aquello, ni las más importantes, ni las de segunda fila:
¿Quién quiere un ordenador en casa? ¿Qué utilidad tiene aquello?
Y, entonces, llegaron los entusiastas de la electrónica... ellos abrieron el camino. Empezaron a proliferar ordenadores basados en kit, como el popular Altair 8800 de 1975 o su clon IMSAI 8080 de 1976, y otros muchos; ordenadores que eran ensamblados pieza a pieza por los entusiastas de la electrónica a mediados de los años setenta.
Llegamos al año 1977, cuando a alguien se le ocurrió la idea que aquello que estaba arrasando entre los entusiastas de la electrónica, podía arrasar entre la población en general. Pero la población no sabía lo que era un circuito impreso, ni sabían lo que era un microprocesador; había que crear ordenadores ensambladores y con el software básico preparado para poder hacer cosas con ellos en los hogares.
¿Pioneros?
Evidentemente fueron Steve Jobs, y Steve Wozniak los pioneros más famosos, pero su primer ordenador, el Apple I de 1976, no era un ordenador, sino una placa base a la cual había que proporcionar el resto de componentes que necesitaba para poder convertirse en un ordenador. Hubo que esperar a 1977 para ver nacer al Apple II, el primer ordenador ensamblado de la empresa de Cupertino. Y para el año 1977 ya habían nacido, casi de la mano, otros pioneros tan populares como el Commodore PET y TRS-80.
Los entusiastas de la electrónica abrieron el camino del ordenador personal y, con ello, de la informática personal. Es el año 1977 donde nació el ordenador personal y la informática personal según mi punto de vista. Y para ese año ya estaba la informática inundada de nombres de productos muy importantes: MOS 6502, Zilog Z80, BASIC, CP/M, etcétera. Y también de otros nombres: Federico Faggin, Gary Kildall, Chuck Peddle, Steve Wozniak,...
Sin duda alguna Federico Faggin fue vital para la época, creador del mítico Zilog Z80, y Gary Kildall, creador del sistema operativo CP/M que alimentó a los primeros ordenadores Intel 8080, y a los posteriores Zilog Z80 que arrasaron en la década de los año ochenta. Pero... ¿y Chuck Peddle? Una persona poco reconocida. Para mí el padre de la informática personal, y del ordenador personal.
Chuck Peddle, después de participar activamente en la creación del Motorola 6800, creyó firmemente en la idea de poder crear un microprocesador barato y de bajo coste. La idea se la quitaron de la cabeza en Motorola, y se fue a MOS Technology donde creó el primer microprocesador barato y asequible, el increíble MOS 6502 que formó parte de ordenadores tan famosos como el Commodore 64, el ordenador más vendido de la historia, o el Apple II.
Y con el MOS 6502 nació en Peddle otra idea, la de crear un ordenador personal que pudiera se asequible para los hogares... informatizar los hogares. Para esa idea, que persiguió sin descanso y con muy pocos apoyos, se fusionó con Jack Tramiel, fundador de Commodore, y crearon en 1977 el mítico Commodore PET. Sin el empeño y la intensidad de Chuck Peddle, la informática personal quizás hubiera sido otra cosa. Seguro que hubiera tardado más tiempo en llegar.
Y así llegamos al año 1986, el día en el que mis padres me regalaron un Amstrad CPC6128 “para jugar”, con nada más y nada menos que 128 Kilobytes de RAM y una disquetera de 3 pulgadas de dos caras que pocos podían tener. Y cuando me senté en ese ordenador, con 12 años de edad que tenía, nació en mi una pasión.
Una pasión que me ha llevado a contar hoy con 30 años de experiencia profesional en Ingeniería de Software, a crear mi blog parceladigital.com donde, por medio de vídeos, podcasts, y artículos en texto, recupero y divulgo la historia de la informática. Y también me llevó a ganar las estatuillas de los premios del mundo de Internet más importantes en idioma español. Pero nada es tan valioso como cuando sé con certeza que hay gente que agradece la labor de divulgar sobre la computación clásica. Y hay muchas personas interesadas en ello.
Al poco tiempo de sentarme en el Amstrad CPC6128 empecé a programar en BASIC, a crear mis primeros videojuegos, y mi primer software de gestión. Me pasé al mundo PC y... nació “el amor a la computación clásica”, con el paso del tiempo.
No viví los años setenta de la informática personal, pero la estudié; sí viví en directo la informática de los años ochenta, aquella en la que no había nada hecho y todo lo tenía que hacer uno por si mismo, donde no existía Internet y el talento era imprescindible para aprender y evolucionar. La pirámide invertida, hoy trabajamos sobre un montón de hardware y software evolucionado por genios y grandes equipos de trabajo... trabajamos en una base muy fuerte con sistemas operativos muy potentes, y con software alta calidad para todo. En los ochenta no había casi nada, todo se trabajaba en modo texto con letras en blanco y fondo texto, y a veces en ensamblador, y con programación de ceros y unos también...
El acto de intercambiar software, disquete arriba y abajo... acudir a las revistas de informática era la mayor fuente de información cuando no existía Internet... las primeras llamadas vía línea telefónica a las BBS’s, unas comunicaciones rudimentarias por medio del “Carbon Copy”... a veces llamando al extranjero... aquellas optimizaciones a mano de la memoria RAM en el MS-DOS para poder liberar el máximo espacio en la memoria convencional de 640 Kilobytes para que aquel vídeojuego potente que queríamos arrancar pudiera hacerlo ya que no podía acceder a la extendida... todo aquello era otra atmósfera diferente al actual, sin ingenio y talento poco podías hacer con un ordenador... la época donde solo podías compartir software con aquellos que tenían tu Amstrad CPC en disquetes de 3 pulgadas, o compartiendo las cintas de ZX Spectrum de Sinclair, o los cartuchos del sistema MSX, que desde Japón se estaba intentado crear un mundo PC similar y abierto, pero dentro de la informática de 8 bits.
Pasados los años tuve la suerte de contactar con personas como José Luis Domínguez, fundador de la mítica empresa Indescomp -el “Steve Jobs” español le llamo- que fundó aquella empresa de cero, apostó por lo que nadie apostaba, logró con artimañas que Alan Michael Sugar le otorgara la distribución en exclusiva para España de los ordenadores británicos Amstrad, y arrasó en el mercado español a mediados de los ochenta con un nuevo concepto: ordenadores de 8 bits de importantes características a precios populares. Hoy en día conversamos él y yo de vez en cuando por Whatsapp e intercambiamos pareceres y proyectos.
Y tuve la suerte también de entablar amistad con Paco Portalo, que cuando terminó la Ingeniería en Electrónica se fue de su Badajoz natal a Madrid para terminar por unirse al mítico pacense Paco Suárez para crear, para Indescomp y José Luis Domínguez, el mítico videojuego de “La Pulga”, “Bugaboo”, “The Flea”, como ustedes prefieran llamarlo. El primer videojuego español de éxito internacional en 1983. Ese año, y con ese videojuego, nació la etapa conocida como “La Edad de Oro del Software Español (1983-1992)” con nombres estelares alrededor como Paco Suárez, Paco Menéndez, Fernando Rada, Camilo Cela, Carlos Granados,.. y un largo etcétera.
Parco Portalo recibió, recientemente, la Medalla de Oro al Mérito de las Bellas Artes de mano de los Reyes de España. Un orgullo ser su amigo. Tanto José Luis Domínguez como Paco Portalo son ejemplos de personas que fueron vitales para la informática clásica en este país, y que hoy debemos recordar y valorar. Hay más, y tuve y tengo la suerte de poder entrar en contacto con algunos de ellos... los pioneros.
En el año 2016 empecé un largo camino con mi blog "Parcela Digital" a través del texto (artículos), vídeo (vídeoblogs), y audio (podcasts) en el sentido de compartir “mi amor a la computación clásica” con todo el mundo. Sobre todo con la idea de compartir con las nuevas generaciones que, cuando nacieron, ya existía incluso Internet y nunca pudieron vivir los años setenta, ochenta, y noventa de la informática personal del siglo pasado.
Y el camino fue tan importante para mí que terminó en un libro de 516 páginas titulado “Historia de la informática: El Ordenador Personal”.
Aquellos años fueron únicos, el ambiente era increíble... una especialidad de la ciencia tecnología por explorar que hacía muy poco que había nacido... era otro mundo, otra forma de vivir, y otras necesidades que atender. Todo aquello, ya pasado hace cuatro y cinco décadas, no puede caer en el olvido, y aquellos que lo hemos vivido con intensidad, debemos ser los que hoy en día divulguemos sobre nuestro “amor por la computación clásica”.