Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 40 additions & 8 deletions ppd/rastertops.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,13 @@ write_flate(cups_raster_t *ras, // I - Image data
// by deflate
unsigned char *pixdata,
*convertedpix;
unsigned char in[header.cupsBytesPerLine * 6], // Input data buffer
out[header.cupsBytesPerLine * 6]; // Output data buffer
size_t line_bytes = header.cupsBytesPerLine ?
(size_t)header.cupsBytesPerLine : 1;
unsigned char in[line_bytes * 6], // Input data buffer
out[line_bytes * 6]; // Output data buffer

if (header.cupsBytesPerLine == 0 || header.cupsHeight == 0)
return (Z_DATA_ERROR);

// allocate deflate state
strm.zalloc = Z_NULL;
Expand All @@ -267,17 +272,37 @@ write_flate(cups_raster_t *ras, // I - Image data
// compress until end of file
do
{
pixdata = malloc(header.cupsBytesPerLine);
cupsRasterReadPixels(ras, pixdata, header.cupsBytesPerLine);
if ((pixdata = malloc(header.cupsBytesPerLine)) == NULL)
{
(void)deflateEnd(&strm);
return (Z_MEM_ERROR);
}
if (cupsRasterReadPixels(ras, pixdata, header.cupsBytesPerLine) !=
header.cupsBytesPerLine)
{
free(pixdata);
(void)deflateEnd(&strm);
return (Z_DATA_ERROR);
}
if (flag)
{
convertedpix = malloc(header.cupsBytesPerLine * 6);
if ((convertedpix = malloc(header.cupsBytesPerLine * 6)) == NULL)
{
free(pixdata);
(void)deflateEnd(&strm);
return (Z_MEM_ERROR);
}
convert_pixels(pixdata,convertedpix, header.cupsBytesPerLine);
alloc = header.cupsBytesPerLine * 6;
}
else
{
convertedpix = malloc(header.cupsBytesPerLine);
if ((convertedpix = malloc(header.cupsBytesPerLine)) == NULL)
{
free(pixdata);
(void)deflateEnd(&strm);
return (Z_MEM_ERROR);
}
memcpy(convertedpix, pixdata, header.cupsBytesPerLine);
alloc = header.cupsBytesPerLine;
}
Expand Down Expand Up @@ -307,6 +332,7 @@ write_flate(cups_raster_t *ras, // I - Image data
if (fwrite(out, 1, have, doc->outputfp) != have)
{
(void)deflateEnd(&strm);
free(pixdata);
if (convertedpix != NULL)
free(convertedpix);
return (Z_ERRNO);
Expand Down Expand Up @@ -410,7 +436,8 @@ ppdFilterRasterToPS(int inputfd, // I - File descriptor input stream
cups_page_header_t header; // Page header from file
int empty, // Is the input empty?
Page = 0, // variable for counting the pages
ret; // Return value of deflate compression
ret, // Return value of deflate compression
status = 0; // Filter return status
cf_logfunc_t log = data->logfunc;
void *ld = data->logdata;
cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
Expand Down Expand Up @@ -516,7 +543,12 @@ ppdFilterRasterToPS(int inputfd, // I - File descriptor input stream
// Write the compressed image data
ret = write_flate(ras, header, &doc);
if (ret != Z_OK)
{
z_error(ret, &doc);
write_end_page(&doc);
status = 1;
break;
}
write_end_page(&doc);
}

Expand All @@ -542,5 +574,5 @@ ppdFilterRasterToPS(int inputfd, // I - File descriptor input stream
fclose(outputfp);
close(outputfd);

return (0);
return (status);
}
115 changes: 114 additions & 1 deletion ppd/test_ppd_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
// Tests covered (50 assertions across 12 groups):
// Tests covered (51 assertions across 13 groups):
//
// Group 1 (T01-T08) NULL / argument guards. ppdFilterLoadPPDFile
// rejects NULL / empty / non-existent paths with
Expand Down Expand Up @@ -135,6 +135,7 @@
#include <ppd/ppd-filter.h>
#include <cupsfilters/filter.h>
#include <cups/cups.h>
#include <ppd/libcups2-private.h>
#include "test-internal.h"

#include <stdio.h>
Expand Down Expand Up @@ -416,6 +417,31 @@ stub_filter(int inputfd, int outputfd,
}


//
// 'find_bytes()' - Locate a byte sequence inside a buffer that may contain NULs.
//

static const char *
find_bytes(const char *haystack,
size_t hay_len,
const char *needle,
size_t needle_len)
{
size_t i;

if (needle_len == 0)
return (haystack);
if (hay_len < needle_len)
return (NULL);

for (i = 0; i <= hay_len - needle_len; i ++)
if (memcmp(haystack + i, needle, needle_len) == 0)
return (haystack + i);

return (NULL);
}


int // O - Exit status (0 = all pass)
main(void)
{
Expand Down Expand Up @@ -1268,6 +1294,93 @@ main(void)
free_filter_data(&data);


// =========================================================================
// Group 13: ppdFilterRasterToPS truncated row safety (T51)
// =========================================================================

// T51 — A two-page CUPS Raster document where page 1 contains marker bytes
// and page 2 is truncated immediately after its header must fail cleanly
// (rc != 0) without compressing uninitialized heap data into page 2.
testBegin("ppdFilterRasterToPS(truncated row) fails without leaking heap");
{
char ras_path[] = "/tmp/test_ppd_raster_XXXXXX";
char ps_path[] = "/tmp/test_ppd_ps_XXXXXX";
int wfd = mkstemp(ras_path);
int pfd = mkstemp(ps_path);
int rfd = -1;
cups_raster_t *ras = NULL;
cups_page_header_t hdr;
unsigned char row[64];
FILE *fp = NULL;
char ps_buf[8192];
size_t ps_len = 0;
const char *img1 = NULL, *img2 = NULL, *g2 = NULL;
size_t rem1 = 0, rem2 = 0;
bool leaked = true;

memset(ps_buf, 0, sizeof(ps_buf));
if (wfd >= 0 && pfd >= 0 &&
(ras = cupsRasterOpen(wfd, CUPS_RASTER_WRITE)) != NULL)
{
memset(&hdr, 0, sizeof(hdr));
hdr.PageSize[0] = 612;
hdr.PageSize[1] = 792;
hdr.cupsWidth = 64;
hdr.cupsHeight = 1;
hdr.cupsBitsPerColor = 8;
hdr.cupsBitsPerPixel = 8;
hdr.cupsBytesPerLine = 64;
hdr.cupsColorSpace = CUPS_CSPACE_K;
hdr.HWResolution[0] = 300;
hdr.HWResolution[1] = 300;

memset(row, 'A', sizeof(row));
memcpy(row, "LEAK-MARKER-0123456789abcdef", 28);
cupsRasterWriteHeader(ras, &hdr);
cupsRasterWritePixels(ras, row, sizeof(row));

// Page 2 header with 0 pixel rows (truncated)
cupsRasterWriteHeader(ras, &hdr);
cupsRasterClose(ras);
close(wfd);

init_filter_data(&data);
rfd = open(ras_path, O_RDONLY);
rc = (rfd >= 0) ? ppdFilterRasterToPS(rfd, pfd, 1, &data, NULL) : -1;
if (rfd < 0)
close(pfd);
free_filter_data(&data);

fp = fopen(ps_path, "rb");
if (fp)
{
ps_len = fread(ps_buf, 1, sizeof(ps_buf), fp);
fclose(fp);
}

img1 = find_bytes(ps_buf, ps_len, ">> image\n", 9);
rem1 = img1 ? ps_len - (size_t)((img1 + 9) - ps_buf) : 0;
img2 = img1 ? find_bytes(img1 + 9, rem1, ">> image\n", 9) : NULL;
rem2 = img2 ? ps_len - (size_t)((img2 + 9) - ps_buf) : 0;
g2 = img2 ? find_bytes(img2 + 9, rem2, "\ngrestore", 9) : NULL;
if (img2 && g2 && g2 == img2 + 9)
leaked = false;

testEndMessage(rc != 0 && !leaked, "rc=%d page2_stream_bytes=%ld",
rc, (img2 && g2) ? (long)(g2 - (img2 + 9)) : -1L);
}
else
{
if (wfd >= 0) close(wfd);
if (pfd >= 0) close(pfd);
testEndMessage(false, "mkstemp failed");
}

unlink(ras_path);
unlink(ps_path);
}


// =========================================================================
// Tear-down: remove temp PPDs.
// =========================================================================
Expand Down
Loading