
Exploit para el kernel de Linux 4.1.15 para CVE-2022-42703, que demuestra una vulnerabilidad de escalada de privilegios local con una implementación de prueba de concepto para investigación y educación en seguridad.
Linux kernel release 4.x http://kernel.org/
Estas son las notas de la versión de Linux 4. Léalas con atención, ya que le explican de qué se trata todo esto, 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 grupo disperso de hackers de todo Internet. Su objetivo es cumplir con POSIX y la Especificación Única de Unix.
Tiene todas las características que esperaría en un Unix moderno y completo, incluyendo multitarea real, memoria virtual, bibliotecas compartidas, carga bajo demanda, ejecutables compartidos con copia en escritura, gestión de memoria adecuada y redes multistack que incluyen IPv4 e IPv6.
Se distribuye bajo la Licencia Pública General de GNU; consulte el archivo COPYING adjunto para más detalles.
¿EN QUÉ HARDWARE FUNCIONA?
Aunque originalmente se desarrolló primero para PC basadas en x86 de 32 bits (386 o superior), hoy en día Linux también funciona en (al menos) 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 32 o 64 bits de propósito general siempre que tengan una unidad de gestión de memoria paginada (PMMU) y una versión del compilador GNU C (gcc) (parte de la Colección de Compiladores GNU, GCC). Linux también se ha portado a varias arquitecturas sin PMMU, aunque entonces la funcionalidad 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 forma electrónica en Internet como en libros, tanto específica de Linux como relacionada con preguntas generales de UNIX. Recomiendo consultar los subdirectorios de documentación en cualquier sitio FTP de Linux para los libros del LDP (Proyecto de Documentación de Linux). Este README no pretende ser documentación del sistema: hay fuentes mucho mejores disponibles.
Hay varios archivos README en el subdirectorio Documentation/: estos suelen contener notas de instalación específicas del kernel para algunos controladores, por ejemplo. Consulte Documentation/00-INDEX para obtener 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 renderizar en varios formatos: PostScript (.ps), PDF, HTML y páginas man, entre otros. Después de la instalación, "make psdocs", "make pdfdocs", "make htmldocs" o "make mandocs" renderizarán la documentación en el formato solicitado.
INSTALACIÓN del código fuente del kernel:
Si instala las fuentes completas, coloque el tarball del kernel en un directorio donde tenga permisos (por ejemplo, su directorio home) 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 tiene un conjunto (generalmente incompleto) de encabezados del kernel que son utilizados por los archivos de encabezado de la biblioteca. Deben coincidir con la biblioteca y no ensuciarse con lo que sea que el kernel del día resulte ser.
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, ingrese al 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 mayores que la versión "X" de su árbol fuente actual, en orden, y debería estar bien. Es posible que desee 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 al 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 del kernel 4.0.2 y desea saltar 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 encontrado.
linux/scripts/patch-kernel linux
El primer argumento en el 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 el uso de versiones excesivamente antiguas de estos paquetes puede causar errores indirectos que son muy difíciles de rastrear, así que no asuma que puede simplemente actualizar los paquetes cuando surjan problemas evidentes durante la compilación o la operación.
DIRECTORIO DE COMPILACIÓN para el 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 (incluyendo .config). Ejemplo:
código fuente del kernel: /usr/src/linux-4.X
directorio de compilación: /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 usa la opción 'O=output/dir', entonces debe usarse para todas las invocaciones de make.
CONFIGURACIÓN del kernel:
No se salte este paso incluso si solo está actualizando una versión menor. Se agregan nuevas opciones de configuración en cada lanzamiento, y surgirán problemas extraños si los archivos de configuración no están configurados como se espera. Si desea transferir su configuración existente a una nueva versión con un trabajo mínimo, use "make oldconfig", que solo le pedirá las respuestas a las preguntas nuevas.
Los comandos de configuración alternativos son:
"make config" Interfaz de texto plano.
"make menuconfig" Menús de color basados en texto, listas de opciones y diálogos.
"make nconfig" Menús de color basados en texto mejorados.
"make xconfig" Herramienta de configuración basada en X windows (Qt).
"make gconfig" Herramienta de configuración basada en X windows (Gtk).
"make oldconfig" Responder por defecto a todas las preguntas basadas en el contenido de su archivo ./.config existente y preguntar sobre nuevos símbolos de configuración.
"make silentoldconfig" Como el anterior, pero evita saturar la pantalla con preguntas ya respondidas. Además, actualiza las dependencias.
"make olddefconfig" Como el anterior, pero establece nuevos símbolos a sus valores por defecto sin preguntar.
"make defconfig" Crear 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" Crear 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" Crear un archivo ./.config estableciendo valores de símbolo a 'y' tanto como sea posible.
"make allmodconfig" Crear un archivo ./.config estableciendo valores de símbolo a 'm' tanto como sea posible.
"make allnoconfig" Crear un archivo ./.config estableciendo valores de símbolo a 'n' tanto como sea posible.
"make randconfig" Crear un archivo ./.config estableciendo valores de símbolo a valores aleatorios.
"make localmodconfig" Crear una configuración basada en la configuración actual y los módulos cargados (lsmod). Deshabilita 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áselo 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 más información, consulte Documentation/Changes.
Tenga en cuenta que aún puede ejecutar programas de usuario a.out con este kernel.
Ejecute "make" para crear una imagen de kernel comprimida. También es posible hacer "make install" si tiene lilo instalado para adaptarse a los makefiles del kernel, pero es posible que desee verificar primero su configuración particular de lilo.
Para realizar la instalación real, debe ser root, pero ninguna de las compilaciones normales debería requerirlo. No tome el nombre de root en vano.
Si configuró alguna de las partes del kernel como `módulos', también tendrá que hacer "make modules_install".
Salida detallada 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 esto, 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 la razón de la recompilación de cada objetivo, use "V=2". El valor predeterminado es "V=0".
Mantenga un kernel de respaldo a mano en caso de que algo salga 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 de mantener también una copia de seguridad de los módulos correspondientes a ese kernel. Si está instalando un nuevo kernel 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 hacer "make modules_install".
Alternativamente, antes de compilar, use la opción de configuración del kernel "LOCALVERSION" para agregar un sufijo único a la versión regular del kernel. LOCALVERSION se puede configurar en el menú "Configuración general".
Para arrancar su nuevo kernel, necesitará 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 normal.
Arrancar un kernel directamente desde un disquete sin la ayuda de un gestor de arranque como LILO ya no es compatible.
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. La 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. Luego, 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 en particular asociada con la parte del kernel con la que está teniendo problemas. Si no hay nadie listado allí, entonces la segunda mejor opción 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 está hablando, cómo duplicar el problema y cuál es su configuración (use su sentido común). Si el problema es nuevo, dígamelo, y si el problema es antiguo, por favor intente decirme cuándo lo notó por primera vez.
Si el error resulta en un mensaje como
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 similar de depuración del kernel en su pantalla o en su registro del sistema, por favor duplíquelo exactamente. El volcado puede parecer incomprensible para usted, pero contiene información que puede ayudar a depurar el problema. El texto sobre el volcado también es importante: dice algo sobre por qué el kernel volcó código (en el ejemplo anterior, se debe a un puntero de kernel incorrecto). Más información sobre cómo dar sentido al volcado está 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 (pero compilar con CONFIG_KALLSYMS suele ser preferible). Esta utilidad se puede descargar de ftp://ftp..kernel.org/pub/linux/utils/kernel/ksymoops/ . Alternativamente, puede hacer la búsqueda del volcado manualmente:
En volcados de depuración como el anterior, ayuda enormemente si puede buscar lo que significa el valor EIP. El valor hexadecimal como tal no ayuda mucho a mí ni a nadie más: dependerá de su configuración particular del kernel. Lo que debe hacer es tomar el valor hexadecimal de la línea EIP (ignore el "0010:"), y buscarlo en la lista de nombres del kernel para ver qué función del kernel contiene la dirección ofensiva.
Para encontrar 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 coincidirla con el EIP del fallo del kernel, haga:
nm vmlinux | sort | less
Esto le dará una lista de direcciones del kernel ordenadas en orden ascendente, a partir de la cual es simple encontrar la función que contiene la dirección ofensiva. Tenga en cuenta que la dirección dada por los mensajes de depuración del kernel no necesariamente coincidirá exactamente con las direcciones de las funciones (de hecho, eso es muy improbable), por lo que no puede simplemente 'grep' la lista: la lista, sin embargo, le dará el punto de inicio de cada función del kernel, por lo que al buscar la función que tiene una dirección de inicio más baja que la que está buscando pero es seguida por una función con una dirección más alta, encontrará la que desea. De hecho, puede ser una buena idea incluir un poco de "contexto" en su informe de problema, dando algunas líneas alrededor de la interesante.
"make localyesconfig" Similar a localmodconfig, excepto que convertirá todas las opciones de módulo en opciones integradas (=y).
Puede encontrar más información sobre el uso de las herramientas de configuración del kernel de Linux en Documentation/kbuild/kconfig.txt.
NOTAS sobre "make config":
Tener controladores innecesarios hará que el kernel sea más grande y puede bajo algunas circunstancias provocar problemas: sondear una tarjeta controladora inexistente puede confundir a sus otros controladores.
Compilar el kernel con "Tipo de procesador" establecido superior a 386 resultará en un kernel que NO funciona en un 386. El kernel lo detectará al arrancar y se rendirá.
Un kernel con emulación matemática compilada seguirá utilizando 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 independientemente de si tienen un coprocesador matemático o no.
Los detalles de configuración de "kernel hacking" generalmente resultan en 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 intentar activamente romper código malo para encontrar problemas del kernel (kmalloc()). Por lo tanto, probablemente debería responder 'n' a las preguntas sobre características de "desarrollo", "experimental" o "depuración".
Reinstalar LILO suele ser cuestión de ejecutar /sbin/lilo. Puede que desee editar /etc/lilo.conf para especificar una entrada para su imagen de kernel anterior (por ejemplo, /vmlinux.old) en caso de que la nueva no funcione. Consulte la documentación de LILO para 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 de kernel precompilada o similar), decirme todo lo posible sobre su configuración ayudará. Lea el documento REPORTING-BUGS para más detalles.
Alternativamente, puede usar gdb en un kernel en ejecución. (solo lectura; es decir, no puede cambiar valores ni establecer puntos de interrupción). Para hacer esto, primero compile el kernel con -g; edite arch/i386/Makefile apropiadamente, luego haga "make clean". También necesitará habilitar CONFIG_PROC_FS (a través de "make config").
Después de reiniciar con el nuevo kernel, haga "gdb vmlinux /proc/kcore". Ahora puede usar todos los comandos habituales de gdb. El comando para buscar el punto donde su sistema falló es "l *0xXXXXXXXX". (Reemplace las XXX con el valor EIP).
gdb en un kernel que no se está ejecutando actualmente falla porque gdb (incorrectamente) ignora el desplazamiento inicial para el cual se compila el kernel.