
Analiza y demuestra la vulnerabilidad del kernel de Linux CVE-2023-28772, proporcionando un kernel parcheado o vulnerable para investigación de seguridad y fines educativos.
Lanzamiento del kernel Linux 4.x http://kernel.org/
Estas son las notas de la versión 4 de Linux. Léelas con atención, ya que te explican de qué va todo, cómo instalar el kernel y qué hacer si algo sale mal.
¿QUÉ ES LINUX?
Linux es un clon del sistema operativo Unix, escrito desde cero por Linus Torvalds con la ayuda de un equipo disperso de hackers de todo Internet. Su objetivo es cumplir con POSIX y la Single UNIX Specification.
Tiene todas las características que cabría esperar de un Unix moderno y completo, incluyendo multitarea real, memoria virtual, bibliotecas compartidas, carga bajo demanda, ejecutables compartidos con copia en escritura, gestión adecuada de memoria y redes multicapa (multistack) que incluyen IPv4 e IPv6.
Se distribuye bajo la Licencia Pública General de GNU (GNU General Public License); consulte el archivo COPYING adjunto para obtener más detalles.
¿EN QUÉ HARDWARE SE EJECUTA?
Aunque originalmente se desarrolló para PC basados en x86 de 32 bits (386 o superiores), hoy Linux también se ejecuta (al menos) en las arquitecturas Compaq Alpha AXP, Sun SPARC y UltraSPARC, Motorola 68000, PowerPC, PowerPC64, ARM, Hitachi SuperH, Cell, IBM S/390, MIPS, HP PA-RISC, Intel IA-64, DEC VAX, AMD x86-64, AXIS CRIS, Xtensa, Tilera TILE, AVR32 y Renesas M32R.
Linux es fácilmente portable a la mayoría de las arquitecturas de propósito general de 32 o 64 bits siempre que tengan una unidad de gestión de memoria paginada (PMMU) y un puerto del compilador GNU C (gcc) (parte de The GNU Compiler Collection, GCC). Linux también se ha portado a varias arquitecturas sin PMMU, aunque la funcionalidad entonces es obviamente algo limitada. Linux también se ha portado a sí mismo. Ahora puede ejecutar el kernel como una aplicación de espacio de usuario; esto se llama UserMode Linux (UML).
DOCUMENTACIÓN:
Hay mucha documentación disponible tanto en formato electrónico en Internet como en libros, tanto específica de Linux como relacionada con cuestiones generales de UNIX. Recomiendo revisar los subdirectorios de documentación en cualquier sitio FTP de Linux para los libros del LDP (Linux Documentation Project). Este README no pretende ser documentación sobre el sistema: hay fuentes mucho mejores disponibles.
Hay varios archivos README en el subdirectorio Documentation/: normalmente contienen notas de instalación específicas del kernel para algunos controladores, por ejemplo. Consulte Documentation/00-INDEX para ver una lista de lo que contiene cada archivo. Lea el archivo Changes, ya que contiene información sobre los problemas que pueden surgir al actualizar su kernel.
El subdirectorio Documentation/DocBook/ contiene varias guías para desarrolladores y usuarios del kernel. Estas guías se pueden generar en varios formatos: PostScript (.ps), PDF, HTML y man-pages, entre otros. Después de la instalación, "make psdocs", "make pdfdocs", "make htmldocs", o "make mandocs" generarán la documentación en el formato solicitado.
INSTALACIÓN DEL CÓDIGO FUENTE DEL KERNEL:
Si instala las fuentes completas, coloque el archivo tar del kernel en un directorio donde tenga permisos (por ejemplo, su directorio personal) y descomprímalo:
xz -cd linux-4.X.tar.xz | tar xvf -
Reemplace "X" con el número de versión del kernel más reciente.
NO utilice el área /usr/src/linux! Esta área contiene un conjunto (generalmente incompleto) de cabeceras del kernel que son utilizadas por los archivos de cabecera de las bibliotecas. Deben coincidir con la biblioteca y no verse alteradas por el kernel de turno que esté presente.
También puede actualizar entre versiones 4.x mediante parches. Los parches se distribuyen en formato xz. Para instalar mediante parches, obtenga todos los archivos de parche más recientes, entre en el directorio de nivel superior del código fuente del kernel (linux-4.X) y ejecute:
xz -cd ../patch-4.x.xz | patch -p1
Reemplace "x" por todas las versiones posteriores a la versión "X" de su árbol de fuentes actual, en orden, y no debería haber problemas. Puede querer eliminar los archivos de respaldo (some-file-name~ o some-file-name.orig) y asegurarse de que no haya parches fallidos (some-file-name# o some-file-name.rej). Si los hay, usted o yo hemos cometido un error.
A diferencia de los parches para los kernels 4.x, los parches para los kernels 4.x.y (también conocidos como kernels -stable) no son incrementales, sino que se aplican directamente sobre el kernel base 4.x. Por ejemplo, si su kernel base es 4.0 y desea aplicar el parche 4.0.3, no debe aplicar primero los parches 4.0.1 y 4.0.2. Del mismo modo, si está ejecutando la versión 4.0.2 del kernel y quiere pasar a 4.0.3, primero debe revertir el parche 4.0.2 (es decir, patch -R) antes de aplicar el parche 4.0.3. Puede leer más sobre esto en Documentation/applying-patches.txt
Alternativamente, el script patch-kernel se puede utilizar para automatizar este proceso. Determina la versión actual del kernel y aplica cualquier parche que encuentre.
linux/scripts/patch-kernel linux
El primer argumento del comando anterior es la ubicación del código fuente del kernel. Los parches se aplican desde el directorio actual, pero se puede especificar un directorio alternativo como segundo argumento.
Asegúrese de que no haya archivos .o obsoletos ni dependencias por ahí:
cd linux make mrproper
Ahora debería tener las fuentes correctamente instaladas.
REQUISITOS DE SOFTWARE
Compilar y ejecutar los kernels 4.x requiere versiones actualizadas de varios paquetes de software. Consulte Documentation/Changes para conocer los números de versión mínimos requeridos y cómo obtener actualizaciones de estos paquetes. Tenga en cuenta que usar versiones excesivamente antiguas de estos paquetes puede causar errores indirectos muy difíciles de rastrear, así que no asuma que basta con actualizar los paquetes cuando surjan problemas evidentes durante la compilación o el funcionamiento.
DIRECTORIO DE COMPILACIÓN DEL KERNEL:
Al compilar el kernel, todos los archivos de salida se almacenarán por defecto junto con el código fuente del kernel. Usar la opción "make O=output/dir" le permite especificar un lugar alternativo para los archivos de salida (incluido .config). Ejemplo:
kernel source code: /usr/src/linux-4.X
build directory: /home/name/build/kernel
Para configurar y compilar el kernel, use:
cd /usr/src/linux-4.X
make O=/home/name/build/kernel menuconfig
make O=/home/name/build/kernel
sudo make O=/home/name/build/kernel modules_install install
Tenga en cuenta: si se utiliza la opción 'O=output/dir', debe usarse en todas las invocaciones de make.
CONFIGURACIÓN DEL KERNEL:
No se salte este paso aunque solo esté actualizando una versión menor. En cada lanzamiento se añaden nuevas opciones de configuración, y aparecerán problemas extraños si los archivos de configuración no están establecidos como se espera. Si desea llevar su configuración existente a una nueva versión con un trabajo mínimo, use "make oldconfig", que solo le preguntará por las respuestas a las nuevas preguntas.
Los comandos de configuración alternativos son:
"make config" Interfaz de texto plano.
"make menuconfig" Menús de color basados en texto, listas de radio y diálogos.
"make nconfig" Menús de color basados en texto mejorados.
"make xconfig" Herramienta de configuración basada en ventanas X (Qt).
"make gconfig" Herramienta de configuración basada en ventanas X (Gtk).
"make oldconfig" Responde por defecto a todas las preguntas basándose en el contenido de su archivo ./.config existente y pregunta sobre los nuevos símbolos de configuración.
"make silentoldconfig" Igual que el anterior, pero evita llenar la pantalla con preguntas ya respondidas. Además actualiza las dependencias.
"make olddefconfig" Igual que el anterior, pero establece los nuevos símbolos a sus valores por defecto sin preguntar.
"make defconfig" Crea un archivo ./.config usando los valores de símbolo por defecto de arch/$ARCH/defconfig o arch/$ARCH/configs/${PLATFORM}_defconfig, dependiendo de la arquitectura.
"make ${PLATFORM}_defconfig" Crea un archivo ./.config usando los valores de símbolo por defecto de arch/$ARCH/configs/${PLATFORM}_defconfig. Use "make help" para obtener una lista de todas las plataformas disponibles de su arquitectura.
"make allyesconfig" Crea un archivo ./.config estableciendo los valores de los símbolos a 'y' tanto como sea posible.
"make allmodconfig" Crea un archivo ./.config estableciendo los valores de los símbolos a 'm' tanto como sea posible.
"make allnoconfig" Crea un archivo ./.config estableciendo los valores de los símbolos a 'n' tanto como sea posible.
"make randconfig" Crea un archivo ./.config estableciendo los valores de los símbolos a valores aleatorios.
"make localmodconfig" Crea una configuración basada en la configuración actual y en los módulos cargados (lsmod). Desactiva cualquier opción de módulo que no sea necesaria para los módulos cargados.
Para crear un localmodconfig para otra máquina, guarde el lsmod
de esa máquina en un archivo y pásalo como parámetro LSMOD.
target$ lsmod > /tmp/mylsmod
target$ scp /tmp/mylsmod host:/tmp
host$ make LSMOD=/tmp/mylsmod localmodconfig
Lo anterior también funciona al compilar de forma cruzada.
COMPILACIÓN DEL KERNEL:
Asegúrese de tener al menos gcc 3.2 disponible. Para obtener más información, consulte Documentation/Changes.
Tenga en cuenta que todavía puede ejecutar programas de usuario a.out con este kernel.
Ejecute "make" para crear una imagen comprimida del kernel. También es posible ejecutar "make install" si tiene lilo instalado para adaptarse a los makefiles del kernel, pero quizá quiera comprobar antes su configuración particular de lilo.
Para realizar la instalación real, debe ser root, pero ninguna de las operaciones normales de compilación debería requerirlo. No tome el nombre de root en vano.
Si configuró alguna de las partes del kernel como `modules', también tendrá que ejecutar "make modules_install".
Salida verbosa de compilación/construcción del kernel:
Normalmente, el sistema de compilación del kernel se ejecuta en un modo bastante silencioso (pero no totalmente silencioso). Sin embargo, a veces usted u otros desarrolladores del kernel necesitan ver los comandos de compilación, enlace u otros exactamente como se ejecutan. Para ello, use el modo de compilación "verbose". Esto se hace insertando "V=1" en el comando "make". Por ejemplo:
make V=1 all
Para que el sistema de compilación también indique el motivo de la reconstrucción de cada objetivo, use "V=2". El valor predeterminado es "V=0".
Tenga a mano un kernel de respaldo por si algo sale mal. Esto es especialmente cierto para las versiones de desarrollo, ya que cada nueva versión contiene código nuevo que no ha sido depurado. Asegúrese también de mantener una copia de seguridad de los módulos correspondientes a ese kernel. Si va a instalar un kernel nuevo con el mismo número de versión que su kernel actual, haga una copia de seguridad de su directorio de módulos antes de ejecutar "make modules_install".
Alternativamente, antes de compilar, use la opción de configuración del kernel "LOCALVERSION" para añadir un sufijo único a la versión normal del kernel. LOCALVERSION se puede establecer en el menú "General Setup".
Para arrancar su nuevo kernel, deberá copiar la imagen del kernel (por ejemplo, .../linux/arch/i386/boot/bzImage después de la compilación) al lugar donde se encuentra su kernel de arranque habitual.
Ya no se admite arrancar un kernel directamente desde un disquete sin la ayuda de un gestor de arranque como LILO.
Si arranca Linux desde el disco duro, es probable que use LILO, que utiliza la imagen del kernel especificada en el archivo /etc/lilo.conf. El archivo de imagen del kernel suele ser /vmlinuz, /boot/vmlinuz, /bzImage o /boot/bzImage. Para usar el nuevo kernel, guarde una copia de la imagen anterior y copie la nueva imagen sobre la anterior. Después, DEBE VOLVER A EJECUTAR LILO para actualizar el mapa de carga. Si no lo hace, no podrá arrancar la nueva imagen del kernel.
SI ALGO SALE MAL:
Si tiene problemas que parecen deberse a errores del kernel, por favor revise el archivo MAINTAINERS para ver si hay una persona concreta asociada con la parte del kernel que le está causando problemas. Si no hay nadie listado allí, lo segundo mejor es enviarlos por correo a mí ([email protected]) y posiblemente a cualquier otra lista de correo relevante o al grupo de noticias.
En todos los informes de errores, por favor indique de qué kernel se trata, cómo reproducir el problema y cuál es su configuración (use su sentido común). Si el problema es nuevo, hágamelo saber, y si es antiguo, por favor intente indicarme cuándo lo notó por primera vez.
Si el error produce un mensaje como el siguiente:
unable to handle kernel paging request at address C0000010 Oops: 0002 EIP: 0010:XXXXXXXX eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx ds: xxxx es: xxxx fs: xxxx gs: xxxx Pid: xx, process nr: xx xx xx xx xx xx xx xx xx xx xx
o información de depuración similar del kernel en su pantalla o en su registro del sistema, reprodúzcala exactamente. El volcado puede parecer incomprensible para usted, pero contiene información que puede ayudar a depurar el problema. El texto que aparece encima del volcado también es importante: indica algo sobre por qué el kernel volcó código (en el ejemplo anterior, se debe a un puntero incorrecto del kernel). Más información sobre cómo interpretar el volcado se encuentra en Documentation/oops-tracing.txt
Si compiló el kernel con CONFIG_KALLSYMS, puede enviar el volcado tal cual; de lo contrario, tendrá que usar el programa "ksymoops" para dar sentido al volcado (aunque normalmente se prefiere compilar con CONFIG_KALLSYMS). Esta utilidad se puede descargar desde ftp://ftp..kernel.org/pub/linux/utils/kernel/ksymoops/ . Alternativamente, puede hacer la búsqueda en el volcado manualmente:
En volcados de depuración como el anterior, ayuda enormemente poder averiguar qué significa el valor EIP. El valor hexadecimal en sí no ayuda mucho a mí ni a nadie: dependerá de su configuración particular del kernel. Lo que debe hacer es tomar el valor hexadecimal de la línea EIP (ignore "0010:"), y buscarlo en la lista de nombres del kernel para ver qué función del kernel contiene la dirección problemática.
Para averiguar el nombre de la función del kernel, necesitará encontrar el binario del sistema asociado con el kernel que mostró el síntoma. Este es el archivo 'linux/vmlinux'. Para extraer la lista de nombres y compararla con el EIP del fallo del kernel, ejecute:
nm vmlinux | sort | less
Esto le dará una lista de direcciones del kernel ordenadas en orden ascendente, a partir de la cual es sencillo encontrar la función que contiene la dirección problemática. Tenga en cuenta que la dirección dada por los mensajes de depuración del kernel no coincidirá necesariamente exactamente con las direcciones de las funciones (de hecho, es muy poco probable), por lo que no puede simplemente hacer 'grep' a la lista: la lista, sin embargo, le dará el punto de inicio de cada función del kernel, así que al buscar la función que tiene una dirección de inicio menor que la que busca pero está seguida de una función con una dirección mayor, encontrará la que desea. De hecho, puede ser una buena idea incluir un poco de "contexto" en su informe de error, dando algunas líneas alrededor de la línea interesante.
"make localyesconfig" Similar a localmodconfig, excepto que convertirá todas las opciones de módulos en opciones integradas (=y).
Puede encontrar más información sobre el uso de las herramientas de configuración del kernel Linux en Documentation/kbuild/kconfig.txt.
NOTAS sobre "make config":
Tener controladores innecesarios hará que el kernel sea más grande, y puede en algunas circunstancias provocar problemas: sondear una tarjeta controladora inexistente puede confundir a sus otros controladores
Compilar el kernel con "Processor type" establecido a un valor superior a 386 dará como resultado un kernel que NO funciona en un 386. El kernel lo detectará en el arranque y se rendirá.
Un kernel con emulación matemática compilada seguirá usando el coprocesador si está presente: la emulación matemática simplemente nunca se usará en ese caso. El kernel será ligeramente más grande, pero funcionará en diferentes máquinas, tengan o no coprocesador matemático.
Los detalles de configuración de "kernel hacking" generalmente dan como resultado un kernel más grande o más lento (o ambos), e incluso pueden hacer que el kernel sea menos estable al configurar algunas rutinas para que intenten activamente romper código malo y encontrar problemas del kernel (kmalloc()). Por lo tanto, probablemente debería responder 'n' a las preguntas sobre las características de "development", "experimental" o "debugging".
Reinstalar LILO normalmente consiste en ejecutar /sbin/lilo. Puede que desee editar /etc/lilo.conf para especificar una entrada para su imagen anterior del kernel (por ejemplo, /vmlinux.old) por si la nueva no funciona. Consulte la documentación de LILO para obtener más información.
Después de reinstalar LILO, todo debería estar listo. Apague el sistema, reinicie y disfrute.
Si alguna vez necesita cambiar el dispositivo raíz predeterminado, el modo de video, el tamaño del ramdisk, etc. en la imagen del kernel, use el programa 'rdev' (o alternativamente las opciones de arranque de LILO cuando corresponda). No es necesario recompilar el kernel para cambiar estos parámetros.
Reinicie con el nuevo kernel y disfrute.
Si por alguna razón no puede hacer lo anterior (tiene una imagen del kernel precompilada o algo similar), contarme todo lo posible sobre su configuración ayudará. Por favor, lea el documento REPORTING-BUGS para más detalles.
Alternativamente, puede usar gdb sobre un kernel en ejecución. (solo lectura; es decir, no puede cambiar valores ni establecer puntos de interrupción.) Para ello, primero compile el kernel con -g; edite arch/i386/Makefile adecuadamente y luego ejecute "make clean". También necesitará habilitar CONFIG_PROC_FS (mediante "make config").
Después de reiniciar con el nuevo kernel, ejecute "gdb vmlinux /proc/kcore". Ahora puede usar todos los comandos habituales de gdb. El comando para buscar el punto donde su sistema se bloqueó es "l *0xXXXXXXXX". (Reemplace las XXX con el valor EIP.)
Usar gdb con un kernel que no está en ejecución actualmente falla porque gdb (erróneamente) ignora el desplazamiento inicial para el que está compilado el kernel.