Home > kernel > Entrando dentro do kernel sem bater na porta :D

Entrando dentro do kernel sem bater na porta :D

Ola após um longo período bem turbulento sem postagem devido a falta de tempo, agora me sobrou um tempo resolvi postar algo interessante(pelo menos para mim), esse e o primeiro de alguns posts que quero falar sobre lkm. Mas e ai? que macumba é LKM?!?. Bom LKM é Load Kernel Module ou módulos do kernel carregavéis “aportuguesado” :D. O que exatamente é um módulo do kernel? Os módulos são pedaços de código que podem ser carregadas e descarregadas dentro do kernel. Eles estendem a funcionalidade do kernel sem a necessidade de reiniciar o sistema. Por exemplo, um tipo de módulo é o driver de dispositivo, que permite o acesso ao hardware conectados ao sistema. Sem os módulos, teríamos que ter o núcleo do sistema operacional na forma de um kernel monolíticos e quando fosse adicionar novas funcionalidades teria que ser feito direto na imagem do kernel. Ou seja nova compilação, recompilação,.., etc. Outra desvantagem em kernel monoliticos é o tamanho do arquivo de imagem do kernel se torna grande devido a ter que conter todo os “pedaços” de codigos ou drivers para cada possível placa de rede, placa de video, ou dispositivo quaisquer, sem contar que a cada inserção de dispositivo um novo suporte de driver também deve ser adicionado gerando com isso a necessidade de recompilar o kernel e reiniciar a máquina. Bom eu desenvolvi esse modulo quando estava no primeiro ano de faculdade nos primórdios do meu aprendizado em Linux. Conforme eu for encontrando tempo vou postar alguns lkm que fiz um deles para interceptar syscall, device driver didatico, criar uma syscall, o duro vai ser converter e ajustar meu código de kernel 2.4 para 2.6 😛

Bom para criar um lkm voce precisa de pre-requisitos um deles é saber a melhor linguagem de todos os tempos “C” 😛 sendo assim eu vou pressupor que voce leitor ja é um programador C. Segue codigo abaixo do nosso LKM.


/*
* hello_world.c - Um simples LKM.
*/
#include <linux/module.h> /* cabeçalhos requeridos */
#include <linux/kernel.h>

int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
return 0;
}

void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}

Vamos as explicações? Pois bem as primeiras linhas e bem intuitivo declaracao de bilbliotecas do kernel. Na linha:


int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
return 0;
}

E a função responsavél por inicializar nosso módulo ou seja carrega nosso código dentro do espaço kernel, vamos fazer uma parada aqui. Afinal o que é espaço kernel? Bom uma regra, todo LKM e executado no assim chamado “espaço kernel” ou “kernel space” enquanto que aplicativos como o editor vim, openoffice, firefox rodam em “espaço usuário” ou “user space”. Livro do Tannenbaum função de um sistema operacional é a de criar programas ou softwares para serem executados em um computador e criar uma interface para esses programas ou softwares protegendo o acesso nao autorizado a dispositivos de hardware e software tirando assim a responsabilidade do programador de aplicativos de se preocupar em carregar registradores da CPU chamar interrupção tal, etc. Esse “espaço” assim designado e chamado de espaço kernel e cria essa proteção dos softwares de usuários do sistema operacional. Bom agora que sabemos o que é espaço kernel e espaço usuário continuamos analisando o código.


void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}

Como temos a função de entrada no kernel(kernel space), também temos a função de saida do kernel “cleanup_module” simples né. Agora vamos a função dentro de cada item(init e cleanup) os “printk”. Quem e acostumado ou é programador C já sacou o que faz o printk sim ele e equivalente ao printf no espaço usuário porém com resalvas. A macro “KERN_INFO” é uma macro que indica prioridade para a mensagem via printk normalmente utilizado pelo ksyslog ou klogd em sistemas Linux antigos. Com isso você pode definir prioridade quando for definir mensagem para o programador do kernel. Existem 8 niveis de prioridade definidas no arquivo de cabeçalho kernel.h normalmente nos fontes do kernel fica em linux-versao/include/linux/kernel.h, vejam as prioridades abaixo.


#define KERN_EMERG "" /* system is unusable */
#define KERN_ALERT "" /* action must be taken immediately */
#define KERN_CRIT "" /* critical conditions */
#define KERN_ERR "" /* error conditions */
#define KERN_WARNING "" /* warning conditions */
#define KERN_NOTICE "" /* normal but significant condition */
#define KERN_INFO "" /* informational */
#define KERN_DEBUG "" /* debug-level messages */

Blz código explicado vamos compilar, mas antes precisamos criar um arquivo Makefile para ser utilizado pela ferramenta de compilação make. Segue Makefile abaixo:


obj-m += hello_world.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Não é intuito deste post explicar o funcionamento do make senão o post vai ficar muito extenso talvez num post futuro. Após a criacao do arquivo execute o comando make


root@capsula:~/lkm# ls
hello_world.c Makefile
root@capsula:~/lkm#
root@capsula:~/lkm# make
make -C /lib/modules/2.6.31-14-generic-pae/build M=/home/ricardobarbosa/lkm modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.31-14-generic-pae'
CC [M] /home/ricardobarbosa/lkm/hello_world.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/ricardobarbosa/lkm/hello_world.mod.o
LD [M] /home/ricardobarbosa/lkm/hello_world.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.31-14-generic-pae'
root@capsula:~/lkm# ls
hello_world.c hello_world.mod.c hello_world.o Module.markers Module.symvers
hello_world.ko hello_world.mod.o Makefile modules.order
root@capsula:~/lkm#

Ótimo meu módulo compilou com sucesso e podemos ver o modulo .ko (uma curiosidade sabe oque significa a extensao .ko – Kernel Object). Vamos subir nosso módulo dentro do kernel? para isso utilizamos o comando insmod (utilitário para carregamento e descarregamento de lkm).


root@capsula:~/lkm# modinfo hello_world.ko
filename: hello_world.ko
srcversion: 140276773A3090F6F33891F
depends:
vermagic: 2.6.31-14-generic-pae SMP mod_unload modversions 586
root@capsula:~/lkm# insmod hello_world.ko
root@capsula:~/lkm# lsmod
Module Size Used by
hello_world 988 0
crc_ccitt 1852 1 dahdi
iptable_filter 3100 0
ip_tables 11692 1 iptable_filter
x_tables 16544 1 ip_tables
snd_intel8x0 30168 0
snd_ac97_codec 101216 1 snd_intel8x0
ppdev 6688 0
ac97_bus 1532 1 snd_ac97_codec
psmouse 56180 0
snd_pcm 75488 2 snd_intel8x0,snd_ac97_codec
serio_raw 5280 0
snd_timer 22276 1 snd_pcm
lp 8964 0
i2c_piix4 10124 0
snd 59204 4 snd_intel8x0,snd_ac97_codec,snd_pcm,snd_timer
parport_pc 32228 0
soundcore 7264 1 snd
snd_page_alloc 9252 2 snd_intel8x0,snd_pcm
parport 35340 3 ppdev,lp,parport_pc
pcnet32 33156 0
mii 5212 1 pcnet32
floppy 54980 0
root@capsula:~/lkm#

Blz nosso lkm subiu sem erro e podemos ver ele carregado quando executamos o comando lsmod(list modules). Subimos o módulo e como sabemos se o nosso módulo funcionou?? Para isso iremos usar o comando dmesg utilitário que exibe as mensagens de inicialização e vindas do kernel.


root@capsula:~/lkm#
.....
[ 105.300548] eth0: link up, 100Mbps, full-duplex
[ 115.782079] eth0: no IPv6 routers present
[13593.784665] hello_world: module license 'unspecified' taints kernel.
[13593.785548] Disabling lock debugging due to kernel taint
[13593.785716] Hello world 1.
root@capsula:~/lkm#

Notem a mensagem hello world nosso módulo subiu perfeitamente notem tambem a mensagem “hello_world: module license ‘unspecified’ taints kernel.” isso é uma forma de indicar que nosso módulo foi inserido no kernel sem uma declaração de licença explicita, o que falta é uma declaração da licença usada pelo módulo. Para isso usamos a macro.


MODULE_LICENSE("GPL");

Adicione o código acima ao fonte e recompile o módulo. após isso a mensagem de “hello_world: module license ‘unspecified’ taints kernel.” irá sumir. Com essa declaração de licença GPL nosso módulo terá acesso aos símbolos do kernel GPL, isso é feito para garantir que tudo dentro do kernel seja GPL 😀

Agora iremos remover nosso módulo das entranhas do kernel para isso outro utilitário rmmod


root@capsula:~/lkm# rmmod hello_world
root@capsula:~/lkm# dmesg
....
[ 105.300548] eth0: link up, 100Mbps, full-duplex
[ 115.782079] eth0: no IPv6 routers present
[16057.727314] Hello world 1.
[17080.476439] Goodbye world 1.
root@capsula:~/lkm#

Nossa este post estava ficando gigante, espero ter conseguido passar o assunto de forma objetiva. Qualquer dúvidas em relação ao assunto e claro se eu souber basta perguntar 😀

Até a próxima.

Advertisements
Categories: kernel
  1. Rafael Petroni
    March 22, 2010 at 9:00 pm

    Aoo Kakaroto, post dahora cara, seu blog ta maneiro.
    abraços.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: