Summary
An out-of-bounds heap read exists in cupsdSetPrinterAttr() in scheduler/printers.c when parsing marker-types attribute values that end with a hyphen character (-). The vulnerable code converts hyphenated marker type strings (e.g., ink-cartridge) into camelCase (e.g., inkCartridge) for the printer-supply IPP attribute, but fails to check for the null terminator after advancing past a trailing hyphen. This causes the loop to read one or more bytes beyond the end of the heap-allocated string.
Details
The vulnerability is in cupsdSetPrinterAttr() at approximately line 2199 of scheduler/printers.c. The function processes marker-types values to build printer-supply attribute strings. It converts hyphenated keywords like ink-cartridge into camelCase (inkCartridge) using the following loop:
for (psptr = pstype; *type && psptr < (pstype + sizeof(pstype) - 1); type ++)
if (*type == '-')
{
type ++; // (A) advance past '-'
*psptr++ = (char)toupper(*type & 255); // (B) capitalize next char
}
else
*psptr++ = *type;
When a marker-types value ends with - (e.g., ink-):
- The outer
for loop iteration reaches the - character and enters the if branch.
- At (A),
type++ advances past the - to the null terminator \0.
- At (B),
toupper('\0' & 255) writes \0 into pstype (harmless by itself).
- The outer loop's
type++ in the for statement then increments type past the null terminator.
- On the next iteration,
*type in the loop condition reads from heap memory beyond the string's allocation, constituting an out-of-bounds read.
The loop continues reading and copying heap bytes into pstype until it encounters a zero byte or fills the 63-byte buffer.
The type pointer originates from ippGetString(types, i, NULL), which returns a pointer to a string interned via _cupsStrAlloc(). That function allocates with calloc(1, sizeof(_cups_sp_item_t) + strlen(s)). Because the _cups_sp_item_t struct contains a char str[1] flexible array member, there are typically a few bytes of zero padding between the end of the string and the allocation boundary. This padding masks the bug in most production scenarios -- the OOB read hits zero bytes from calloc and the loop terminates -- but the read is still undefined behavior and constitutes a genuine out-of-bounds access.
The code runs in the cupsd scheduler process, which typically executes as root.
PoC
The following standalone C program reproduces the bug. It extracts the vulnerable loop verbatim from scheduler/printers.c and allocates the marker-types string with malloc(slen+1) (tight allocation, no struct padding) so that AddressSanitizer can detect the OOB read.
/*
* Compile:
* gcc -fsanitize=address -fno-omit-frame-pointer -g -O1 \
* -o poc_marker_types_oob poc_marker_types_oob.c
*
* Expected: ASAN reports heap-buffer-overflow on READ of size 1.
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
const size_t slen = 4;
char *type_str = (char *)malloc(slen + 1);
if (!type_str)
return 1;
memcpy(type_str, "ink-", slen);
type_str[slen] = '\0';
char pstype[64];
char *psptr;
const char *type = type_str;
for (psptr = pstype;
*type && psptr < (pstype + sizeof(pstype) - 1);
type++)
{
if (*type == '-')
{
type++;
*psptr++ = (char)toupper(*type & 255);
}
else
{
*psptr++ = *type;
}
}
*psptr = '\0';
printf("pstype = \"%s\" (len=%zu)\n", pstype, strlen(pstype));
free(type_str);
return 0;
}
ASAN output (truncated):
==PID==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x...
READ of size 1 at 0x... thread T0
#0 main poc_marker_types_oob.c:31
0x... is located 0 bytes after 5-byte region [0x..., 0x...)
allocated by thread T0 here:
#0 malloc
#1 main poc_marker_types_oob.c:18
To trigger this via the CUPS backend protocol, a backend program (running as root) sends:
The cupsd scheduler parses this in cupsdUpdatePrinterAttr() which calls cupsdSetPrinterAttr(), reaching the vulnerable loop.
Impact
Confidentiality: The OOB read copies heap bytes beyond the string allocation into the pstype buffer, which is then formatted into the printer-supply IPP attribute via snprintf(). This attribute value is subsequently available to authenticated users querying printer attributes, potentially leaking small amounts of heap data. In practice, the _cupsStrAlloc() calloc padding limits the leak to typically zero bytes, but this is an implementation detail that cannot be relied upon for security.
Availability: If heap memory beyond the string contains non-zero bytes (possible with different allocators, or after heap churn), the loop could copy up to 63 bytes of heap data into pstype, potentially producing garbled printer-supply values. This is unlikely to cause a crash but constitutes undefined behavior.
Integrity: No write-based corruption occurs.
Overall severity is Low because exploitation requires local access (a malicious backend or a compromised printer sending crafted IPP attributes), the read is small and typically masked by allocator padding, and the leaked data (if any) is limited to nearby heap contents.
Suggested Fix
Add a null-terminator check immediately after the inner type++ to prevent advancing past the end of the string:
for (psptr = pstype; *type && psptr < (pstype + sizeof(pstype) - 1); type ++)
if (*type == '-')
{
type ++;
if (!*type)
break;
*psptr++ = (char)toupper(*type & 255);
}
else
*psptr++ = *type;
The added if (!*type) break; exits the loop when the string ends with -, preventing the outer loop's type++ from advancing past the null terminator.
Fixes:
master 5460a712f Protect against a driver reporting a supply type with a trailing '-'.
2.4.x ed6ac03 Protect against a driver reporting a supply type with a trailing '-'.
Summary
An out-of-bounds heap read exists in
cupsdSetPrinterAttr()inscheduler/printers.cwhen parsingmarker-typesattribute values that end with a hyphen character (-). The vulnerable code converts hyphenated marker type strings (e.g.,ink-cartridge) into camelCase (e.g.,inkCartridge) for theprinter-supplyIPP attribute, but fails to check for the null terminator after advancing past a trailing hyphen. This causes the loop to read one or more bytes beyond the end of the heap-allocated string.Details
The vulnerability is in
cupsdSetPrinterAttr()at approximately line 2199 ofscheduler/printers.c. The function processesmarker-typesvalues to buildprinter-supplyattribute strings. It converts hyphenated keywords likeink-cartridgeinto camelCase (inkCartridge) using the following loop:When a
marker-typesvalue ends with-(e.g.,ink-):forloop iteration reaches the-character and enters theifbranch.type++advances past the-to the null terminator\0.toupper('\0' & 255)writes\0intopstype(harmless by itself).type++in theforstatement then incrementstypepast the null terminator.*typein the loop condition reads from heap memory beyond the string's allocation, constituting an out-of-bounds read.The loop continues reading and copying heap bytes into
pstypeuntil it encounters a zero byte or fills the 63-byte buffer.The
typepointer originates fromippGetString(types, i, NULL), which returns a pointer to a string interned via_cupsStrAlloc(). That function allocates withcalloc(1, sizeof(_cups_sp_item_t) + strlen(s)). Because the_cups_sp_item_tstruct contains achar str[1]flexible array member, there are typically a few bytes of zero padding between the end of the string and the allocation boundary. This padding masks the bug in most production scenarios -- the OOB read hits zero bytes from calloc and the loop terminates -- but the read is still undefined behavior and constitutes a genuine out-of-bounds access.The code runs in the
cupsdscheduler process, which typically executes as root.PoC
The following standalone C program reproduces the bug. It extracts the vulnerable loop verbatim from
scheduler/printers.cand allocates the marker-types string withmalloc(slen+1)(tight allocation, no struct padding) so that AddressSanitizer can detect the OOB read.ASAN output (truncated):
To trigger this via the CUPS backend protocol, a backend program (running as root) sends:
The
cupsdscheduler parses this incupsdUpdatePrinterAttr()which callscupsdSetPrinterAttr(), reaching the vulnerable loop.Impact
Confidentiality: The OOB read copies heap bytes beyond the string allocation into the
pstypebuffer, which is then formatted into theprinter-supplyIPP attribute viasnprintf(). This attribute value is subsequently available to authenticated users querying printer attributes, potentially leaking small amounts of heap data. In practice, the_cupsStrAlloc()calloc padding limits the leak to typically zero bytes, but this is an implementation detail that cannot be relied upon for security.Availability: If heap memory beyond the string contains non-zero bytes (possible with different allocators, or after heap churn), the loop could copy up to 63 bytes of heap data into
pstype, potentially producing garbledprinter-supplyvalues. This is unlikely to cause a crash but constitutes undefined behavior.Integrity: No write-based corruption occurs.
Overall severity is Low because exploitation requires local access (a malicious backend or a compromised printer sending crafted IPP attributes), the read is small and typically masked by allocator padding, and the leaked data (if any) is limited to nearby heap contents.
Suggested Fix
Add a null-terminator check immediately after the inner
type++to prevent advancing past the end of the string:The added
if (!*type) break;exits the loop when the string ends with-, preventing the outer loop'stype++from advancing past the null terminator.Fixes:
master 5460a712f Protect against a driver reporting a supply type with a trailing '-'.
2.4.x ed6ac03 Protect against a driver reporting a supply type with a trailing '-'.