Академический Документы
Профессиональный Документы
Культура Документы
QUE VAMOS A CONOCER? * Como compilar un Kernel Vanilla. * Como compilar un Kernel Vanilla. * Que son las syscalls y como utilizarlas. * Que son las syscalls y como utilizarlas. * Que son los modulos y cuales son los tipos * Que son los modulos y cuales son los tipos de modulos. de modulos. * Ejemplo basico de un modulo. * Ejemplo basico de un modulo. * Registro y operaciones de un modulo. * Registro y operaciones de un modulo. * Estructura del codigo fuente del kernel. * Estructura del codigo fuente del kernel.
Conocimientos previos
* Comandos basicos de Linux. * Comandos basicos de Linux. * Lenguaje C, assembler inline. * Lenguaje C, assembler inline. * * Arquitectura Arquitectura computador. computador. o o componentes componentes del del
CONCEPTOS BASICOS
Hacking Hacking Conocer el funcionamiento interno de un sistema, Conocer el funcionamiento interno de un sistema, en particular en particular de computadoras y redes de computadoras y redes informticas. informticas. Kernel o nucleo Kernel o nucleo El kernel de un sistema operativo, es un programa El kernel de un sistema operativo, es un programa encargado de administrar los recursos de un encargado de administrar los recursos de un sistema. Ejemplo: Administracin de la memoria, sistema. Ejemplo: Administracin de la memoria, administrador de discos, etc. administrador de discos, etc.
CONCEPTOS BASICOS
Modo usuario (user mode): En modo usuario se Modo usuario (user mode): En modo usuario se prohibe el uso de ciertas instrucciones consideradas prohibe el uso de ciertas instrucciones consideradas privilegiadas. Un proceso de usuario no puede acceder privilegiadas. Un proceso de usuario no puede acceder a los puertos de E/S ni capturar interrupciones. a los puertos de E/S ni capturar interrupciones. Modo kernel (kernel mode): En modo kernel el CPU Modo kernel (kernel mode): En modo kernel el CPU permite la ejecucin de todas las instrucciones permite la ejecucin de todas las instrucciones mquina, es posible acceder a todas las direcciones mquina, es posible acceder a todas las direcciones de memoria, programar los perifricos. de memoria, programar los perifricos.
CONCEPTOS BASICOS
ACCESO RESTRINGIDO
MODO USUARIO
MODO KERNEL
ACCESO TOTAL
HARDWARE
HERRAMIENTAS NECESARIAS
$ sudo apt-get install build-essential wget bzip2 $ sudo apt-get install build-essential wget bzip2 kernel-package libncurses-dev fakeroot kernel-package libncurses-dev fakeroot modulemoduleinit-tools init-tools
$ wget -C http://www.kernel.org/pub/linux/kernel/ $ wget -C http://www.kernel.org/pub/linux/kernel/ v2.6/linux-2.6.37.tar.bz2 v2.6/linux-2.6.37.tar.bz2
RECOPILANDO INFORMACION
** Manual de la tarjeta madre. Abrir el gabinete Manual de la tarjeta madre. Abrir el gabinete del PC y tomar nota de los componentes. del PC y tomar nota de los componentes.
$ lspci -v -t $ lspci -v -t $ lsusb $ lsusb $ lsmod $ lsmod $ cat /proc/cpuinfo $ cat /proc/cpuinfo $ cat /proc/meminfo $ cat /proc/meminfo $ cat /proc/partitions $ cat /proc/partitions
COMPILANDO EL KERNEL # cp linux-2.6.37.tar.bz2 /usr/src/ # cp linux-2.6.37.tar.bz2 /usr/src/ # tar -xjf linux-2.6.37.tar.bz2 # tar -xjf linux-2.6.37.tar.bz2 # cd /usr/src/linux-2.6.37 # cd /usr/src/linux-2.6.37 # cp /boot/config-$(uname -r) .config # cp /boot/config-$(uname -r) .config # make menuconfig # make menuconfig
COMPILANDO EL KERNEL
COMPILANDO EL KERNEL
Configurar el kernel para cargar y descargar Configurar el kernel para cargar y descargar modulos modulos
COMPILANDO EL KERNEL
Guardamos las modificaciones realizadas Guardamos las modificaciones realizadas
Podemos seleccionar el archivo de configuracion para la Podemos seleccionar el archivo de configuracion para la arquitectura x86 32 bits en arch/x86/configs/i386_defconfig arquitectura x86 32 bits en arch/x86/configs/i386_defconfig
COMPILANDO EL KERNEL
-initrd -initrd
Puedes compilar la documentacion del kernel en Puedes compilar la documentacion del kernel en varios formatos. Para mas informacion ejecuta el varios formatos. Para mas informacion ejecuta el comando make help. comando make help.
VERIFICANDO ERRORES $ dmesg || grep "Err" $ dmesg grep "Err" $ dmesg || grep "warning" $ dmesg grep "warning" $ dmesg || grep "fail" $ dmesg grep "fail"
Este error se debe a que el archivo utsrelease.h ha sido cambiado de lugar, ahora se encuentra en include/generated/utsrelease.h
El numero de syscalls definidas se encuentra en la El numero de syscalls definidas se encuentra en la constante NR_syscalls en el fichero unistd_32.h constante NR_syscalls en el fichero unistd_32.h
Para ver las syscalls que utiliza un proceso Para ver las syscalls que utiliza un proceso utiliza el comando strace. utiliza el comando strace.
**Tambien se puede escribir directamente el nombre de la syscall Tambien se puede escribir directamente el nombre de la syscall
(sin __NR_): (sin __NR_): caracteres = write(1, msg, strlen(msg)); caracteres = write(1, msg, strlen(msg));
Se puede utilizar la funcion perror() definida en stdio.h, para Se puede utilizar la funcion perror() definida en stdio.h, para obtener los mensajes de error. La variable global errno esta obtener los mensajes de error. La variable global errno esta definida en errno.h en la libreria estandar C. definida en errno.h en la libreria estandar C.
int pid; int pid; int main() {{ int main() __asm__( __asm__( "movl $20, %eax \n" // numero de la syscall (20 getpid) "movl $20, %eax \n" // numero de la syscall (20 getpid) "int $0x80 \n" // interrupcion 0x80, llama a la syscall "int $0x80 \n" // interrupcion 0x80, llama a la syscall "movl %eax, pid \n" // en eax queda el valor devuelto "movl %eax, pid \n" // en eax queda el valor devuelto ); ); printf("El pid del proceso es: %d\n", pid); printf("El pid del proceso es: %d\n", pid); return 0; return 0; }}
En los procesadores actuales, esta habilitado la instruccion SYSENTER En los procesadores actuales, esta habilitado la instruccion SYSENTER para ejecutar una syscall. Si la syscall recibe parametros, estos se para ejecutar una syscall. Si la syscall recibe parametros, estos se deben colocar en los registros %ebx, %ecx, %edx, %esi yy%edi. deben colocar en los registros %ebx, %ecx, %edx, %esi %edi.
KERNEL KERNEL
(Lista doblemente enlazada del kernel) (Lista doblemente enlazada del kernel) FUNCIONES EXPORTADAS FUNCIONES EXPORTADAS
modulo
insmod insmod
modulo
rmmod rmmod
MANEJO DE MODULOS
# insmod mimodulo.ko // carga un modulo # insmod mimodulo.ko // carga un modulo # rmmod mimodulo.ko // descarga un modulo # rmmod mimodulo.ko // descarga un modulo
# modinfo mimodulo.ko // muestra informacion sobre un # modinfo mimodulo.ko // muestra informacion sobre un modulo modulo # modprobe # modprobe
dependencias dependencias
// carga y descarga modulos junto con sus // carga y descarga modulos junto con sus
# lsmod # lsmod
// lista todos los modulos cargados // lista todos los modulos cargados
Existe el comando depmod que se utiliza para definir un archivo Existe el comando depmod que se utiliza para definir un archivo de dependencia de modulos. de dependencia de modulos.
TIPOS DE MODULOS
Existen diferentes formas en los cuales el kernel Existen diferentes formas en los cuales el kernel intercambia informacion con el hardware, estas se pueden intercambia informacion con el hardware, estas se pueden clasificar en: clasificar en: **Character Device: Maneja los datos en flujos de Character Device: Maneja los datos en flujos de bytes. bytes.
1110010101011010100110100
KERNEL
1110010101011010100110100
HARDWARE
Los dispositivos de caracter se denotan con la palabra c, Los dispositivos de caracter se denotan con la palabra c, en /dev. en /dev.
TIPOS DE MODULOS
**Block Device: Maneja los datos en bloques de bytes. Block Device: Maneja los datos en bloques de bytes.
01010 10101 10110 01010 10101 10110 01010 10101 10110
KERNEL
01010 10101 10110 01010 10101 10110 01010 10101 10110
HARDWARE
Los dispositivos de bloque se denotan con la palabra b, Los dispositivos de bloque se denotan con la palabra b, en /dev. en /dev.
TIPOS DE MODULOS
# ls -l /dev # ls -l /dev crw------- 1 root crw------- 1 root video video agpgart agpgart crw-rw---- 1 root audio 14, crw-rw---- 1 root audio 14, 10, 175 2011-03-24 10:30 10, 175 2011-03-24 10:30 4 2011-03-24 10:30 audio 4 2011-03-24 10:30 audio
.. .. .. ..
brw-rw---- 1 root disk brw-rw---- 1 root disk brw-rw---- 1 root disk brw-rw---- 1 root disk brw-rw---- 1 root disk brw-rw---- 1 root disk
8, 0 2011-03-24 06:00 sda 8, 0 2011-03-24 06:00 sda 8, 1 2011-03-24 06:00 sda1 8, 1 2011-03-24 06:00 sda1 8, 2 2011-03-24 06:00 sda2 8, 2 2011-03-24 06:00 sda2
Los dispositivos de caracter yybloque no son las unicas categorias Los dispositivos de caracter bloque no son las unicas categorias que administra el kernel. Las tarjetas de red ocupan una posicion que administra el kernel. Las tarjetas de red ocupan una posicion especial en el kernel. especial en el kernel.
Se
utiliza
para
identificar
un
tty0
brw-rw---- 1 root brw-rw---- 1 root brw-rw---- 1 root brw-rw---- 1 root brw-rw---- 1 root brw-rw---- 1 root crw--w---- 1 root crw--w---- 1 root crw------- 1 root crw------- 1 root
disk disk disk disk disk disk root root root root
8, 8, 8, 8, 8, 8, 4, 4, 4, 4,
0 2011-03-24 17:11 sda 0 2011-03-24 17:11 sda 1 2011-03-24 17:11 sda1 1 2011-03-24 17:11 sda1 2 2011-03-24 17:11 sda2 2 2011-03-24 17:11 sda2 0 2011-03-24 17:11 tty0 0 2011-03-24 17:11 tty0 1 2011-03-24 21:41 tty1 1 2011-03-24 21:41 tty1
En Documentation/devices.txt puedes ver los nombres de los En Documentation/devices.txt puedes ver los nombres de los dispositivos, sda se refiere a un dispositivo SCSI. dispositivos, sda se refiere a un dispositivo SCSI.
para
identificar
Minor Minor Number Number
los
0 1 2
tty0 tty1
brw-rw---- 1 root brw-rw---- 1 root brw-rw---- 1 root brw-rw---- 1 root brw-rw---- 1 root brw-rw---- 1 root crw--w---- 11root crw--w---- root crw------- 1 root crw------- 1 root
disk disk disk disk disk disk root root root root
8, 8, 8, 8, 8, 8, 4, 4, 4, 4,
0 2011-03-24 17:11 sda 0 2011-03-24 17:11 sda 1 2011-03-24 17:11 sda1 1 2011-03-24 17:11 sda1 2 2011-03-24 17:11 sda2 2 2011-03-24 17:11 sda2 0 2011-03-24 17:11 tty0 0 2011-03-24 17:11 tty0 1 2011-03-24 21:41 tty1 1 2011-03-24 21:41 tty1
Para obtener el Major yy Minor number se utilizan las macros Para obtener el Major Minor number se utilizan las macros MAJOR(dev_t dev) yy MINOR(dev_t dev), definidas en MAJOR(dev_t dev) MINOR(dev_t dev), definidas en include/linux/kdev_t.h. include/linux/kdev_t.h.
ESTRUCTURA DE UN MODULO
#include <linux/init.h> #include <linux/init.h> #include <linux/module.h> #include <linux/module.h> ////macros para el inicio yysalida de modulos macros para el inicio salida de modulos ////necesario para modulos necesario para modulos
MODULE_LICENSE("Dual BSD/GPL"); ////tipo de licencia MODULE_LICENSE("Dual BSD/GPL"); tipo de licencia MODULE_AUTHOR("z3r0d4y"); ////author del modulo MODULE_AUTHOR("z3r0d4y"); author del modulo MODULE_DESCRIPTION("Modulo de prueba"); ////descripcion MODULE_DESCRIPTION("Modulo de prueba"); descripcion MODULE_VERSION("Version 1.0"); ////version del modulo MODULE_VERSION("Version 1.0"); version del modulo ////funcion de entrada funcion de entrada int hola_mundo() { { int hola_mundo() printk(KERN_INFO "Hola Mundo desde un Modulo Linux\n"); printk(KERN_INFO "Hola Mundo desde un Modulo Linux\n"); return 0; return 0; }} ////funcion de salida funcion de salida void adios_mundo() { { void adios_mundo() printk(KERN_INFO "Adios Mundo desde un modulo Linux\n"); printk(KERN_INFO "Adios Mundo desde un modulo Linux\n"); }} module_init(hola_mundo); module_init(hola_mundo); module_exit(adios_mundo); module_exit(adios_mundo); ////definimos cual es la funcion de entrada definimos cual es la funcion de entrada ////definimos cual es la funcion de salida definimos cual es la funcion de salida
ESTRUCTURA DE UN MODULO
**Debido a que el kernel se ejecuta sobre si mismo debe definir sus Debido a que el kernel se ejecuta sobre si mismo debe definir sus propias funciones: propias funciones:
printk(KERN_INFO "Hola Mundo desde un Modulo Linux\n"); printk(KERN_INFO "Hola Mundo desde un Modulo Linux\n");
**Para pasarle un valor a un modulo se debe definir la variable Para pasarle un valor a un modulo se debe definir la variable como static: como static:
#include <linux/moduleparam.h> #include <linux/moduleparam.h> #include <linux/stat.h> #include <linux/stat.h> . .. .. . static int parametro_modulo ==1; static int parametro_modulo 1; module_param(parametro_modulo, int, S_IRUGO); module_param(parametro_modulo, int, S_IRUGO); . .. .. . printk(KERN_INFO El valor pasado es: %d,parametro_modulo); printk(KERN_INFO El valor pasado es: %d,parametro_modulo); ##insmod mimodulo.ko parametro_modulo=20 insmod mimodulo.ko parametro_modulo=20
Los loglevels del kernel estan definidos en linux/printk.h. Las Los loglevels del kernel estan definidos en linux/printk.h. Las constantes de permiso de un archivo estan definidas en linux/stat.h constantes de permiso de un archivo estan definidas en linux/stat.h
ESTRUCTURA DE UN MODULO
**Exportar simbolos de un modulo: Exportar simbolos de un modulo:
#include mimodulo.h #include mimodulo.h . .. .. .. . void Compartir(void) void Compartir(void) {{ printk(KERN_INFO Esta funcion va aaser compartida con el Kernel); printk(KERN_INFO Esta funcion va ser compartida con el Kernel); }} EXPORT_SYMBOL(Compartir); EXPORT_SYMBOL(Compartir); #include mimodulo.h #include mimodulo.h . .. .. .. . void Compartir(); void Compartir();
** Al compilar un modulo se generara un archivo llamado Al compilar un modulo se generara un archivo llamado Module.symvers, este archivo almacena las direcciones yyruta de los Module.symvers, este archivo almacena las direcciones ruta de los simbolos exportados. simbolos exportados. Las funciones exportadas se pueden ver en /proc/kallsysms. Las funciones exportadas se pueden ver en /proc/kallsysms.
**Luego de reservar el numero del dispositivo, se debe eliminar Luego de reservar el numero del dispositivo, se debe eliminar este registro para que otro controlador pueda utilizarlo. este registro para que otro controlador pueda utilizarlo.
El comando mknod crea un fichero especial de un modulo. El comando mknod crea un fichero especial de un modulo.
dev_t Driver; ////almacena el Major yyMinor number del dispositivo dev_t Driver; almacena el Major Minor number del dispositivo ////registramos el major number del modulo en /proc/devices registramos el major number del modulo en /proc/devices int iniciar_modulo() { { int iniciar_modulo() Driver ==MKDEV(MAJOR_DRIVER, MINOR_DRIVER); ////Inicia dev_t Driver MKDEV(MAJOR_DRIVER, MINOR_DRIVER); Inicia dev_t return register_chrdev_region(Driver, 1, Mi_Driver); return register_chrdev_region(Driver, 1, Mi_Driver); }} ////liberamos el modulo registrado liberamos el modulo registrado void finalizar_modulo() { { void finalizar_modulo() unregister_chrdev_region(Driver, 1); unregister_chrdev_region(Driver, 1); }} module_init(iniciar_modulo); module_init(iniciar_modulo); module_exit(finalizar_modulo); module_exit(finalizar_modulo); ////funcion de entrada funcion de entrada ////funcion de salida funcion de salida
**Se debe indicar al kernel las operaciones que puede realizar Se debe indicar al kernel las operaciones que puede realizar el modulo a traves de la estructura file_operations definida en el modulo a traves de la estructura file_operations definida en linux/fs.h. linux/fs.h.
ssize_t MiDriver_read(struct file *fOps, char __user *buff, size_t count, loff_t *pOff) ssize_t MiDriver_read(struct file *fOps, char __user *buff, size_t count, loff_t *pOff) {{ ////Realizar Operaciones de lectura Realizar Operaciones de lectura return 0; return 0; }} struct file_operations OperacionesDriver =={ { struct file_operations OperacionesDriver .owner ==THIS_MODULE, ////Puntero hacia la estructura del modulo .owner THIS_MODULE, Puntero hacia la estructura del modulo .read ==MiDriver_read, ////Lee datos del dispositivo .read MiDriver_read, Lee datos del dispositivo .write ==MiDriver_write, ////Escribe datos al dispositivo .write MiDriver_write, Escribe datos al dispositivo
. .. .. .
. .. .. .
////Primera operacion del dispositivo Primera operacion del dispositivo ////Libera al dispositivo Libera al dispositivo
Existen diferentes formas de registrar un modulo yy depende del Existen diferentes formas de registrar un modulo depende del tipo de modulo a crear. tipo de modulo a crear.
COMPILACION DE UN MODULO
**Un modulo se puede compilar con el siguiente Makefile generico: Un modulo se puede compilar con el siguiente Makefile generico:
obj +:= modulo1.o, modulo2.o ////aqui podemos agregar los archivos obj necesarios obj +:= modulo1.o, modulo2.o aqui podemos agregar los archivos obj necesarios all: all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
Se puede ver los mensajes de la funcion printk, utilizando el Se puede ver los mensajes de la funcion printk, utilizando el comando dmesg o en la ruta /var/log/syslog comando dmesg o en la ruta /var/log/syslog
(CODIGO DEL KERNEL, SCHEDULER, CPU, ETC) (CODIGO DEL KERNEL, SCHEDULER, CPU, ETC) (ADMINISTRACION DE LA MEMORIA) (ADMINISTRACION DE LA MEMORIA) (PROTOCOLOS DE RED, BLUETOOTH, ETC) (PROTOCOLOS DE RED, BLUETOOTH, ETC)
CONCLUSIONES
** Entender el funcionamiento interno del kernel no es una tarea Entender el funcionamiento interno del kernel no es una tarea facil ya que se requiere de un cierto conocimiento de sistemas facil ya que se requiere de un cierto conocimiento de sistemas operativos y de la comunicacion de este con el hardware. operativos y de la comunicacion de este con el hardware. **Puedes empezar entendiendo yydesarrollando modulos o realizar Puedes empezar entendiendo desarrollando modulos o realizar pequeas modificaciones al kernel. Por ejemplo: definir una nueva pequeas modificaciones al kernel. Por ejemplo: definir una nueva syscall, modificar el banner del kernel, etc. syscall, modificar el banner del kernel, etc. ** Si quieres ser un desarrollador del kernel linux o quieres Si quieres ser un desarrollador del kernel linux o quieres colaborar debes comenzar tu lectura en Documentation/HOWTO. colaborar debes comenzar tu lectura en Documentation/HOWTO. ** El kernel linux es portable vamos a mantenerlo asi. Utiliza los El kernel linux es portable vamos a mantenerlo asi. Utiliza los tipos de datos definidos por el kernel. tipos de datos definidos por el kernel.
Linus Tolvards: "La mejor forma de aprender el nucleo es leer tu Linus Tolvards: "La mejor forma de aprender el nucleo es leer tu mismo el codigo fuente." mismo el codigo fuente."
REFERENCIAS
**Linux Device Driver Third Edition. Linux Device Driver Third Edition. **http://www.ibiblio.org/pub/Linux/docs/HOWTO/translations/es/ http://www.ibiblio.org/pub/Linux/docs/HOWTO/translations/es/
**http://es.tldp.org http://es.tldp.org **http://www.kernel-labs.org http://www.kernel-labs.org **http://kernelnewbies.org http://kernelnewbies.org **http://www.kernel.org http://www.kernel.org **http://www.linuxquestions.org http://www.linuxquestions.org