01 - Carregamento e Remoção (insmod, rmmod, modprobe)
video: https://youtu.be/... no frontmatter da nota.O sistema de módulos do kernel Linux (Loadable Kernel Modules - LKM) é uma arquitetura de extensão dinâmica que permite a manipulação do código que reside no nível mais privilegiado de execução da CPU (Ring 0). A capacidade de injetar e remover código do kernel em tempo de execução, sem a necessidade de um ciclo de recompilação e reinicialização, é o que confere ao Linux sua versatilidade inigualável em hardware. O gerenciamento destes módulos não é apenas uma tarefa de carregamento de arquivos, mas uma orquestração de dependências simbólicas e de estado do kernel, mediada por utilitários que interagem com as syscalls init_module() e delete_module().
1. A Estrutura Binária e o Registro no Kernel
Os módulos do kernel são binários compilados no formato ELF (Executable and Linkable Format), especificamente desenhados para serem realocáveis. Eles possuem a extensão .ko (Kernel Object). Internamente, um módulo contém:
-
Código Executável: Funções C que serão integradas ao espaço de endereçamento do kernel.
-
Tabela de Símbolos: Uma lista de funções e variáveis que o módulo exporta para uso por outros módulos ou pelo próprio núcleo, e uma lista de símbolos que ele importa (necessita) de outros componentes.
-
Seções de Inicialização e Destruição: Marcadas geralmente pelas macros
module_init()emodule_exit(), que ditam os pontos de entrada quando o módulo é inserido ou removido.
2. insmod: Injeção de Baixo Nível
O insmod (insert module) representa a interface mais primitiva e direta entre o usuário e o kernel para o carregamento de código. Ao executar insmod <arquivo.ko>, o utilitário realiza as seguintes operações:
-
Abertura do Arquivo: O binário ELF é carregado do disco para a memória do espaço do usuário.
-
Realocação Dinâmica: O
insmodsolicita que o kernel aloque uma região de memória no Ring 0. O binário é realocado para endereços de memória virtual específicos e os ponteiros de símbolos importados são resolvidos contra a tabela global de símbolos exportados pelo kernel (/proc/kallsyms). -
Chamada de Sistema: O utilitário invoca a syscall
init_module(), passando um ponteiro para o bloco de memória contendo o código realocado e o tamanho do mesmo. -
Execução: O kernel assume o controle, executa a função de inicialização (
module_init) e, se bem-sucedida, o módulo torna-se uma parte integrante da árvore de símbolos do kernel.
A limitação crítica do insmod é sua cegueira topológica. Ele não analisa dependências. Se o módulo driver_x.ko depender de uma função exportada pelo módulo bus_y.ko, e este último não estiver carregado, o insmod falhará com um erro de "Unknown symbol". O uso do insmod em produção é desencorajado, sendo restrito a ambientes de desenvolvimento de drivers ou debugging cirúrgico.
3. rmmod: A Remoção do Código
O utilitário rmmod (remove module) é o contraparte do insmod, acionando a syscall delete_module(). O seu funcionamento é estritamente condicional:
-
Contagem de Referências: O kernel mantém um campo
refcnt(reference count) nastruct modulede cada módulo carregado. Este contador é incrementado sempre que outro módulo depende do referido, ou sempre que um dispositivo de hardware é aberto ou utilizado por um processo. -
Falha de Remoção: Se o
refcnt > 0, o kernel nega a remoção. Isso impede estados de inconsistência, como a tentativa de descarregar um driver de disco enquanto processos de espaço de usuário estão realizando escritas síncronas. -
Limpeza: Se o contador for zero, o kernel executa a função
module_exit(), desvincula o módulo da lista global e libera a região de memória (Ring 0) anteriormente ocupada.
4. modprobe: A Orquestração Inteligente
O modprobe é o padrão industrial e a interface de alta camada para o gerenciamento de módulos. Ele não opera sobre arquivos brutos como o insmod, mas sobre uma base de conhecimento das dependências do sistema.
O Funcionamento do modprobe
Quando o comando modprobe <modulo> é disparado, o utilitário executa uma sequência lógica determinística:
-
Consulta ao
modules.dep: Omodprobelê o arquivo/lib/modules/$(uname -r)/modules.dep.bin(um banco de dados indexado gerado pelodepmod). Este arquivo mapeia cada módulo para sua lista exata de dependências. -
Resolução de Grafo: O utilitário reconstrói o grafo de dependências. Ele carrega, na ordem topológica correta, cada dependência necessária antes de carregar o módulo alvo.
-
Carregamento Condicional: Diferente do
insmod, omodprobeé inteligente o suficiente para verificar se o módulo já não está carregado. Se estiver, ele termina com sucesso silencioso. -
Parâmetros e Aliases: O
modprobeconsulta arquivos em/etc/modprobe.d/para aplicar as diretivas deoptions(passagem de parâmetros ao módulo) e processar aliases (nomes alternativos ou identificadores de hardware).
O Papel do depmod
A eficácia do modprobe depende integralmente da integridade do arquivo modules.dep. Este é gerado pelo utilitário depmod, que varre o diretório /lib/modules/ a cada instalação de kernel ou adição de novos drivers. O depmod realiza uma análise estática dos binários ELF para verificar quais símbolos de cada módulo são importados e exportados, construindo o mapa lógico que permite que o sistema de carregamento opere sem intervenção humana na ordem de carga.
5. Considerações de Segurança e Integridade
Em sistemas modernos com Secure Boot e Kernel Lockdown ativados, a operação de carregamento de módulos é altamente restrita. O kernel verifica a assinatura digital (Authenticode/X.509) do arquivo .ko antes de permitir sua carga na memória privilegiada. Se a assinatura não bater com uma chave confiável (no keyring do kernel), a syscall init_module() é abortada, resultando no erro "Required key not available".
Além disso, o carregamento de módulos pode ser desabilitado inteiramente após o boot (usando a diretiva kernel.modules_disabled = 1 no sysctl), transformando o kernel monolítico em um sistema estático, o que é uma estratégia comum de endurecimento (hardening) em servidores de alta segurança para impedir a injeção de rootkits dinâmicos mesmo que o usuário root seja comprometido.