Yocto
Porque os scanners de SBOM não veem o que está nos builds Yocto
Os scanners leem um resultado, como um sistema de ficheiros, um binário ou um manifesto, e deduzem o que entrou nele. Uma imagem Yocto esconde a maior parte disso: as bibliotecas estáticas e os crates Rust são compilados para dentro dos binários, os patches das receitas alteram código sem alterar os números de versão, a configuração do kernel decide que código chega sequer a existir e as ferramentas do anfitrião de build nunca chegam à imagem. A alternativa é registar o build e manter os metadados de patches e CVE do próprio Yocto.
Atualizado a
Num minuto
- Anfitrião de build: as ferramentas da máquina de build moldam a imagem e nunca aparecem nela. Um scanner da imagem não as consegue ver.
- Obtenção: o BitBake descarrega fontes, crates Rust, módulos Go e ferramentas. Um scanner vê apenas o que sobrevive até à imagem.
- Receitas e patches: uma receita mantém a versão upstream e aplica patches de segurança por cima. Um scanner que compara versões reporta CVE que já estão corrigidas.
- Código compilado: bibliotecas estáticas, crates e a configuração do kernel acabam dentro dos binários. Um scanner vê um ficheiro onde entraram dezenas de componentes.
- Imagem: as imagens de produção deixam muitas vezes de fora a base de dados de pacotes. O scanner fica então sem lista para ler e reporta pouco ou nada.
Em que difere um build Yocto do que os scanners esperam
Um build Yocto não é uma instalação feita por um gestor de pacotes. A maior parte do que acaba no dispositivo é decidida no momento do build, dentro do BitBake, em cinco camadas. Os scanners olham para uma camada depois do facto e têm de adivinhar o resto.
1. O anfitrião de build
O BitBake corre com ferramentas da máquina de build. A variável HOSTTOOLS lista as ferramentas do anfitrião de build
que as tarefas de build podem chamar, e o sistema de build cria ligações simbólicas para elas em ${TMPDIR}/hosttools. O BitBake também
constrói as suas próprias ferramentas através de receitas -native e -cross. As ferramentas do anfitrião influenciam a imagem e,
por conceção, não fazem parte dela.
2. Obtenção
As receitas indicam as suas fontes em SRC_URI, e o fetcher descarrega-as para DL_DIR. Procura
primeiro em DL_DIR, depois em PREMIRRORS, depois upstream e por fim em MIRRORS. Os crates Rust
chegam através do fetcher crate://, listados num ficheiro -crates.inc que o
cargo-update-recipe-crates gera a partir de Cargo.lock. Os módulos Go chegam através da
classe go-mod ou são incluídos com go-vendor. BB_NO_NETWORK e
BB_ALLOWED_NETWORKS controlam o que o fetcher pode alcançar.
3. Receitas e patches
Cada receita fixa uma versão upstream em PV e aplica patches por cima. Um patch com uma linha CVE:
no cabeçalho marca essa CVE como corrigida. O número de versão continua a ser o upstream, pelo que a receita pode estar corrigida
enquanto a sua versão diz o contrário.
4. Código compilado
As bibliotecas estáticas (os pacotes -staticdev), os crates Rust e os módulos Go acabam dentro dos binários que os
utilizam. O kernel e os seus módulos são construídos a partir de uma configuração específica do produto, pelo que duas plataformas com a mesma versão
do kernel contêm código diferente.
5. A imagem
O sistema de ficheiros raiz. A funcionalidade de imagem package-management instala as ferramentas de gestão de pacotes e
preserva a base de dados do gestor de pacotes. Sem ela, os ficheiros de dados do gestor de pacotes são apagados do sistema de ficheiros
raiz, o que é comum nas imagens de produção.
A cache shared state (sstate)
O BitBake pode restaurar o resultado de uma tarefa a partir da cache shared state (estado partilhado) em vez de a executar. O manual de visão geral do Yocto di-lo claramente: se os objetos pré-construídos estiverem disponíveis, o compilador não é necessário, "assim, o compilador nem sequer é descarregado". As tarefas restauradas a partir do sstate saltam a obtenção, a compilação e a instalação, o que importa para qualquer ferramenta que dependa de observar esses passos. Mais sobre isto na secção sobre caches, abaixo.
Porque os scanners de imagens e de sistemas de ficheiros não veem a maior parte
-
Sem base de dados de pacotes. Uma imagem de produção construída sem
package-managementnão dá ao scanner nenhuma lista para ler, pelo que este recorre a heurísticas sobre ficheiros ou não reporta quase nada. O resultado parece completo e está quase vazio. -
Código estático e incluído. Uma biblioteca estática ou um crate compilado para
/usr/bin/foonão deixa nenhum registo de pacote. Olibrsvgé um exemplo: a receita atual do oe-core lista mais de 350 crates Rust, e no dispositivo é uma única biblioteca partilhada. -
Anfitrião de build e ferramentas obtidas. Nunca estão na imagem, e por isso nunca numa análise da imagem, embora uma
ferramenta do anfitrião ou uma GitHub Action comprometida possa comprometer a imagem. A backdoor do xz utils (CVE-2024-3094) entrou na
biblioteca enquanto esta era construída, a partir dos tarballs de release e não do repositório Git. Em março de 2025, a CISA reportou
que todas as versões da GitHub Action
tj-actions/changed-filesestiveram comprometidas durante três dias. -
Patches aplicados. A imagem indica
opensslnuma versão upstream. A receita aplicou a correção de uma CVE que afeta essa versão e marcou o patch comCVE:. Uma correspondência por intervalo de versões assinala-a na mesma. É a forma Yocto do problema dos backports das distribuições, e uma das principais fontes do ruído tratado em como reduzir o ruído de vulnerabilidades.
O resultado é uma mistura de componentes em falta e de resultados errados, e nada no resultado indica qual é qual. O mesmo argumento aplica-se aos contentores nas SBOM de imagens Docker e aos projetos de linguagens nos geradores de SBOM open source.
Porque a análise de binários de firmware tem de adivinhar
A análise de binários compara strings, símbolos e assinaturas de código no firmware extraído com componentes conhecidos e depois deduz as versões. Onde o binário traz provas claras, isso funciona. Numa imagem Yocto, muitas vezes tem de adivinhar:
- binários stripped sem strings de versão;
- código ligado estaticamente, onde as fronteiras entre bibliotecas desapareceram;
- Rust compilado, onde as fronteiras entre crates desaparecem num único executável;
- patches com backport, que são invisíveis num número de versão;
- código do kernel que a configuração incluiu ou excluiu da compilação.
A análise de binários é a ferramenta certa para firmware que não construiu: blobs de fornecedores, módulos comprados, um dispositivo que está a avaliar. Se não tem o build, analisar o binário é a única opção. A regra de decisão é simples: se o constrói, registe-o; se apenas o recebe, analise-o e peça ao fornecedor uma SBOM do build dele.
O que as ferramentas de SBOM e CVE do próprio Yocto fazem bem
O trabalho do Yocto Project em SBOM é boa engenharia, e sabe coisas que nenhuma ferramenta externa consegue saber. A sua documentação diz que a SBOM é "uma descrição de todos os componentes que utilizou, das suas licenças, das suas dependências, das suas fontes, das alterações que lhes foram aplicadas e das vulnerabilidades conhecidas que foram corrigidas".
create-spdx por versão
- 4.3 (Nanbield): a geração de SPDX está ativa por predefinição.
- 5.1 (Styhead): SPDX 3.0 por predefinição em vez de 2.2, e uma classe
vexque dá às ferramentas de CVE externas a informação de que precisam. - 5.3 (Whinlatter):
SPDX_INCLUDE_COMPILED_SOURCES, que inclui apenas as fontes usadas para compilar. - 6.0 (Wrynose, suporte de longo prazo): SPDX 2.2 removido;
SPDX_INCLUDE_KERNEL_CONFIGeSPDX_INCLUDE_PACKAGECONFIGadicionados; as receitas construídas com as classes Cargo, Go, PyPI, npm e CPAN recebem um package URL do ecossistema.
A SBOM abrange o que o BitBake constrói, incluindo as ferramentas nativas que constrói para o anfitrião. É exaustiva em relação a tudo o que tem uma receita.
Estado das CVE como VEX dentro da SBOM
Em SPDX 3, o sistema de build escreve o estado das CVE de cada receita como relações VEX: uma CVE corrigida passa a "fixed",
ligada aos ficheiros de patch; uma não corrigida, "affected"; uma ignorada, "not affected", com o motivo como declaração
de impacto. SPDX_INCLUDE_VEX define quanto é incluído: none, current (a predefinição,
vulnerabilidades ainda não corrigidas na fonte upstream) ou all.
CVE_STATUS e a marcação do patch
CVE_STATUS regista uma decisão por CVE, como um motivo e uma descrição opcional. Os motivos correspondem a
corrigida (backported-patch, cpe-stable-backport, fixed-version e outros),
não corrigida (vulnerable-investigating) e ignorada (cpe-incorrect, disputed,
not-applicable-config, not-applicable-platform, upstream-wontfix).
CVE_STATUS_GROUPS aplica uma decisão a um grupo de CVE, e CVE_PRODUCT define o nome do produto
usado na correspondência.
# In a recipe or .bbappend
CVE_STATUS[CVE-2020-15523] = "not-applicable-platform: Issue only applies on Windows"
# In the header of a patch file
CVE: CVE-2022-3341
Upstream-Status: Backport [link to the upstream commit]
De cve-check a sbom-cve-check
O cve-check comparava os nomes das receitas (CVE_PRODUCT) e as versões com os dados de vulnerabilidades. As
notas de lançamento da 5.2 avisam que, desde o início de 2024, os responsáveis pela NVD deixaram de anotar muitas CVE com os
CPE afetados, pelo que "os relatórios de CVE atuais podem parecer bons, mas a realidade é que algumas vulnerabilidades simplesmente não são
reportadas". A 5.2 tornou também o feed FKIE a predefinição em vez da NVD. O Yocto 6.0 removeu o cve-check e
substituiu-o pela classe sbom-cve-check, que executa o
sbom-cve-check da Bootlin sobre
o resultado SPDX. Da 5.0 à 5.3 continua a ter o cve-check; trate-o como legado.
Onde a SBOM do Yocto termina
O que o Yocto não consegue ver é tudo o que está fora dos metadados do BitBake. Construímos core-image-sato duas vezes num
runner ARM64 nativo com 32 vCPUs, uma vez com a geração de SBOM do Yocto e outra sem ela, e comparámos a SBOM SPDX
3.0.1 do Yocto, escrita em 1.632 ficheiros, com a SBOM CycloneDX que o CRACI registou:
-
Componentes. A SBOM registada pelo CRACI tinha todos os componentes da SBOM do Yocto e mais 88 que esta não tinha: 23 pacotes
do anfitrião na máquina de build (como o
cpiodo Ubuntu), 10 fontes do GitHub, incluindo a GitHub Actionactions/upload-artifact, e 55 outras fontes e ferramentas obtidas durante o build. -
Crates Rust. Ambas listavam as mesmas 653 versões de crates Rust. Na versão que construímos, a SBOM do Yocto
listava-as apenas como ficheiros
.cratecom uma localização de descarga, sem um package URLpkg:cargo, pelo que não podiam ser comparadas com advisories. Desde o Yocto 6.0, as receitas construídas com a classe Cargo têm um package URL para a própria receita, comopkg:cargo/librsvg; no código atual, as descargas de crates individuais continuam sem nenhum. Verifique o que a sua versão escreve. -
Custo. O build com a geração de SBOM do Yocto demorou 155 min 40 s e escreveu 1.632 ficheiros SPDX. Sem
ela, o build demorou 88 min 48 s, menos 43%.
SPDX_INCLUDE_SOURCES,SPDX_INCLUDE_COMPILED_SOURCES,SPDX_INCLUDE_KERNEL_CONFIGeSPDX_INCLUDE_PACKAGECONFIGestavam ativos, pelo que uma configuração predefinida custa menos. A própria documentação do Yocto avisa que, com as fontes compiladas incluídas, a SBOM não comprimida decore-image-minimal"pode crescer de centenas de megabytes para vários gigabytes".
As receitas nativas, como cmake, llvm, ninja e qemu, estão na SBOM do Yocto.
O método, ambas as SBOM e o relatório completo estão em builds Yocto no CRACI.
CVE do kernel Linux: o problema por configuração
O projeto do kernel Linux anunciou a 13 de fevereiro de 2024 que se tinha tornado uma CVE Numbering Authority, e atribui CVE às correções com generosidade. A sua documentação sobre CVE diz que a aplicabilidade de qualquer CVE específica "cabe ao utilizador do Linux determinar", porque "não conhecemos o seu caso de utilização e não sabemos que partes do kernel utiliza".
Assim, uma correspondência pela versão do kernel produz centenas de resultados, a maioria para código que a sua configuração nunca compila. Quatro plataformas de hardware com quatro configurações do kernel dão quatro respostas diferentes a partir da mesma versão do kernel. Há quatro formas de lidar com isto:
- Apenas correspondência de versões. Todas as CVE da versão são reportadas. Ruído máximo.
-
Listas de exclusão curadas. Entradas
CVE_STATUSgeradas a partir dos dados de CVE do kernel. Em maio de 2026, o oe-core removeu a sua lista gerada paralinux-yocto, porque osbom-cve-checkfaz isto ele próprio a partir da lista de CVE que o kernel fornece, com um relatório de CVE inalterado e um SPDX quase 20 MB mais pequeno. -
Filtragem pelo que foi compilado. Com
SPDX_INCLUDE_COMPILED_SOURCESativo para a receita do kernel, oimprove_kernel_cve_report.pyverifica se os ficheiros afetados por uma CVE foram usados para construir o kernel. O manual de segurança do Yocto diz que "reduz os falsos positivos de CVE em 70%-80%". - Registo da configuração.
SPDX_INCLUDE_KERNEL_CONFIG(6.0) escreve a configuração do kernel na SBOM, para que a resposta possa ser verificada mais tarde.
Exemplo prático. Uma CVE do kernel num driver de rede. A plataforma A compila o driver; a plataforma B não.
| Plataforma | Driver compilado? | Correspondência de versões | Filtro de fontes compiladas |
|---|---|---|---|
| A | Sim | Reportada | Reportada: os ficheiros afetados foram compilados |
| B | Não | Reportada | Não reportada: os ficheiros afetados não foram compilados |
Para ter hoje relatórios de CVE do kernel por plataforma, execute as ferramentas de fontes compiladas do Yocto uma vez por configuração de máquina. É a configuração que decide a resposta, pelo que o relatório tem de vir do build de cada configuração.
Caches, mirrors e vendoring: onde qualquer ferramenta de registo tem de ter cuidado
-
Um build que restaura tudo a partir do sstate ou de um
DL_DIRpreenchido obtém pouco ou nada. Uma ferramenta de registo que vê as obtenções tem de transportar as suas provas com essas caches, ou o registo encolhe. - Uma receita que aponta para um tarball com dependências já incluídas mostra uma descarga, não os crates ou módulos que contém.
- Use o que usar, construa as imagens de release a partir de um estado de cache conhecido, mantenha mirrors que controla e compare o número de componentes entre builds.
No CRACI, os pacotes restaurados a partir de caches de CI permanecem na SBOM, e o estado de completude de cada job assinala o que o registo não conseguiu ver.
O que executar: uma tabela de decisão
| Situação | O que usar | O que obtém | O que continua a faltar |
|---|---|---|---|
| Constrói a imagem em GitHub Actions | Registe o build (CRACI); mantenha o create-spdx se depende do seu estado de patches e CVE |
Pacotes do anfitrião, fontes e Actions obtidas, um URL pkg:cargo por crate, monitorização contínua |
Filtragem do kernel por configuração: use as ferramentas do Yocto |
| Constrói com Yocto noutro sistema de CI ou num servidor de build | create-spdx com sbom-cve-check (ou cve-check em versões mais antigas), filtragem do kernel com fontes compiladas |
Receitas, patches, estado das CVE como VEX | Um inventário dos pacotes do anfitrião e das ferramentas obtidas, mantido à parte |
| Recebe firmware que não constrói | Análise de binários, e uma SBOM do build pedida ao fornecedor | Componentes deduzidos a partir do binário | Certeza sobre versões, patches e entradas do build |
| Precisa das CVE do kernel por plataforma | Ferramentas de fontes compiladas do Yocto, por configuração de máquina | CVE do código que cada configuração constrói | Componentes que não são do kernel, a partir da sua SBOM |
| Só tem um scanner de imagens | Use-o para os pacotes instalados, se a base de dados de pacotes for mantida | Parte da lista de pacotes em runtime | Tudo o que é compilado para dentro, corrigido com patches ou deixado no anfitrião de build; um resultado limpo não é prova |
O que cada método vê
| Classe de componente | Scanner de imagens | Análise de binários | Yocto create-spdx |
Registo do build (CRACI) |
|---|---|---|---|---|
| Pacotes instalados | Só se a base de dados de pacotes for mantida | Deduzidos a partir de ficheiros | Sim | Sim, a partir das fontes que o build obteve |
| Bibliotecas estáticas | Não | Deduzidas a partir de assinaturas | Sim, como receitas | Sim, a partir das fontes que o build obteve |
| Crates Rust | Não | Deduzidos; as fronteiras entre crates desaparecem | Como descargas .crate, sem package URL por crate |
Sim, cada um com um package URL pkg:cargo |
| Módulos Go | Não | Deduzidos a partir do binário | Como descargas de módulos da receita | Sim, quando obtidos durante o build |
| Patches aplicados e estado das CVE | Não | Não | Sim, como VEX | Não |
| Configuração do kernel | Não | Não | Sim, com SPDX_INCLUDE_KERNEL_CONFIG (6.0) |
Não |
| Ferramentas do anfitrião na máquina de build | Não | Não | Não (receitas nativas, sim) | Sim |
| Ferramentas de build obtidas fora das receitas, e GitHub Actions | Não | Não | Não | Sim |
Onde entra o CRACI
Para builds Yocto que correm em GitHub Actions, o CRACI é o runner, com até 32 vCPUs e 96 GB de RAM. Regista o que o build trouxe, incluindo pacotes do anfitrião, fontes e Actions do GitHub e outras fontes obtidas, com um package URL para cada crate Rust: na comparação publicada, todos os componentes da SBOM do Yocto e mais 88 que esta não tinha. Compara os componentes com advisories, continua a reavaliar a SBOM à medida que são publicados novos e mostra que builds continham uma dependência vulnerável.
O BitBake já consegue restringir o seu fetcher com BB_ALLOWED_NETWORKS. A
política de egress do CRACI acrescenta um segundo controlo no runner, verificado antes do início do job
e que falha em modo fechado, para que um script ou uma ferramenta que contorne o fetcher continue sem conseguir chegar a um anfitrião que não
autorizou.
Em termos de cobertura da cadeia de abastecimento, a SBOM do CRACI pode substituir o create-spdx. O SPDX do Yocto continua a conter os patches
aplicados e as CVE marcadas como corrigidas, que o CRACI não regista, por isso mantenha o create-spdx ativo se depende
deles. A documentação do CRACI inclui um exemplo que constrói core-image-sato. Porque é que registar é, em geral, melhor do que analisar
explica-se em SBOM no momento do build; as ferramentas para Yocto são comparadas em
ferramentas de segurança embebida comparadas e
CRACI vs Timesys Vigiles.
Quando o CRACI não é a resposta
- Depende do estado das CVE ao nível dos patches, como as decisões
CVE_STATUSe as CVE corrigidas ou ignoradas como VEX. Isso está no SPDX do Yocto: mantenha-o. - Precisa hoje de relatórios de CVE do kernel por configuração. Use as ferramentas de fontes compiladas do Yocto.
- Não constrói o firmware. Use a análise de binários.
- Os seus builds Yocto correm fora do GitHub Actions, ou têm de correr na sua própria infraestrutura. O CRACI oferece hoje runners geridos em infraestrutura europeia; outros sistemas de CI e runners alojados pelo cliente estão no roadmap.
- Precisa da SBOM do job Yocto especificamente em SPDX. A SBOM do CRACI na comparação publicada era CycloneDX; a SBOM do próprio Yocto é SPDX.
Constrói dispositivos ligados para o mercado da UE? Leia o que o CRA exige, como funciona o VEX e como o CRACI se adequa a equipamento de telecomunicações e de rede, IoT industrial e eletrónica de consumo.
Yocto CVE check e SBOM: perguntas frequentes
Porque é que a minha ferramenta de SCA não consegue analisar os nossos produtos baseados em Yocto?
Porque a maioria das ferramentas de SCA lê manifestos, lockfiles ou a base de dados de pacotes de uma imagem, e um build Yocto decide o seu conteúdo dentro do BitBake. As imagens de produção deixam muitas vezes de fora a base de dados de pacotes, as bibliotecas estáticas e os crates Rust são compilados para dentro dos binários, os patches das receitas mantêm os números de versão upstream e as ferramentas do anfitrião de build nunca chegam à imagem.
Posso analisar uma imagem Yocto ou um firmware com o Trivy, o Grype ou um scanner de binários?
Pode, e obterá uma resposta parcial. Um scanner de imagens lê os pacotes instalados se a base de dados de pacotes for mantida, e não vê o que está compilado lá dentro. Um scanner de binários deduz componentes a partir de strings e assinaturas e tem de adivinhar perante binários stripped, código estático e Rust compilado. Nenhum dos dois vê o anfitrião de build nem os patches que uma receita aplicou.
A SBOM do Yocto inclui crates Rust e módulos Go?
Lista-os como fontes da receita que os utiliza. Na versão que construímos, cada crate Rust aparecia como uma descarga .crate com uma localização de descarga e sem package URL pkg:cargo. Desde o Yocto 6.0, as receitas construídas com as classes Cargo e Go recebem um package URL do ecossistema para a própria receita, não para cada descarga de crate ou de módulo.
Porque é que o meu scanner reporta CVE que as nossas receitas Yocto já corrigem?
Porque compara números de versão. Uma receita Yocto mantém a versão upstream e aplica as correções de segurança como patches, marcados com uma linha CVE: ou registados em CVE_STATUS. Uma correspondência por intervalo de versões não consegue ver o patch. O próprio SPDX do Yocto regista essas CVE como corrigidas, ligadas aos ficheiros de patch.
O que substituiu o cve-check no Yocto?
A classe sbom-cve-check, no Yocto 6.0. Executa o sbom-cve-check da Bootlin sobre o resultado SPDX do build. As versões 5.0 a 5.3 continuam a ter o cve-check, que comparava nomes e versões de receitas; as notas de lançamento da 5.2 avisam que os seus relatórios podem deixar escapar vulnerabilidades porque muitas CVE já não trazem dados CPE.
Como obtenho as CVE do kernel Linux para a minha própria configuração do kernel?
Ative SPDX_INCLUDE_COMPILED_SOURCES para a receita do kernel e execute o improve_kernel_cve_report.py, que verifica se os ficheiros afetados por cada CVE foram compilados. O manual de segurança do Yocto diz que reduz os falsos positivos de CVE em 70% a 80%. Execute-o por configuração de máquina, uma vez que cada configuração constrói código diferente.
A cache shared state afeta a SBOM?
Pode afetar. As tarefas restauradas a partir do sstate saltam a obtenção e a compilação, pelo que uma ferramenta que dependa de observar esses passos vê menos. O create-spdx do Yocto trabalha a partir dos metadados das receitas. Seja qual for o método, construa as imagens de release a partir de um estado de cache conhecido e compare o número de componentes entre builds.
A SBOM integrada do Yocto é suficiente para o CRA?
O CRA exige uma SBOM que abranja pelo menos as dependências de nível superior, e a SBOM do Yocto é exaustiva em relação ao que o BitBake constrói. Não lista os pacotes do anfitrião na máquina de build, as GitHub Actions nem as ferramentas obtidas fora das receitas. Se isso é suficiente, cabe-lhe a si decidir; a SBOM é uma prova do seu processo, não conformidade por si só.
Traga um build Yocto para a demo
Marque uma demo e executaremos um dos seus builds BitBake num runner do CRACI e analisaremos consigo o que foi obtido.
Marcar demo