Uma proposta RFC recém-enviada ao kernel Linux promete expandir radicalmente o que o BPF pode fazer. A série de patches introduz um novo tipo de programa — BPF_PROG_TYPE_RAW_TRACEPOINT_OVERRIDE — que permitiria a um BPF sobrescrever (override) a função probe de um tracepoint já registrado. Em outras palavras: em vez de apenas observar um evento, passamos a poder interceptá-lo e alterar seu comportamento em tempo real. Para quem vive de observability, debug e segurança, esse é um divisor de águas.
De observador a ator: como funciona o override

Pense num tracepoint como uma coletiva de imprensa: até hoje, o BPF era o jornalista no fundo da sala — ouvia tudo e anotava. Com o novo tipo, o BPF pode “subir ao púlpito”: decide se deixa o porta-voz original falar, se responde no lugar dele, ou se muda a resposta. Tecnicamente, o patch cria o programa RAW_TRACEPOINT_OVERRIDE e estende o caminho de attach do raw_tracepoint_open para aceitar um probe_name: o nome da função de probe que já está conectada àquele tracepoint (via register_trace_*
). O kernel localiza essa função (via kallsyms_lookup_name
), guarda um snapshot do estado original e troca a função pelo programa BPF. Ao desanexar, o kernel restaura o probe original automaticamente.
Sob o capô, a estrutura struct tracepoint
ganha um ponteiro tracepoint_func_snapshot *snapshot
para registrar o par “original/override”. Funções novas como tracepoint_probe_override()
e utilitários de salvar/restaurar fazem o trabalho sujo de remover o callback antigo e inserir o BPF com a mesma prioridade. É uma engenharia direta, mas poderosa: altera o fluxo de execução do tracepoint sem precisar recompilar o kernel.
Do lado do user space, a série já traz suporte no libbpf. Há novas sections — raw_tp.o/...
— e a API passa a aceitar probe_name
em bpf_raw_tracepoint_open_opts()
. Na prática, você escreve algo como SEC("raw_tp.o/<tracepoint>:<probe_name>")
no seu programa BPF, e o libbpf divide o que vem antes/depois dos dois-pontos para preencher tp_name
e probe_name
corretamente ao anexar.
Os casos de uso: live-patching, mocking e sandboxing
Por que isso importa? Porque muda a nossa alavanca de ação dentro do kernel.
- Live-patching rápido: a proposta afirma que o override via tracepoints estáticos pode viabilizar a aplicação de hotfixes — inclusive de segurança — sem recompilar ou reiniciar, usando pontos já existentes como “ancoras” para inserir correções temporárias. Em ambientes de missão crítica, isso reduz MTTR e ganha tempo enquanto o upstream não integra o patch definitivo.
- Testes avançados (mocking): imagine testes de integração que “fingem” comportamentos de subsistemas do kernel — por exemplo, forçar um erro específico num caminho de I/O — simplesmente substituindo a probe do tracepoint por uma versão BPF que retorna condições controladas.
- Segurança e sandboxing: políticas defensivas podem bloquear ou transformar certos eventos sensíveis em tempo de execução (ex.: reduzir a verbosidade de um caminho que exfiltra metadados via tracing), sem tocar em código nativo e com a segurança do verificador de BPF.
Tudo isso sem depender de kprobes/fprobes em funções arbitrárias — aqui a âncora é o tracepoint (documentado, estável, com ABI de argumentos conhecido), o que tende a ser mais previsível para produção. (Para contexto sobre raw tracepoints e a diferença para tracepoints “normais”, vale a referência canônica da documentação de eBPF.)
O debate: limites, riscos e o que vem pela frente
Como toda ideia ambiciosa, há tensão de escopo. Tracepoints sempre foram pensados para telemetria; permitir intervenção direta muda esse contrato. Há também custo de memória: a estrutura struct tracepoint
fica maior ao ganhar o ponteiro para snapshot (e já existe um coro histórico pedindo para reduzir o overhead dos tracepoints). O design tenta mitigar isso limitando o override a quem souber exatamente o probe_name (um callback registrado), registrando/restaurando com prioridade idêntica e validando o acesso do programa BPF quanto ao número/tamanho dos argumentos do evento. Ainda assim, a conversa com mantenedores deve ser intensa — é RFC, e o formato final pode mudar bastante.
Também é legítimo perguntar sobre segurança: se um programa pode “tomar” um tracepoint, qual a superfície de ataque? A resposta de sempre no ecossistema BPF continua válida: o verificador limita leituras/escritas e o capability model controla quem pode carregar/ancorar esses programas. O caminho proposto reaproveita as checagens existentes de RAW_TRACEPOINT (incluindo limites de max_ctx_offset
e writable_size
) antes de permitir a troca do callback.
Como experimentar (prévia de desenvolvedor)
A série já chega com selftests que demonstram a ideia: um programa em SEC("raw_tp.o/...")
substitui a probe alvo, aciona um evento de teste no módulo bpf_testmod
e verifica, via uma flag em BSS, que o BPF realmente tomou o lugar do probe original. Para quem quer sentir o gosto, os patches também atualizam o libbpf para aceitar probe_name
e parsear raw_tp.o/<tp>:<probe>
. Claro, por ser RFC, isso exige uma árvore de kernel/libbpf patchada; não é algo que você vá rodar no seu host de produção amanhã.
No fim das contas, a frase-chave aqui é possibilidade. Se aprovada, essa extensão abre um espaço totalmente novo entre observação e intervenção — com implicações práticas para Linux BPF tracepoint em SRE, QA e segurança. E como toda boa mudança no kernel, ela nascerá melhor se for forjada no calor do review.