Summary
cupsJSONExportString() budgets 32 bytes per CUPS_JTYPE_NUMBER in its size estimation (line 276), but _cupsStrFormatd() with %.12f can produce up to 322 characters for extreme doubles like 1e308. The allocated buffer overflows when formatting such numbers.
Details
Size estimation (cups/json.c:276):
case CUPS_JTYPE_NUMBER :
length += 32; // Only 32 bytes
break;
Serialization (cups/json.c:375-376):
_cupsStrFormatd(ptr, s + length, current->value.number, loc);
ptr += strlen(ptr);
For 1e308, _cupsStrFormatd uses snprintf(temp, 1024, "%.12f", number) which produces a 310-character string. The 32-byte budget is exceeded by ~278 bytes per extreme number.
Additionally, _cupsStrFormatd() at cups/string.c:728 writes *bufptr = '\0' when bufptr == bufend, placing a NUL 1 byte past the allocation.
Reproducer
#include "cups/json.h"
int main(void) {
cups_json_t *root = cupsJSONNew(NULL, NULL, CUPS_JTYPE_OBJECT);
cupsJSONNewKey(root, NULL, "value");
cupsJSONNewNumber(root, NULL, 1e308);
char *exported = cupsJSONExportString(root); // heap overflow
if (exported) free(exported);
cupsJSONDelete(root);
return 0;
}
Also triggered by import-then-export:
cups_json_t *json = cupsJSONImportString("{\"e\":1e308}");
char *s = cupsJSONExportString(json); // overflow
ASan output:
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x504000000080
WRITE of size 1 at 0x504000000080 thread T0
#0 _cupsStrFormatd cups/string.c:728
#1 cupsJSONExportString cups/json.c:375
Suggested Fix
case CUPS_JTYPE_NUMBER :
- length += 32;
+ length += 330; // DBL_MAX with %.12f = ~322 chars + margin
break;
And fix the off-by-one in cups/string.c:728:
- *bufptr = '\0';
+ if (bufptr < bufend) *bufptr = '\0';
+ else if (bufptr > buffer) *(bufptr - 1) = '\0';
Summary
cupsJSONExportString()budgets 32 bytes perCUPS_JTYPE_NUMBERin its size estimation (line 276), but_cupsStrFormatd()with%.12fcan produce up to 322 characters for extreme doubles like1e308. The allocated buffer overflows when formatting such numbers.Details
Size estimation (
cups/json.c:276):Serialization (
cups/json.c:375-376):For
1e308,_cupsStrFormatdusessnprintf(temp, 1024, "%.12f", number)which produces a 310-character string. The 32-byte budget is exceeded by ~278 bytes per extreme number.Additionally,
_cupsStrFormatd()atcups/string.c:728writes*bufptr = '\0'whenbufptr == bufend, placing a NUL 1 byte past the allocation.Reproducer
Also triggered by import-then-export:
ASan output:
Suggested Fix
And fix the off-by-one in
cups/string.c:728: