Desbordamiento de entero en asignación de buffer de imagen
GHSA-g766-88fx-58h8 · Asignación de CVE pendiente
Resumen
Ocho rutas de asignación de buffer de imagen en pkg/pdfcpu/model/image.go calculan tamaños de buffer con multiplicación int sin comprobar (w*h*N). En plataformas con int de 32-bit, dimensiones suficientemente grandes desbordan, asignando un buffer menor al esperado. Hoy la validación MaxImagePixels aguas arriba (calculada en int64 con safemath) mantiene dimensiones lo bastante bajas para que el desbordamiento no sea alcanzable — pero esto es un hueco de defensa en profundidad. Si algún decodificador de imagen alguna vez produjera dimensiones de salida mayores que las declaradas en la cabecera (patrón visto en múltiples CVEs de librerías de imagen), el buffer infradimensionado se escribiría fuera de rango, causando corrupción de heap.
Impacto
- Plataformas 64-bit: no directamente explotable con límites actuales (desbordamiento imposible bajo
MaxImagePixels), pero el endurecimiento es válido. - Plataformas 32-bit: potencialmente explotable → escritura heap out-of-bounds si existe un bug de desacople de dimensiones en el decodificador.
- Severidad: MEDIUM 5.9 — impacto de integridad bajo (potencial corrupción de heap), disponibilidad alta (panic que mata el proceso).
Causa Raíz
Seis funciones primarias (más dos variantes) asignan buffers de píxeles con multiplicación int simple:
// pkg/pdfcpu/model/image.go
buf := make([]byte, w*h*3) // writeRGBAImageBuf, writeNRGBAImageBuf
buf := make([]byte, w*h*6) // writeRGBA64ImageBuf
buf := make([]byte, w*h) // writeGrayImageBuf
buf := make([]byte, 2*w*h) // writeGray16ImageBuf
buf := make([]byte, w*h*4) // writeCMYKImageBuf
Mientras tanto validateImageResourceLimits correctamente usa safemath.MultiplyInt64 y MaxImagePixels = 100M — así que la validación es segura pero las rutas de asignación que confían en ella no lo son, si sus entradas alguna vez vienen de una fuente distinta a la cabecera validada.
Prueba de Concepto
Confirmación mediante prueba unitaria de la aritmética de desbordamiento (simulación 32-bit):
TestImageBufferOverflowDirect/overflow_rgba_32bit
w=26768, h=26768, multiplier=3
resultado 64-bit: 2149577472
resultado 32-bit: -2145389824 (truncado)
→ asignación de buffer menor en sistemas 32-bit
Bajo límites actuales de MaxImagePixels una imagen cuadrada se limita a ~10,000×10,000 píxeles, manteniendo w*h*3 dentro del rango 32-bit — la corrección es endurecimiento contra una regresión futura o desacople de decodificador, coincidiendo con la clase de bugs vistos en CVE-2026-46601 (WebP dimension mismatch) y CVE-2026-46602 (TIFF unbounded tiles).
Cronología de Divulgación
| Fecha | Evento |
|---|---|
| 2026-09-24 | Informe enviado vía GitHub Private Vulnerability Reporting |
| 2026-09-24 | Aceptado por el mantenedor (hhrutter) |
| 2026-09-28 | Aviso publicado — GHSA-g766-88fx-58h8 |
| Corregido en | pdfcpu v0.16.0 |
Corrección
Usar safemath.MultiplyInt para cada cómputo de tamaño de buffer:
// Después (seguro):
size, err := safemath.MultiplyInt(w, h)
if err != nil {
return nil, fmt.Errorf("image buffer size overflow: %w", err)
}
size, err = safemath.MultiplyInt(size, 3)
if err != nil {
return nil, fmt.Errorf("image buffer size overflow: %w", err)
}
buf := make([]byte, size)
Corregido en pdfcpu v0.16.0. Aviso publicado 2026-09-28; asignación de CVE pendiente.