
Código fuente del kernel de Linux 4.1.15 con enfoque en CVE-2022-45934, que proporciona una referencia para análisis de vulnerabilidades e investigación de explotación.
Versión del kernel Linux 4.x http://kernel.org/
Estas son las notas de la versión para Linux versión 4. Léelas con atención, ya que te explican de qué va 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 equipo poco cohesionado de hackers de toda la Red. Su objetivo es cumplir con POSIX y con 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, una gestión de memoria adecuada y redes de múltiples pilas, incluyendo IPv4 e IPv6.
Se distribuye bajo la Licencia Pública General de GNU; consulta el archivo COPYING adjunto para más detalles.
¿EN QUÉ HARDWARE SE EJECUTA?
Aunque originalmente se desarrolló primero para PCs basados en x86 de 32 bits (386 o superiores), hoy en día Linux también se ejecuta 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 propósito general de 32 o 64 bits, siempre que tengan una unidad de gestión de memoria paginada (PMMU) y un port del compilador GNU C (gcc) (parte de The GNU Compiler Collection, GCC). Linux también ha sido portado a varias arquitecturas sin PMMU, aunque en ese caso la funcionalidad es evidentemente algo limitada. Linux también ha sido portado a sí mismo. Ahora puedes 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 relativa a cuestiones generales de UNIX. Recomendaría revisar los subdirectorios de documentación de cualquier sitio FTP de Linux para encontrar 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. Consulta Documentation/00-INDEX para ver una lista de lo que contiene cada archivo. Por favor, lee el archivo Changes, ya que contiene información sobre los problemas que pueden surgir al actualizar tu 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 páginas man, entre otros. Tras la instalación, "make psdocs", "make pdfdocs", "make htmldocs" o "make mandocs" generarán la documentación en el formato solicitado.
INSTALANDO EL CÓDIGO FUENTE DEL KERNEL:
Si instalas las fuentes completas, coloca el tarball del kernel en un directorio donde tengas permisos (p. ej., tu directorio personal) y descomprímelo:
xz -cd linux-4.X.tar.xz | tar xvf -
Sustituye "X" por el número de versión del kernel más reciente.
¡NO uses el área /usr/src/linux! Esta área contiene un conjunto (normalmente incompleto) de cabeceras del kernel que utilizan los archivos de cabecera de las bibliotecas. Deben coincidir con la biblioteca y no deben verse alteradas por el kernel que esté de turno (kernel-du-jour).
También puedes actualizar entre versiones 4.x aplicando parches. Los parches se distribuyen en formato xz. Para instalar mediante parches, consigue todos los archivos de parche más recientes, entra en el directorio de nivel superior del código fuente del kernel (linux-4.X) y ejecuta:
xz -cd ../patch-4.x.xz | patch -p1
Sustituye "x" por todas las versiones posteriores a la versión "X" de tu árbol de fuentes actual, en orden, y todo debería ir bien. Puede que quieras eliminar los archivos de respaldo (some-file-name~ o some-file-name.orig) y asegurarte de que no haya parches fallidos (some-file-name# o some-file-name.rej). Si los hay, o tú 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 tu kernel base es 4.0 y quieres aplicar el parche 4.0.3, no debes aplicar primero los parches 4.0.1 y 4.0.2. Del mismo modo, si estás ejecutando la versión 4.0.2 del kernel y quieres saltar a la 4.0.3, primero debes revertir el parche 4.0.2 (es decir, patch -R) antes de aplicar el parche 4.0.3. Puedes 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úrate de que no queden archivos .o obsoletos ni dependencias por ahí:
cd linux make mrproper
Ahora deberías tener las fuentes correctamente instaladas.
REQUISITOS DE SOFTWARE
Compilar y ejecutar los kernels 4.x requiere versiones actualizadas de varios paquetes de software. Consulta Documentation/Changes para conocer los números de versión mínimos necesarios y cómo obtener actualizaciones de estos paquetes. Ten cuidado: el uso de versiones excesivamente antiguas de estos paquetes puede provocar errores indirectos muy difíciles de rastrear, así que no des por sentado que basta con actualizar los paquetes cuando surjan problemas evidentes durante la compilación o el funcionamiento.
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. El uso de la opción "make O=output/dir" permite especificar una ubicación alternativa 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, usa:
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
Por favor, ten en cuenta: si se utiliza la opción 'O=output/dir', debe usarse en todas las invocaciones de make.
CONFIGURANDO EL KERNEL:
No te saltes este paso, aunque solo estés actualizando una versión menor. En cada versión 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 quieres trasladar tu configuración existente a una nueva versión con el mínimo esfuerzo, usa "make oldconfig", que solo te 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 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 tu archivo ./.config existente y pregunta por los nuevos símbolos de configuración.
"make silentoldconfig" Igual que el anterior, pero evita saturar la pantalla con preguntas ya respondidas. Además, actualiza las dependencias.
"make olddefconfig" Igual que el anterior, pero establece los nuevos símbolos en 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 de arch/$ARCH/configs/${PLATFORM}_defconfig, según la arquitectura.
"make ${PLATFORM}_defconfig" Crea un archivo ./.config usando los valores de símbolo por defecto de arch/$ARCH/configs/${PLATFORM}_defconfig. Usa "make help" para obtener una lista de todas las plataformas disponibles de tu arquitectura.
"make allyesconfig" Crea un archivo ./.config estableciendo los valores de los símbolos en 'y' tanto como sea posible.
"make allmodconfig" Crea un archivo ./.config estableciendo los valores de los símbolos en 'm' tanto como sea posible.
"make allnoconfig" Crea un archivo ./.config estableciendo los valores de los símbolos en 'n' tanto como sea posible.
"make randconfig" Crea un archivo ./.config estableciendo los valores de los símbolos en 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, guarda 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.
COMPILANDO EL KERNEL:
Asegúrate de tener disponible al menos gcc 3.2. Para más información, consulta Documentation/Changes.
Ten en cuenta que aún puedes ejecutar programas de usuario a.out con este kernel.
Ejecuta "make" para crear una imagen comprimida del kernel. También es posible hacer "make install" si tienes lilo instalado de forma adecuada para los makefiles del kernel, pero quizá quieras comprobar antes tu configuración particular de lilo.
Para realizar la instalación en sí, tienes que ser root, pero ninguna de las fases normales de compilación debería requerirlo. No tomes el nombre de root en vano.
Si configuraste alguna de las partes del kernel como `modules', también tendrás que ejecutar "make modules_install".
Salida verbosa de compilación/construcción del kernel:
Normalmente, el sistema de compilación del kernel funciona en un modo bastante silencioso (pero no totalmente). Sin embargo, a veces tú u otros desarrolladores del kernel necesitan ver los comandos de compilación, enlazado u otros exactamente tal como se ejecutan. Para ello, usa el modo de compilación "verbose" (verboso). Esto se hace insertando "V=1" en el comando "make". P. ej.:
make V=1 all
Para que el sistema de compilación también indique el motivo de la reconstrucción de cada objetivo, usa "V=2". El valor por defecto es "V=0".
Ten a mano un kernel de respaldo por si algo sale mal. Esto es especialmente cierto en las versiones de desarrollo, ya que cada nueva versión contiene código nuevo que no ha sido depurado. Asegúrate también de mantener una copia de respaldo de los módulos correspondientes a ese kernel. Si vas a instalar un kernel nuevo con el mismo número de versión que tu kernel en funcionamiento, haz una copia de respaldo de tu directorio de módulos antes de ejecutar "make modules_install".
Alternativamente, antes de compilar, usa 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 tu nuevo kernel, tendrás que copiar la imagen del kernel (p. ej., .../linux/arch/i386/boot/bzImage después de la compilación) al lugar donde se encuentra tu kernel arrancable habitual.
Arrancar un kernel directamente desde un disquete sin la ayuda de un gestor de arranque como LILO ya no está soportado.
Si arrancas Linux desde el disco duro, lo más probable es que uses 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, guarda una copia de la imagen anterior y copia la nueva imagen sobre la antigua. Después, DEBES VOLVER A EJECUTAR LILO para actualizar el mapa de carga!! Si no lo haces, no podrás arrancar la nueva imagen del kernel.
SI ALGO SALE MAL:
Si tienes problemas que parecen deberse a errores del kernel, por favor consulta el archivo MAINTAINERS para ver si hay una persona concreta asociada a la parte del kernel con la que tienes 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 indica de qué kernel estás hablando, cómo reproducir el problema y cuál es tu configuración (usa tu sentido común). Si el problema es nuevo, dímelo; y si el problema es antiguo, intenta decirme cuándo lo notaste por primera vez.
Si el error produce 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 de depuración del kernel similar en tu pantalla o en el registro del sistema, por favor reprodúcela exactamente. El volcado puede parecerte incomprensible, pero contiene información que puede ayudar a depurar el problema. El texto que hay encima del volcado también es importante: indica algo sobre por qué el kernel volcó el código (en el ejemplo anterior, se debe a un puntero de kernel incorrecto). Más información sobre cómo interpretar el volcado está en Documentation/oops-tracing.txt
Si compilaste el kernel con CONFIG_KALLSYMS, puedes enviar el volcado tal cual; de lo contrario, tendrás que usar el programa "ksymoops" para dar sentido al volcado (pero normalmente se prefiere compilar con CONFIG_KALLSYMS). Esta utilidad se puede descargar de ftp://ftp..kernel.org/pub/linux/utils/kernel/ksymoops/ . Alternativamente, puedes hacer la consulta del volcado manualmente:
En volcados de depuración como el anterior, ayuda enormemente poder consultar qué significa el valor EIP. El valor hexadecimal en sí no me ayuda mucho a mí ni a nadie más: dependerá de tu configuración particular del kernel. Lo que debes hacer es tomar el valor hexadecimal de la línea EIP (ignora el "0010:") y buscarlo en la lista de nombres (namelist) 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, tendrás que encontrar el binario del sistema asociado al 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, haz:
nm vmlinux | sort | less
Esto te dará una lista de direcciones del kernel ordenadas de forma ascendente, a partir de la cual es sencillo encontrar la función que contiene la dirección problemática. Ten en cuenta que la dirección proporcionada por los mensajes de depuración del kernel no coincidirá necesariamente de forma exacta con las direcciones de las funciones (de hecho, es muy poco probable), así que no puedes simplemente hacer 'grep' en la lista: sin embargo, la lista te dará el punto de inicio de cada función del kernel, así que, buscando la función que tiene una dirección de inicio inferior a la que buscas pero que está seguida de una función con una dirección superior, encontrarás la que quieres. De hecho, puede ser una buena idea incluir un poco de "contexto" en tu informe del problema, dando unas pocas líneas alrededor de la interesante.
"make localyesconfig" Similar a localmodconfig, excepto que convertirá todas las opciones de módulo en opciones integradas (=y).
Puedes 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: la detección (probing) de una tarjeta controladora inexistente puede confundir a tus otros controladores
Compilar el kernel con el "Processor type" (tipo de procesador) establecido en un valor superior a 386 dará como resultado un kernel que NO funciona en un 386. El kernel detectará esto al arrancar y se rendirá.
Un kernel con emulación matemática (math-emulation) compilada seguirá usando el coprocesador si está presente: la emulación matemática simplemente nunca se utilizará 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" normalmente 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 defectuoso con el fin de encontrar problemas en el kernel (kmalloc()). Por lo tanto, probablemente deberías responder 'n' a las preguntas sobre las funciones "development" (desarrollo), "experimental" o "debugging" (depuración).
Reinstalar LILO normalmente consiste en ejecutar /sbin/lilo. Puede que quieras editar /etc/lilo.conf para especificar una entrada para tu imagen anterior del kernel (por ejemplo, /vmlinux.old) por si la nueva no funciona. Consulta la documentación de LILO para más información.
Después de reinstalar LILO, todo debería estar listo. Apaga el sistema, reinicia y ¡disfruta!
Si alguna vez necesitas cambiar el dispositivo raíz predeterminado, el modo de video, el tamaño del ramdisk, etc. en la imagen del kernel, usa el programa 'rdev' (o, alternativamente, las opciones de arranque de LILO cuando corresponda). No es necesario recompilar el kernel para cambiar estos parámetros.
Reinicia con el nuevo kernel y disfruta.
Si por alguna razón no puedes hacer lo anterior (tienes una imagen de kernel precompilada o algo similar), contarme todo lo posible sobre tu configuración ayudará. Por favor, lee el documento REPORTING-BUGS para más detalles.
Alternativamente, puedes usar gdb sobre un kernel en ejecución. (solo lectura; es decir, no puedes cambiar valores ni establecer puntos de interrupción.) Para hacer esto, primero compila el kernel con -g; edita arch/i386/Makefile de forma apropiada y luego ejecuta "make clean". También necesitarás habilitar CONFIG_PROC_FS (mediante "make config").
Después de reiniciar con el nuevo kernel, ejecuta "gdb vmlinux /proc/kcore". Ahora puedes usar todos los comandos habituales de gdb. El comando para buscar el punto donde se produjo el fallo de tu sistema es "l *0xXXXXXXXX". (Sustituye las XXX por el valor EIP.)
Usar gdb sobre 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.