Como o kernel Linux é testado?
- por Sergio Prado
O kernel Linux está presente no nosso dia-a-dia muito mais do que imaginamos. Uma residência típica pode ter mais de 20 (!) dispositivos rodando o kernel Linux. TVs inteligentes, roteadores, equipamentos de TV a cabo, smartphones e tablets Android, PCs, relógios inteligentes, impressoras, máquinas de lavar, modems, etc. A lista não acaba. Automóveis, equipamentos médicos, máquinas de cartão de crédito, aviões, etc. E claro, boa parte da infraestrutura mundial de computação é baseada no kernel Linux, de servidores na Internet a switches, firewalls e supercomputadores! Sim, Linux is everywhere.
No entanto, não existe nada muito formal no processo de desenvolvimento do kernel Linux.
A cada 3 meses aproximadamente (10 a 12 semanas) é liberado um release do kernel Linux. Neste período, 2 semanas são reservadas para o “merge window”, período onde é feita a integração (merge) do que já foi desenvolvido na árvore do Linus Torvalds (mainline), e as outras 8 a 10 semanas de desenvolvimento são reservadas para estabilização do código-fonte e correções de bugs.
Quando o Linus Torvalds “sentir” que o código estabilizou e a quantidade de bugs encontrados diminuiu, o release é liberado e o ciclo de desenvolvimento se repete. Não existe nenhum plano formal de testes para garantir o funcionamento do kernel antes do lançamento de um novo release. A decisão sobre lançar uma nova versão é realmente baseada no “feeling” do ditador benevolente do projeto, Linus Torvalds.
Mas isso não significa que não são feitos testes no kernel Linux. Muito pelo contrário!
A começar pelos usuários e desenvolvedores do kernel, que são incentivados a testar as árvores de desenvolvimento e produção e reportar bugs nas listas de discussão e no Bugzilla (ferramenta de rastreamento de bugs utilizada pelo kernel). O próprio Linus Torvalds incentiva estes testes quando libera uma nova versão do kernel terminando o e-mail com a mensagem “Go out and test”.
O processo de desenvolvimento do kernel prova também que existe um foco grande nos testes, já que 20% do tempo é reservado para integração e os outros 80% para testes e correções de bugs.
Mas a identificação de bugs e a qualidade de um release do kernel não depende somente da iniciativa isolada de desenvolvedores e usuários. Muitas ferramentas auxiliam no processo, incluindo análise estática de código, automação de testes e integração contínua.
Vamos conhecer algumas das ferramentas mais importantes que auxiliam nos testes do kernel Linux?
ANÁLISE ESTÁTICA DE CÓDIGO
Melhor do que gerar uma imagem do kernel com bugs é identificar os bugs antes da geração da imagem, certo? Este é o papel das ferramentas de análise estática de código.
Estas ferramentas fazem uma análise no código-fonte para identificar erros muito antes deles acontecerem. Caso queira entender melhor como estas ferramentas funcionam, veja os artigos “Análise estática de código” e “Analisando código-fonte C/C++ com a ferramenta Cppcheck“.
O fato é que existem algumas ferramentas de análise estática de código que ajudam bastante os desenvolvedores a identificar e corrigir problemas durante o desenvolvimento do kernel Linux.
Sparse é uma ferramenta escrita por Linus Torvalds e integrada ao kernel Linux capaz de identificar e reportar possíveis problemas no kernel. Através de marcações no código-fonte, a ferramenta faz diversas validações semânticas no código. Por exemplo, a ferramenta irá indicar um erro se um código do kernel tentar acessar diretamente um ponteiro de espaço de usuário marcado com __user. Informações sobre a ferramenta estão disponíveis na documentação do kernel.
Smatch é um verdadeiro analisador estático de código desenvolvido com foco no kernel Linux. Esta ferramenta é capaz de identificar problemas de programação incluindo acesso a ponteiros nulos, buffer overflow, uso de memória liberada, deadlocks, uso de variável não inicializada, etc. Segundo a documentação do projeto, mais de 3.000 bugs já foram identificados e corrigidos com o Smatch. Mais informações sobre esta ferramenta estão disponíveis no site do projeto.
Coccinelle é uma ferramenta bem interessante capaz de identificar padrões no código-fonte e realizar alterações automaticamente. Por exemplo, vamos supor que seja necessário alterar a assinatura de uma função da API do kernel utilizada por centenas de drivers de dispositivo. Ao invés de abrir o código-fonte de cada driver e fazer a alteração manualmente, é possível utilizar a ferramenta Coccinelle para automatizar o processo. E esta ferramenta já identificou centenas de bugs no kernel Linux. Por exemplo, este patch foi gerado automaticamente pela ferramenta para corrigir um erro de vazamento de memória no kernel. Mais informações estão disponíveis no site do projeto, incluindo uma lista de bugs identificados pela ferramenta no kernel Linux.
AUTOMAÇÃO DE TESTES
O kernel Linux possui diversas ferramentas de automação de testes. Este tipo de ferramenta auxilia bastante os desenvolvedores, evitando a execução de tarefas repetitivas, identificando automaticamente possíveis erros e regressões no código, dando uma maior segurança ao desenvolvedor e diminuindo os custos de testes ao longo do tempo.
ktest é um script em perl (ktest.pl) disponível no código-fonte do Linux em tools/testing/ktest/, capaz de automatizar o processo de compilação, deploy e testes de uma imagem do kernel. A ferramenta recebe um arquivo de configuração do kernel, faz um build a partir deste config, depois faz o deploy da imagem gerada em uma máquina remota (por exemplo via SSH) e executa algum tipo de teste definido pelo usuário, como esperar uma mensagem de login na console serial. Todas as etapas de build, deploy e teste são configuráveis. É uma ferramenta bem útil de automação de testes do kernel. O anúncio na LKML pode servir de referência para quem tiver interesse em aprender mais sobre a ferramenta.
kselftest é um framework de testes disponível no código-fonte do kernel em tools/testing/selftests/, capaz de testar partes específicas do Linux. Os testes são escritos em linguagem C ou shell script e rodam em espaço de usuário para testar alguma parte específica do kernel. Existem testes para verificar o funcionamento de diversos subsistemas, bibliotecas e APIs do kernel Linux, incluindo cpufreq, gpio, networking, rtc, watchdog, cgroup, ftrace, futex, ipc, etc. É uma ferramenta bastante útil tanto para desenvolvedores quanto para usuários do Linux, e sua documentação está disponível no código-fonte do kernel e nesta página wiki.
O Linux Test Project (LTP) é um projeto que oferece um conjunto de testes automatizados do kernel Linux para validar não só as funcionalidades do kernel, mas também a confiabilidade, robustez e estabilidade do sistema operacional. O projeto é desenvolvido e mantido por empresas como IBM, Cisco, Fujitsu, SUSE e Red Hat. Os testes são escritos em C e Shell Script, e rodam diretamente na máquina com o kernel a ser testado. Informações sobre o projeto, incluindo o código-fonte e a documentação, estão disponíveis no GitHub.
Autotest é um framework de automação de testes com foco no kernel Linux, licença GPL, desenvolvido e utilizado por diversas organizações como Google, IBM e Red Hat. Possui uma arquitetura bastante modular incluindo um cliente para executar os testes, um servidor para controlar múltiplos clientes e uma interface web para disparar testes e visualizar o resultado. O foco da ferramenta não é implementar os testes em si, mas prover uma infraestrutura para automatizar a execução de testes implementados em outros projetos. Ela utiliza por exemplo os testes do projeto LTP. O código-fonte do projeto e sua documentação estão disponíveis no GitHub.
KUnit é um framework de teste unitário do kernel Linux proposto no final de 2018 por Brendan Higgins do Google na lista de discussão do kernel Linux. Segundo o autor do projeto, este framework foi inspirado em outras ferramentas de teste unitário como JUnit (Java), unittest.mock (Python) e Googletest/Googlemock (C++). Enquanto a maioria das ferramentas de automação de testes exige uma máquina com o kernel rodando para executar o testes, o kunit não tem essa necessidade. Ele utiliza um recurso do kernel chamado User-mode Linux, uma espécie de arquitetura especial que possibilita rodar o kernel Linux como se fosse um programa qualquer. Desta forma, não existe a necessidade de rodar os testes em uma VM ou máquina separada. É uma ferramenta nova que ainda não foi aceita oficialmente no kernel, então só o tempo dirá se ela irá ter adoção significativa da comunidade. A documentação da ferramenta está disponível no GitHub.
Outra técnica bastante comum de automação de testes, utilizada principalmente para identificar problemas de segurança, é chamada de fuzzing. Uma ferramenta de fuzzing é capaz de gerar entradas inválidas e randômicas para uma aplicação e monitorar o resultado para identificar possíveis problemas como crashes, travamentos ou vazamentos de recurso. Duas das principais ferramentas de fuzzing do kernel Linux são a Trinity e a Syzkaller. Existe ainda uma ferramenta de automação chamada Syzbot que fica continuamente executando a Syzkaller em algumas árvores do kernel Linux e reportando os problemas identificados neste web site.
Por fim, existem ainda diversas ferramentas desenvolvidas com o propósito de testar subsistemas específicos do kernel, incluindo mmtests com foco em gerenciamento de memória, xfstests para testar sistemas de arquivos e hackbench para testar o escalonador de tarefas.
Muitas destas ferramentas de testes são utilizadas em projetos de integração contínua para identificar e reportar bugs durante o desenvolvimento do kernel Linux.
INTEGRAÇÃO CONTÍNUA
Centenas de commits são feitos nos repositórios de desenvolvimento e produção do kernel todos os dias. Estes commits podem causar diversos problemas, incluindo regressões, falhas de build e conflitos de merge com outros branches e repositórios.
A prática de integração contínua (CI – Continuous Integration) pode ajudar nesta situação. Uma ferramenta de CI irá integrar o trabalho realizado pelos desenvolvedores diariamente, realizando testes e possibilitando a identificação e correção de problemas muito antes deles acontecerem.
KernelCI é atualmente a mais completa ferramenta de testes automatizados e integração contínua do kernel Linux. Criada pela Linaro em 2014 e publicada em kernelci.org, a ferramenta realiza testes automáticos de build em diversas árvores de desenvolvimento do kernel, faz o boot do kernel compilado em uma quantidade grande de plataformas de hardware e executa alguns testes automatizados. Os resultados são publicados na lista de e-mail e no web site do projeto. O código-fonte da ferramenta está hospedado no GitHub.
Outra ferramenta de integração contínua do kernel Linux é a 0-Day Test Service. Criada e mantida pela Intel, esta ferramenta monitora as diversas árvores de desenvolvimento e produção do kernel, realizando automaticamente testes de build, boot, funcionais e de performance, com foco na arquitetura x86. Quando um problema é detectado, um e-mail é enviado para os desenvolvedores responsáveis. Segundo o site do projeto, este serviço já ajudou a identificar mais de 40.000 bugs nas árvores de desenvolvimento do kernel! Mais informações estão disponíveis no site do projeto.
LKFT (Linux Kernel Functional Testing) é uma ferramenta de integração contínua da Linaro com o objetivo de realizar testes funcionais em diversas árvores de desenvolvimento do kernel para identificar bugs e regressões. Os builds são feitos com o OpenEmbedded e os testes automatizados são realizados em plataformas ARM e x86 (32 bits e 64 bits). Os resultados são publicados no site do projeto.
O projeto Kerneltests foi criado em 2013 para testar releases estáveis do kernel Linux. Esta ferramenta roda continuamente testes de build em todas as arquiteturas e alguns testes de boot no QEMU. Os resultados dos testes são publicados no site do projeto.
Existem ainda outras ferramentas de automação de testes e integração contínua como a Fuego, LAVA e Beaker. Algumas comunidades que mantém distribuições Linux utilizam estas ferramentas de automação de testes para identificar e reportar problemas no kernel.
CONCLUSÃO
Quando comecei as pesquisas para escrever este artigo, já conhecia algumas ferramentas de teste do kernel Linux, mas não imaginava que esta lista de ferramentas seria tão grande assim.
O fato é que existem diversas iniciativas para testar o kernel Linux, começando com o usuário e o desenvolvedor, passando por ferramentas de análise estática de código, fuzzing, testes unitários, automação de testes e integração contínua. É um esforço conjunto e contínuo da comunidade para manter a qualidade de um dos maiores projeto de software livre do mundo.
Mas ainda existem muitos desafios pela frente.
Apesar da cobertura dos testes ter aumentado nos últimos anos, a base de código-fonte do kernel é muito grande e cresce exponencialmente a cada release, então o esforço é grande para manter e aumentar esta cobertura de testes do código-fonte do kernel. Outro grande desafio é automatizar testes de drivers e código de plataforma porque exigem o hardware a ser testado. Falta também colaboração, interoperabilidade e padronização entre as ferramentas.
Mas estes desafios devem servir de incentivo para a comunidade melhorar as ferramentas e os processos existentes, desenvolver novas técnicas e ferramentas de teste e continuar melhorando a qualidade do kernel Linux.
Um abraço,
Sergio Prado
Sem Comentários
Nenhum comentário até agora... é a sua chance de ser o primeiro a comentar!