Pacote privado de reprodução de sanitizador ponta a ponta para seis descobertas do GDCM
Seis defeitos de parser/codec no GDCM, reproduzidos na v3.2.6 como falhas de sanitizer ou verificações de propagação limitada. Cada gatilho automatizado possui um controle quase válido que não produz o sinal vulnerável. O Achado 1 também inclui uma primitiva de fluxo de controle instrumentada.
Destinado à revisão do mantenedor e do coordenador de vulnerabilidades. Leia SAFETY.md antes de executar qualquer coisa.
manifest/targets.env:
| Nome | Revisão | O que é |
|---|
vulnerable | 9c71b163 | tag v3.2.6 |
master | 2cd05d13 | snapshot upstream do master revisado estaticamente; matriz de runtime pendente |
fixed | não definido | preencher apenas quando existir um commit de remediação revisado |
master é um snapshot datado, não um branch móvel. Ambas as revisões são alcançáveis a partir do repositório público, então bootstrap.sh pode preparar qualquer uma sem nenhum código-fonte privado.
A evidência de runtime neste repositório é para a v3.2.6. Os intervalos mais amplos abaixo vêm da inspeção do histórico do código-fonte; os padrões implicados também permanecem no snapshot fixado do master.
| # | CWE | Intervalo inspecionado no código-fonte | Caminho necessário |
|---|---|---|---|
| 1 | CWE-787 | v3.0.4 até v3.2.7 | leitura multi-frame RLE YBR_FULL_422 |
| 2 | CWE-787 | v2.0.16 até v3.2.7 | codificação/transcodificação JPEG2000 |
| 3 | CWE-125 | v2.0.5 até v3.2.7 | parsing de paleta segmentada; a aplicação da LUT expõe valores propagados |
| 4 | CWE-787 | v2.0.8 até v3.2.7 | ImageRegionReader::ReadIntoBuffer; relacionado à validação de precisão incompleta após CVE-2024-22373 |
| 5 | CWE-674 | v2.0.4 ou anterior até v3.2.7 | parsing comum de sequências aninhadas |
| 6 | CWE-369 | v2.0.4 ou anterior até v3.2.7 | parsing comum de RLE com NumSegments=0 |
fixtures/ - as entradas DICOM inertes, com SHA-256 fixado em manifest/expectations.json
e verificadas antes de cada execução de gatilhogenerators/ - geradores de código-fonte determinísticos e sem dependências para cada fixtureharnesses/ - harnesses mínimos de leitura/codificação/decodificação; o Achado 2 é demonstrado tanto
pela CLI gdcmconv quanto pela API de transcodificação da biblioteca que um servidor chamariamanifest/expectations.json - comandos legíveis por máquina, sinais decisivos e
critérios de aceitação para o alvo fixedscripts/ - preparação de código-fonte fixado, builds com sanitizer, execução limitada, limpezaevidence/ - resultados concisos já observados, com alvos não testados declarados explicitamenteLICENSE - licença MITUm ambiente de build descartável Linux ou macOS com Git, Python 3, CMake 3.20+, Ninja e
uma toolchain C++11 (Clang ou GCC). No Ubuntu: git python3 cmake ninja-build clang zlib1g-dev. Defina CC/CXX para usar GCC em vez disso.
A preparação do código-fonte clona via HTTPS a menos que GDCM_SOURCE_REPO aponte para um clone
local existente. Nenhum host SSH é usado.
Estes comandos preparam apenas o código-fonte e os artefatos de build; eles não abrem nenhuma fixture.
./scripts/build-target.sh vulnerable asan debug
./scripts/build-target.sh vulnerable ubsan debug
./scripts/build-target.sh master asan debug
./scripts/build-target.sh master ubsan debug
O terceiro argumento é o perfil. debug é -O0 -g; release é -O2 -g -DNDEBUG,
que elimina os gdcm_debug_assert() do GDCM e corresponde a como as distribuições compilam a
biblioteca. Executar a matriz em ambos responde à primeira pergunta que um mantenedor faz,
que é se os relatórios são um artefato de um build com assertions habilitadas.
GDCM_SUPPORT_BROKEN_IMPLEMENTATION=ON é o próprio padrão do GDCM e é deixado como está.
Substitua o paralelismo conservador com JOBS=8.
Cada build grava build-info.json (revisão, compilador, flags, plataforma) em sua árvore de build
do GDCM, e cada resumo de execução o incorpora, então a evidência arquivada é autodescritiva.
export GDCM_REPRO_ACK=I_UNDERSTAND_THIS_CRASHES_A_LOCAL_PROCESS
./scripts/run-matrix.sh vulnerable master --profile debug # todos os casos automatizados
./scripts/run-one.sh vulnerable f1 # um gatilho
./scripts/run-one.sh vulnerable f1 --control # seu controle
run-matrix.sh executa todos os casos automatizados para cada alvo, não para na primeira
falha, e grava _runs/matrix-<stamp>.json mais um
_runs/matrix-<stamp>.md renderizado. O caso f1-exploit de dois estágios permanece manual e é reportado
como tal em vez de ser classificado erroneamente como um caso automatizado falho.
Cada processo filho tem core dumps desabilitados e um timeout de 15 segundos; o Achado 5 recebe adicionalmente um
limite de pilha limitado. As saídas permanecem sob _runs/. O classificador corresponde à classe do sanitizer
e à função implicada, nunca a endereços, PIDs ou números de linha do código-fonte.
Para vulnerable, um caso passa quando o sinal decisivo aparece e seu controle permanece
limpo. Para master, o executor registra observação em vez de um veredito pré-declarado.
Para fixed, um caso passa apenas quando o sinal está ausente, nenhum outro sanitizer ou sinal fatal
aparece, e o harness retorna um resultado limpo permitido. Essas regras são
provisórias até que FIXED_REV nomeie um patch real; elas devem ser revisadas contra o
comportamento pretendido de rejeitar-ou-processar desse patch.
| Caso | Achado | O que mostra |
|---|---|---|
f1 | 1 | escrita de heap ASan em RLECodec::DecodeFragment |
f1-exploit | 1 | sobrescrita instrumentada de objeto adjacente e controle de branch indireto (Linux x86-64) |
f2 | 2 | escrita de heap ASan em opj_write_from_memory via gdcmconv --j2k |
f2-lib | 2 | a mesma escrita via ImageChangeTransferSyntax::Change |
f3 | 3 | leitura de heap ASan na expansão de paleta segmentada |
f3-propagation | 3 | bytes fora dos limites alcançam pixels decodificados, reportado como uma contagem |
f3-sentinel | 3 | uma palavra de guarda conhecida e limitada cruza o limite lógico da LUT |
f4 | 4 | escrita de heap ASan na decodificação de região JPEG2000 |
f5 | 5 | esgotamento de pilha ASan em itens de sequência aninhados |
f6 | 6 | divisão por zero UBSan na decodificação RLE; SIGFPE em x86 |
Dois harnesses adicionais são pesquisa de explorabilidade em vez de casos de reprodução, e compilam apenas no perfil sem sanitizer em Linux x86-64:
| Harness | Achado | O que estabelece |
|---|---|---|
finding01_groom | 1 | a adjacência glibc testada, observada através de hooks de registro de alocação |
finding03_leak | 3 | uma leitura excessiva de 131070 bytes pode expor um ponteiro de biblioteca específico do build |
evidence/v3.2.6-macos-arm64-debug.md registra a matriz de debug completa da v3.2.6,
incluindo cada controle e ambas as verificações limitadas de propagação do Achado 3.
evidence/v3.2.6-linux-x86_64-finding01-groom.md e
evidence/v3.2.6-linux-x86_64-finding03-leak.md registram os dois resultados de explorabilidade
abaixo. Resultados do master atual, da matriz completa do perfil release e do f1-exploit não são
reivindicados até que suas transcrições sejam retidas.
./scripts/clean.sh
A limpeza se recusa a executar sem o marcador do pacote e remove apenas _work, _build,
_generated, _runs e caches de bytecode Python sob este repositório. A evidência retida
em evidence/ não é removida.
f1-exploit é apenas para Linux-x86_64 e é executado manualmente; manifest/expectations.json contém
a sequência exata de comandos. Sob o layout de alocação determinístico do harness, ele testa
três fatos separados, cada um com um caso negativo correspondente:
f1, reporta corrupção mas explicitamente
não controle de conteúdo, então a verificação é falseável;Cerca de metade das janelas de 8 bytes dentro do overflow de 12288 bytes aceitam um valor
arbitrário. O restante é acoplado, porque DoYBRFull422 duplica um byte de origem em duas
posições de saída; o offset 6144 é uma das janelas livres. A decodificação do Frame 1 é executada por último, então
é o conteúdo do frame 1 que persiste após a alocação.
O harness registra se ImageReader::Read() retorna true enquanto o objeto adjacente
é modificado. Uma transcrição bem-sucedida de Linux x86-64 deve ser retida antes de descrever esse
resultado como evidência observada.
f1-exploit fornece seu próprio layout de vítima, então não pode responder se um processo
não modificado tem esse layout. finding01_groom usa glibc padrão, PIE padrão e ASLR, com
hooks globais de alocação que registram mas não realocam alocações. Nos testes retidos:
finding01 morre da mesma forma sem nenhuma instrumentação.No build glibc testado, o Achado 1 causou confiavelmente negação de serviço; nenhum caminho de execução de código foi encontrado. A geometria testada era fixa, e outros alocadores ou plataformas podem dispor o heap de forma diferente.
finding03_leak é o resultado mais forte. No build testado, a leitura fora dos limites
alcança 131070 bytes, um ponteiro de vtable de gdcm::ByteValue entra nos pixels decodificados, e o
harness deriva a base de carregamento da biblioteca usando o offset de vtable conhecido desse build. Este é um
resultado de divulgação local em nível de API: requer aplicação de LUT e acesso ao buffer
de pixels decodificados. Não mostra que um serviço de rede retorna esses pixels.
Os dois não podem ser encadeados em execução de código aqui, e não apenas porque nenhuma vítima foi encontrada: eles precisam de valores diferentes de PhotometricInterpretation, então precisam de dois arquivos, e uma base vazada só é útil enquanto o processo que vaza ainda está vivo.
Um relatório de sanitizer prova o evento declarado de segurança de memória ou comportamento indefinido no
processo e revisão testados. f1-exploit testa controle de bytes e uma sobrescrita adjacente de ponteiro de
função sob um alocador instrumentado que deliberadamente fornece o layout alvo.
Ele não estabelece esse layout em um consumidor não modificado. As tentativas retidas
de finding01_groom não observaram esse layout para a geometria testada e o build glibc.
Nada disso prova alcançabilidade remota em qualquer produto específico, persistência ou aplicabilidade downstream. O argumento de alcançabilidade para uma dada implantação é uma reivindicação separada, feita no texto de divulgação e não por este pacote.