Entorno para desarrollo y hacking del kernel Linux

Antes de empezar a desarrollar o a hacer hacking del kernel Linux es necesario preparar un entorno que nos permita hacer modificaciones en el núcleo, compilarlo y probarlo de forma que no afecte a nuestra máquina de desarrollo (no queremos que un error de programación impida que nuestra máquina vuelva a arrancar). A mí, personalmente me gusta usar una máquina virtual en Qemu, aunque hay diferentes alternativas, como preparar un entorno chroot. Aquí voy a describir como lo hago yo, que por supuesto no tiene por qué ser la mejor manera. Por último, antes de comenzar, señalar que en mi máquina de desarrollo utilizo Ubuntu, por lo que las siguientes instrucciones son directamente aplicables a este sistema operativo (aunque son fácilmente adaptables a cualquier otra distribución Linux).



Necesitamos un directorio de trabajo donde descargar el código fuente y compilarlo. Yo tengo un directorio llamado kerneldev en mi directorio home. Es decir, en /home/alberto/kerneldev.
Seguidamente vamos instalar los paquetes necesarios para poder compilar el kernel ejecutando el siguiente comando desde una consola:

sudo apt-get install fakeroot kernel-wedge build-essential makedumpfile \
kernel-package libncurses5 libncurses5-dev

Para compilar el kernel necesitaremos satisfacer algunas dependencias instalando los paquetes que nos falten, este comando hará el trabajo por nosotros:

sudo apt-get build-dep --no-install-recommends linux-image-$(uname -r)

Para descargar el código fuente, podemos recurrir directamente al repositorio oficial del kernel y descargar la última versión estable, o descargarlo usando la utilidad apt de la siguiente manera.

mkdir ~/kerneldev
mkdir ~/kerneldev/src
cd ~/kerneldev/src
apt-get source linux-image-$(uname -r)
cd linux-$(uname -r)

Podemos crear una configuración nueva o partir de la ya existente en nuestro sistema. La configuración del kernel se guarda en un archivo llamado .config. Para utilizar la misma que la de nuestra máquina de desarrollo hacemos lo siguiente:

cp -vi /boot/config-`uname -r` ~/kerneldev/src/linux-`uname -r`/.config

Si necesitamos hacer cambios en la configuración para adecuar el kernel a nuestras necesidades, podemos utilizar el siguiente comando para lanzar la utilidad de configuración del kernel.

sudo make menuconfig

También podemos usar make config si no queremos usar menús, o editar directamente el archivo .config. En nuestro caso, vamos a desactivar el módulo RTS5139, ya que hay un bug conocido que impide compilarlo correctamente en Ubuntu 12.10.

sed -i s/CONFIG_RTS5139=m/CONFIG_RTS5139=n/ .config

Por fin estamos listos para compilar. Simplemente ejecutamos el comando make. Si nuestro procesador tiene dos o más cores, podemos acelerar la compilación usando el parámetro -j4 (lanza cuatro procesos. Se suelen usar dos por core).

make -j4

Bien, ya tenemos el kernel compilado. Por ahora intacto, ya que no hemos tocado nada. Aun así, es una mala idea probar el kernel en nuestra propia máquina. Si hay algún problema dejarás tu sistema operativo inservible, así que mejor vamos a usar Qemu para virtualizar una máquina en la que probar nuestro flamante kernel.

Instalamos Qemu:

sudo apt-get install qemu kqemu-common

También necesitamos una imagen de un sistema linux ya instalado para Qemu. Vamos a descargar una imagen ya preparada de debian squeeze.

cd ~/kerneldev/
wget http://people.debian.org/~aurel32/qemu/amd64\
/debian_squeeze_amd64_standard.qcow2

Mi sistema es de 64 bits, pero si estas trabajando en 32 bits puedes descargar esta otra versión:

wget http://people.debian.org/~aurel32/qemu/i386\
/debian_squeeze_i386_standard.qcow2

Finalmente, nos resta iniciar la máquina virtual con la imagen de debian de 64 bits, pero usando nuestro nuevo kernel.

qemu-system-x86_64 -boot c -kernel \
~/kerneldev/src/linux-$(uname -r)/arch/x86_64/boot/bzImage \ 
-hda ./debian_squeeze_amd64_standard.qcow2 -append \
"root=/dev/sda1 clock=pit" -net nic,model=e1000 -net user

En caso de usar un kernel de 32 bits:

qemu-system-x86 -boot c -kernel \
~/kerneldev/src/linux-$(uname -r)/arch/i386/boot/bzImage \ 
-hda ./debian_squeeze_i386_standard.qcow2 -append \
"root=/dev/sda1 clock=pit" -net nic,model=e1000 -net user

Tened en cuenta que la password del usuario root es 'root'.

¡Enhorabuena! Hemos compilado y lanzado el kernel en la máquina virtual. Ahora queda la parte más difícil, que es empezar a "jugar" y a trastear con el kernel. Lo que los angloparlantes llaman Kernel hacking. En cualquier caso, si quieres empezar a moverte y navegar por el código fuente del kernel, necesitarás alguna ayuda para no perderte entre tantos ficheros y líneas de código.

Vamos a instalar una utilidad llamada cscope que nos ayudará bastante en nuestras andaduras con el núcleo Linux (también se puede navegar por el código fuente de Linux en http://lxr.linux.no/linux/).

sudo apt-get install cscope

Esta aplicación necesita crear una base de datos con todos los identificadores y archivos del código.

LNX=~/kerneldev/src/linux-$(uname -r)
find  $LNX                                                                \
-path "$LNX/arch/*" ! -path "$LNX/arch/i386*" -prune -o               \
-path "$LNX/include/asm-*" ! -path "$LNX/include/asm-i386*" -prune -o \
-path "$LNX/tmp*" -prune -o                                           \
-path "$LNX/Documentation*" -prune -o                                 \
-path "$LNX/scripts*" -prune -o                                       \
-path "$LNX/drivers*" -prune -o                                       \
-name "*.[chxsS]" -print > ~/kerneldev/cscope.files

cscope -b -q -k

Para entrar en la utilidad cscope ejecutamos el siguiente comando:

cscope -d

Es importante pasar el parámetro -d para que cscope no genere de nuevo la base de datos. Para moverte por los campos pulsa el tabulador y para salir usamos ctrl+d. En la pantalla se mostrará la lista de tipos de búsqueda que se pueden hacer. Son las siguientes:

Find this C symbol:
Find this global definition:
Find functions called by this function:
Find functions calling this function:
Find this text string:
Change this text string:
Find this egrep pattern:
Find this file:
Find files #including this file:

Por ejemplo, si te pones en la línea
Find this C symbol:
e introduces task_struct, podrás ver dónde se define y se usa esta estructura de datos.

Ahora que tenemos listo nuestro entorno de desarrollo para el kernel podemos remangarnos y empezar a tocar sin miedo (pero con respeto). Si quieres saber como modificar el kernel, crear tus propios módulos, controladores de dispositivo, etc, yo no me perdería los próximos artículos.

2 comentarios:

  1. El comando cd linux-$(uname -r) no me funciona. me da un error, me dice que este directorio no existe. Alli tienes las dos lineas de orden, de envio y respuesta:

    administrador@AVM480:~/kerneldev/src$ cd linux-$(uname -r)
    bash: cd: linux-3.11.0-18-generic: No existe el archivo o el directorio

    ResponderEliminar
    Respuestas
    1. Comprueba si existe realmente el directorio linux-3.11.0-18-generic o si tiene otro nombre. Si tiene otro nombre, simplemente escribe: cd [nombre del directorio]

      Eliminar