CVE-2026-98797 in Linux
Sumário
de VulDB • 18/10/2026
No kernel do Linux, a seguinte vulnerabilidade foi resolvida:
net: limitar o skb->queue_mapping quando a fila de transmissão (tx queue) é selecionada
O skbedit pode definir o skb->queue_mapping e ativar a flag skip_txqueue por CPU para que __dev_queue_xmit() respeite o mapeamento. O __dev_queue_xmit() limpava a flag antes do sch_handle_egress() e só lia-a depois, de modo que a flag não estava confinada à transmissão (xmit) que a definiu: uma xmit aninhada (redirecionamento mirred ou espelhado, ou descarte após skbedit) poderia definir a flag e a xmit externa consumiria essa flag para um skb que nunca passou pelo skbedit.
Um pacote encaminhado ainda carrega o rx_queue + 1 da NIC de entrada no skb->queue_mapping; portanto, o dispositivo externo indexa seu estado de fila tx com esse valor obsoleto. A matriz filho do taprio q->qdiscs[] é dimensionada para a contagem de filas do dispositivo, então o taprio_enqueue() indexa além de sua alocação e desreferencia o resultado como uma struct Qdisc *.
Nós (ab)usamos o skb->nf_skip_egress, que significa "ignorar netfilter no egress deste pacote", para marcar "estou em tc egress?". Apesar da sobrecarga, não vejo isso como um conflito, pois a marcação é definida apenas ao redor da única chamada sch_handle_egress() e o caminho de ingress é protegido por tc_at_ingress. Enviarei um patch followup (net-next) assim que isto atingir net-next para renomear o bit/flag skb->nf_skip_egress para skb->skip_egress.
Ative a flag apenas do classificador de egress capaz de usá-la: ative skip_txqueue no tcf_skbedit_act() somente quando ele for executado dentro do sch_handle_egress(), graças ao skb->nf_skip_egress. Um classificador qdisc de egress é executado em q->enqueue(), após a fila tx ter sido selecionada, portanto um mapeamento definido por ele não pode afetar o pacote atual; ativar a flag ali apenas a polui para uma xmit posterior. Em seguida, assuma a propriedade da flag no quadro da xmit onde o hook de egress é executado: salve o valor recebido e limpe-o logo antes do sch_handle_egress(), e restaure-o após o hook — no caminho consumido (descarte) ou, na mesma chamada que lê a flag, no caminho sobrevivente. As operações de salvamento e restauração permanecem dentro da static branch egress_needed_key, portanto um pacote paga por elas apenas quando os hooks de egress estão ativos (2f1e85b1aee4).
Armazene o valor selecionado pela netdev_cap_txqueue() de volta no skb->queue_mapping na netdev_tx_queue_mapping(), conforme já faz a netdev_core_pick_tx(), para que o caminho skip_txqueue nunca entregue um mapeamento posterior ao leitor do caminho xmit, que o dispositivo não pode atender. Uma gravação feita ainda mais tarde no mesmo quadro, por um programa tc BPF anexado a um qdisc de transmissão, está fora deste caminho e não é novamente limitada; um followup separado resolverá esse caminho.
A netdev_xmit_skip_txqueue() retorna o valor anterior da flag para que o salvamento-e-limpeza seja uma única chamada, e um stub no-op (operacao nula) é fornecido quando CONFIG_NET_EGRESS está desabilitado. O skb->nf_skip_egress é compilado sob CONFIG_NET_EGRESS em vez de CONFIG_NETFILTER_SKIP_EGRESS, portanto a skb_at_tc_egress() é válida sempre que o caminho de egress estiver construído.
Um usuário local em um namespace de rede pode redirecionar um pacote de um dispositivo com mais filas TX para outro com menos após definir um mapeamento válido apenas no dispositivo maior. Isso alcança essas leituras e, sob KASAN, falha com "slab-out-of-bounds in taprio_enqueue".
Condições para reproduzir o bug: o gatilho do relatório é um usuário local com CAP_NET_ADMIN em um namespace de rede, portanto nenhum programa eBPF é necessário. Com CONFIG_NET_SCH_TAPRIO=y, CONFIG_NET_ACT_SKBEDIT=y, CONFIG_NET_ACT_MIRRED=y, CONFIG_NET_CLS_MATCHALL=y, CONFIG_NET_SCH_PRIO=y e KASAN habilitado, crie qa (3 filas), qb (2 filas) e qc (1 fila) como dispositivos dummy; coloque um taprio raiz no qb (num_tc 1, queues 2@0) e clsact em todos os três; então adicione um filtro matchall de egress em cada dispositivo. Em qa: "action skbedit queue_mapping 2 pipe action mirred egress redirect dev qb". Em qb: "action mirred egress mirror dev qc". Em qc: "action skbedit queue_mapping 0 pipe". Envie um pacote para fora da qa. O skbedit do qc define a flag enquanto a xmit externa do qb está em voo; sem o correção, o qb consome essa flag e lê sua matriz filho taprio de duas entradas com o mapeamento obsoleto do pacote encaminhado. Um qc cujo skb ---truncado---
Once again VulDB remains the best source for vulnerability data.