Kabosu - Creando cosas

Logo de la página. Gato esférico con colores verdoso.

lscpu y las vulnerabilidades en los procesadores

Publicado: 2024-06-02 (actualizado 2024-08-02)

Etiquetas: Linux


En este artículo voy a contar algo que me ha pasó hace unos días: estaba curioseando entre los programas instalados en Ubuntu y encontré uno que lista vulnerabilidades del procesador e indica si están o no mitigadas. Una de ellas no lo estaba así que estuve investigando cómo hacerlo hasta que finalmente lo conseguí. Aunque la alegría no duró mucho...

lscpu

Desde hace un tiempo estoy intentando aprender más a fondo cómo funciona Linux y en particular la distribución que uso: Ubuntu. Hace 10 o 15 años estaba mucho más familiarizado con los entresijos del sistema y conocía muy bien los ficheros de configuración, comandos, paquetes, etc. Incluso era capaz de hacer pequeños cambios en el código del kernel y no romper nada. Pero esa época ya pasó y desde entonces he estado usando Ubuntu sin pararme a entender qué ocurre por debajo. Supongo que me había acomodado.

Decidí hacer 3 cosas para reciclarme un poco:

En las últimas semanas he ido haciéndolo a ratos y todavía me queda mucho que investigar pero estoy aprendiendo bastante. Hace poco, en una de mis sesiones de análisis encontré por casualidad el programa lscpu que es el que inició toda la historia que voy a contar.

El directorio /bin tiene un conjunto de programas que empiezan por ls que proporcionan información diversa sobre el sistema y el hardware:

$ ls /bin/ls*
ls           lsb_release  lsinitramfs  lslogins     lsns         lspgpot      
lsattr       lscpu        lsipc        lsmem        lsof         lsusb        
lsblk        lshw         lslocks      lsmod        lspci 

Si ignoramos el clásico ls creo que lsusb es seguramente el que más he usado de ellos. Al ejecutarlo muestra una lista con los dispositivos USB que tenemos conectados al ordenador incluyendo hubs y cosas internas pero que realmente están conectadas por USB como la cámara del portátil. Me ha resultado útil en el pasado para saber si estaba reconociendo correctamente mis dispositivos.

$ lsusb
Bus 002 Device 002: ID 8086:0a66 Intel Corp. Intel(R) RealSense(TM) 3D Camera (Front F200)
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 8087:0a2a Intel Corp. Bluetooth wireless interface
Bus 001 Device 037: ID 1bcf:0005 Sunplus Innovation Technology Inc. Optical Mouse
Bus 001 Device 036: ID 040b:2000 Weltrend Semiconductor wired Keyboard [Dynex DX-WRK1401]
Bus 001 Device 035: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

El programa que no conocía (o no recuerdo haber usado nunca) es lscpu que como su nombre indica muestra información sobre el procesador. Muestra el modelo de CPU, velocidad, número de nucleos y cosas así pero también indica qué características opcionales tenemos activadas.

$ lscpu
Architecture:            x86_64
  CPU op-mode(s):        32-bit, 64-bit
  Address sizes:         39 bits physical, 48 bits virtual
  Byte Order:            Little Endian
CPU(s):                  8
  On-line CPU(s) list:   0-7
Vendor ID:               GenuineIntel
  Model name:            Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
    CPU family:          6
    Model:               94
    Thread(s) per core:  2
    Core(s) per socket:  4
    Socket(s):           1
    Stepping:            3
    CPU max MHz:         3500.0000
    CPU min MHz:         800.0000
    BogoMIPS:            5199.98
    Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflu
                         sh dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm const
                         ant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid a
                         perfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16
                          xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsav
                         e avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pt
                         i ssbd ibrs ibpb stibp tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_a
                         djust bmi1 avx2 smep bmi2 erms invpcid mpx rdseed adx smap clflushopt intel_p
                         t xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_a
                         ct_window hwp_epp vnmi md_clear flush_l1d arch_capabilities
Virtualization features: 
  Virtualization:        VT-x
Caches (sum of all):     
  L1d:                   128 KiB (4 instances)
  L1i:                   128 KiB (4 instances)
  L2:                    1 MiB (4 instances)
  L3:                    6 MiB (1 instance)
NUMA:                    
  NUMA node(s):          1
  NUMA node0 CPU(s):     0-7
...

Lo que no me esperaba, y es básicamente por lo que estoy escribiendo este artículo, es que lsusb también comprueba los distintos problemas de seguridad que se han encontrado en los procesadores en los últimos años y para cada uno de ellos indica si lo tenemos parcheado o no.

Vulnerabilities:         
  Gather data sampling:  Vulnerable: No microcode
  Itlb multihit:         KVM: Mitigation: VMX disabled
  L1tf:                  Mitigation; PTE Inversion; VMX conditional cache flushes, SMT vulnerable
  Mds:                   Mitigation; Clear CPU buffers; SMT vulnerable
  Meltdown:              Mitigation; PTI
  Mmio stale data:       Mitigation; Clear CPU buffers; SMT vulnerable
  Retbleed:              Mitigation; IBRS
  Spec rstack overflow:  Not affected
  Spec store bypass:     Mitigation; Speculative Store Bypass disabled via prctl
  Spectre v1:            Mitigation; usercopy/swapgs barriers and __user pointer sanitization
  Spectre v2:            Mitigation; IBRS; IBPB conditional; STIBP conditional; RSB filling; PBRSB-eIB
                         RS Not affected; BHI Not affected
  Srbds:                 Mitigation; Microcode
  Tsx async abort:       Mitigation; TSX disabled

En mi caso tengo todas las vulnerabilidades mitigadas excepto la primera: Gather data sampling. Me pareció raro porque ese error, conocido popularmente como Downfall es bastante importante.

Intentando actualizar el procesador

¿Cómo se actualiza un procesador? Pues instalando un microcódigo del fabricando más reciente. El microcódigo es una especie de firmware para los procesadores y tiene una particularidad: no es permanente sino que hay que aplicar la actualización cada vez que se enciende el ordenador. La BIOS/UEFI puede aplicar el microcódigo automáticamente pero, como la gente no suele actualizar el firmware de su placa base los sistemas operativos también lo aplican.

Con el comando dmesg se puede ver que lo primero que hace el kernel de Linux al iniciarse es actualizar el microcódigo. En mi caso a la versión del día 2021-11-12:

[    0.000000] microcode: updated early: 0x74 -> 0xf0, date = 2021-11-12
[    0.000000] Linux version 6.5.0-1023-oem (buildd@lcy02-amd64-106) (x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #24-U
buntu SMP PREEMPT_DYNAMIC Tue May  7 14:26:31 UTC 2024 (Ubuntu 6.5.0-1023.24-oem 6.5.13)

La vulnerabilidad Downfall fue descubierta en 2022 y el microcódigo de mi CPU es de 2021 así que es normal que lscpu se queje de que Gather data sampling: Vulnerable: No microcode. La pregunta es porqué no la tengo mitigada.

Estuve investigando si podía parchear el problema. Lo primero que intenté es averiguar qué microcódigo está aplicando el kernel cada vez que se inicia y porqué salía con fecha de 2021. En Ubuntu para procesadores Intel, viene en el paquete intel-microcode. Según la documentación de Ubuntu se necesita como mínimo la versión 3.20230808 para estar protegido contra esta vulnerabilidad y yo tengo 3.20240514.0ubuntu0.22.04.1. El paquete que tengo instalado es de hace apenas unas semanas. Debería tener el microcódigo que mitiga Downfall pero por alguna razón no se aplica al iniciar.

Otra forma de actualizar microcódigo es que lo haga la placa base. Tengo un portátil Lenovo de 2015. Por lo que veo en su web, la última actualización de los drivers y la BIOS/EUFI fue en 2019 (y ya actualicé hace unos años) así que era poco probable que pudiera mitigar la vulnerabilidad instalando algo del fabricante.

Tras un rato leyendo documentación y el contenido del paquete intel-microcode empecé a sospechar que lo que ocurría es que Intel había publicado el microcódigo para mitigar Downfall pero no para mi procesador por ser "antiguo". La última actualización del microcódigo para mi CPU es de la de noviembre 2021 así que poco podía hacer.

Mitigando la vulnerabilidad en el kernel de Linux

Estuve investigando un poco más y descubrí que el kernel de Linux tiene un parámetro que permite mitigar la Downfall aunque no se pueda actualizar el procesador. Esto me podría solucionar el problema. Configurando gather_data_sampling="force", Linux desactiva completamente las instrucciones AVX haciendo imposible que se explote la vulnerabilidad. AVX significa Advance Vector Extensions y son instrucciones para manejar vectores de datos y acelerar determinados cálculos. Ya avisan que desactivándolas el CPU puede rendir entre un 30 y un 50% menos. Entiendo que esta es la razón por la que Ubuntu no activa la opción del kernel por defecto.

La verdad es que no sabía cómo se pasaban argumentos al kernel así que tuve que averiguar eso también. El comando cat /proc/cmdline nos muestra qué parameros ha recibido el kernel que estamos ejecutando actualmente. Por supuesto en el mío no estaba la opción gather_data_sampling.

En Linux se pueden añadir parámetros temporalmente al iniciar el sistema. Cuando aparece el menú de selección de sistema operativo, el mítico Grub, pulsando la tecla e podemos editar la configuración del kernel antes de iniciar. Eso hice para comprobar qué pasaba. Al iniciar el sistema pude ver con dmesg que, efectivamente, el kernel buscaba una actualización de microcódigo y al no encontrarla desactivaba las instrucciones AVX tal y cómo indicaba la documentación.

[    0.119123] GDS: Microcode update needed! Disabling AVX as mitigation.
[    0.119124] GDS: Mitigation: AVX disabled, no microcode

Ahora con el comando lscpu finalmente todas las vulnerabilidades aparecen mitigadas.

Vulnerabilities:         
  Gather data sampling:  Mitigation; AVX disabled, no microcode
  Itlb multihit:         KVM: Mitigation: VMX disabled
  L1tf:                  Mitigation; PTE Inversion; VMX conditional cache flushe
                         s, SMT vulnerable
  Mds:                   Mitigation; Clear CPU buffers; SMT vulnerable
  Meltdown:              Mitigation; PTI
  Mmio stale data:       Mitigation; Clear CPU buffers; SMT vulnerable
  Retbleed:              Mitigation; IBRS
  Spec rstack overflow:  Not affected
  Spec store bypass:     Mitigation; Speculative Store Bypass disabled via prctl
  Spectre v1:            Mitigation; usercopy/swapgs barriers and __user pointer
                          sanitization
  Spectre v2:            Mitigation; IBRS; IBPB conditional; STIBP conditional; 
                         RSB filling; PBRSB-eIBRS Not affected; BHI Not affected
  Srbds:                 Mitigation; Microcode
  Tsx async abort:       Mitigation; TSX disabled

Para añadir el parámetro definitivamente al kernel hay que editar el ficher /etc/default/grub pero cómo explicaré a continuación no hizo falta.

Probando Ubuntu sin AVX

Nunca juego en este ordenador así que mi única preocupación era que el navegador o VLC fallasen que son los programas que potencialmente podrían hacer un buen uso de AVX. Tras probar un rato todo parecía funcionar bien. Podía escuchar música y ver vídeos con VLC. Estuve usando Firefox durante horas y no encontré ningún problema. No sabría decir si funcionaban entre un 30 y un 50% más lentos. En general el sistema funcionaba de manera aceptable.

Sí que noté que, de vez en cuando, aparecía una ventana de Ubuntu diciendo que un programa había fallado y que si quería reportarlo. No era ninguno de los que yo estaba usando pero claramente algún programa en segundo plano parecía tener problemas con la falta de AVX.

Finalmente, un día después di con el programa afectado y era uno de los que no menos me esperaba. En mi cabeza los programas que más podrían aprovechar AVX son los que hacen cálculos intensivos: juegos, multimedia, etc. En mi caso me estaba fallando ¡el comando apt!

Errores:

$ sudo apt-get update
[sudo] password for x: 
Hit:1 http://es.archive.ubuntu.com/ubuntu jammy InRelease
Reading package lists... Done                                                                                                                    
E: Method https has died unexpectedly!
E: Sub-process https received signal 4.

Al parecer para conectarse por HTTPS al servidor de paquetes se utiliza GnuTLS y esta librería intenta aprovechar las instrucciones AVX para optimizar sus funciones criptográficas. Según la documentación de GnuTLS podría usar la variable de entorno GNUTLS_CPUID_OVERRIDE=0x1 para desactivar todas las optimizaciones de la librería y solucionar el problema pero a partir de ese momento debería acordarme de definirla cada vez que quisiese usar apt. Un engorro.

Y tampoco sé si hay otros programas en mi sistema o que me instale en un futuro que requieran instrucciones AVX. Para evitar problemas decidí volver a activar AVX. Reinicié el ordenador y esta vez no añadí la configuración en Grub. apt volvía a funcionar con normalidad y lscpu me decía que Gather data sampling no estaba mitigada.

Ahora estoy me estoy pensando los siguientes pasos. Podría cambiarme a una distribución de Linux que compile todo lo que instala como Gentoo o Arch. Simplemente tendría que configurar que no quiero AVX y podría estar seguro de que al desactivarlo en el kernel ningún programa me fuera a fallar inexplicablemente.

De momento, me mantengo con Ubuntu y la vulnerabilidad no mitigada. Mi ordenador no es un sistema tan crítico como para necesitar protegerlo urgentemente y, de todas formas, no me había enterado en todos estos años.

El servidor

Tras investigar y aprender mucho con el portátil. Me puse a mirar si mi servidor de casa, que usa una Raspberry Pi 4, tenía alguna vulnerabilidad. Al ejecutar lscpu muestra la misma lista de vulnerabilidades pero en la mayoría de ellas pone "Not affected". Era lo esperable, al fin y al cabo Raspberry Pi tiene un procesador ARM y la mayoría de estos errores son específicos de las instrucciones Intel.

Para mí sorpresa, de las pocas vulnerabilidades que sí afectaban a ARM, 2 de ellas me aparecen como "Vulnerable". En los próximos días tengo que investigar cómo mitigarlas ya que este servidor está expuesto al mundo.


Artículo siguiente: Mi sistema de notas
Artículo anterior: Adelgazando el feed de este blog