/src/cups/ossfuzz/fuzz_ppd_gen_cache.c
Line | Count | Source |
1 | | #include <stdio.h> |
2 | | #include <stdlib.h> |
3 | | #include <string.h> |
4 | | #include <unistd.h> |
5 | | #include <stdint.h> |
6 | | #include "ppd.h" |
7 | | #include "ppd-private.h" |
8 | | #include "cups.h" |
9 | | #include "ipp.h" |
10 | | #include "file-private.h" |
11 | | |
12 | | // Global variables for cleanup |
13 | | static char *g_ppd_file = NULL; |
14 | | static char *g_cache_file = NULL; |
15 | | |
16 | | // Cleanup function |
17 | | static void cleanup_files(void) |
18 | 19.5k | { |
19 | 19.5k | if (g_ppd_file) |
20 | 9.76k | { |
21 | 9.76k | unlink(g_ppd_file); |
22 | 9.76k | free(g_ppd_file); |
23 | 9.76k | g_ppd_file = NULL; |
24 | 9.76k | } |
25 | 19.5k | if (g_cache_file) |
26 | 9.76k | { |
27 | 9.76k | unlink(g_cache_file); |
28 | 9.76k | free(g_cache_file); |
29 | 9.76k | g_cache_file = NULL; |
30 | 9.76k | } |
31 | 19.5k | } |
32 | | |
33 | | // Parse input data into segments |
34 | | static int parse_input_segments(const uint8_t *data, size_t size, |
35 | | const uint8_t **segments, size_t *seg_sizes, int max_segments) |
36 | 9.76k | { |
37 | 9.76k | if (size < 4) |
38 | 0 | return 0; |
39 | | |
40 | 9.76k | uint32_t num_segments = *(uint32_t *)data; |
41 | 9.76k | if (num_segments == 0 || num_segments > max_segments) |
42 | 46 | return 0; |
43 | | |
44 | 9.71k | const uint8_t *ptr = data + 4; |
45 | 9.71k | size_t remaining = size - 4; |
46 | | |
47 | 24.5k | for (uint32_t i = 0; i < num_segments && i < max_segments; i++) |
48 | 21.6k | { |
49 | 21.6k | if (remaining < 4) |
50 | 4.01k | return i; |
51 | | |
52 | 17.6k | uint32_t seg_len = *(uint32_t *)ptr; |
53 | 17.6k | ptr += 4; |
54 | 17.6k | remaining -= 4; |
55 | | |
56 | 17.6k | if (seg_len > remaining) |
57 | 2.85k | return i; |
58 | | |
59 | 14.8k | segments[i] = ptr; |
60 | 14.8k | seg_sizes[i] = seg_len; |
61 | 14.8k | ptr += seg_len; |
62 | 14.8k | remaining -= seg_len; |
63 | 14.8k | } |
64 | | |
65 | 2.84k | return num_segments; |
66 | 9.71k | } |
67 | | |
68 | | // Create a simple IPP job for testing |
69 | | static ipp_t *create_test_job(const uint8_t *data, size_t size) |
70 | 756 | { |
71 | 756 | ipp_t *job = ippNew(); |
72 | 756 | if (!job) |
73 | 0 | return NULL; |
74 | | |
75 | | // Add some basic attributes using fuzz data |
76 | 756 | if (size > 10) |
77 | 624 | { |
78 | 624 | char media_name[64]; |
79 | 624 | snprintf(media_name, sizeof(media_name), "media-%02x%02x", data[0], data[1]); |
80 | 624 | ippAddString(job, IPP_TAG_JOB, IPP_TAG_KEYWORD, "media", NULL, media_name); |
81 | 624 | } |
82 | | |
83 | 756 | if (size > 20) |
84 | 568 | { |
85 | 568 | char source_name[64]; |
86 | 568 | snprintf(source_name, sizeof(source_name), "source-%02x%02x", data[10], data[11]); |
87 | 568 | ippAddString(job, IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-source", NULL, source_name); |
88 | 568 | } |
89 | | |
90 | 756 | if (size > 30) |
91 | 332 | { |
92 | 332 | char type_name[64]; |
93 | 332 | snprintf(type_name, sizeof(type_name), "type-%02x%02x", data[20], data[21]); |
94 | 332 | ippAddString(job, IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL, type_name); |
95 | 332 | } |
96 | | |
97 | 756 | return job; |
98 | 756 | } |
99 | | |
100 | | // Test all cache GET functions |
101 | | static void test_cache_functions(_ppd_cache_t *pc, ppd_file_t *ppd, const uint8_t **segments, size_t *seg_sizes, int num_segments) |
102 | 13.6k | { |
103 | 13.6k | if (!pc) |
104 | 0 | return; |
105 | | |
106 | | // Test _ppdCacheGetBin |
107 | 13.6k | if (num_segments > 4 && seg_sizes[4] > 0) |
108 | 75 | { |
109 | 75 | char bin_name[256]; |
110 | 75 | size_t copy_len = seg_sizes[4] < sizeof(bin_name) - 1 ? seg_sizes[4] : sizeof(bin_name) - 1; |
111 | 75 | memcpy(bin_name, segments[4], copy_len); |
112 | 75 | bin_name[copy_len] = '\0'; |
113 | | |
114 | 75 | const char *result = _ppdCacheGetBin(pc, bin_name); |
115 | 75 | (void)result; // Suppress unused variable warning |
116 | 75 | } |
117 | | |
118 | | // Test _ppdCacheGetOutputBin |
119 | 13.6k | if (num_segments > 4 && seg_sizes[4] > 0) |
120 | 75 | { |
121 | 75 | char output_bin[256]; |
122 | 75 | size_t copy_len = seg_sizes[4] < sizeof(output_bin) - 1 ? seg_sizes[4] : sizeof(output_bin) - 1; |
123 | 75 | memcpy(output_bin, segments[4], copy_len); |
124 | 75 | output_bin[copy_len] = '\0'; |
125 | | |
126 | 75 | const char *result = _ppdCacheGetOutputBin(pc, output_bin); |
127 | 75 | (void)result; |
128 | 75 | } |
129 | | |
130 | | // Test _ppdCacheGetSource |
131 | 13.6k | if (num_segments > 3 && seg_sizes[3] > 0) |
132 | 86 | { |
133 | 86 | char input_slot[256]; |
134 | 86 | size_t copy_len = seg_sizes[3] < sizeof(input_slot) - 1 ? seg_sizes[3] : sizeof(input_slot) - 1; |
135 | 86 | memcpy(input_slot, segments[3], copy_len); |
136 | 86 | input_slot[copy_len] = '\0'; |
137 | | |
138 | 86 | const char *result = _ppdCacheGetSource(pc, input_slot); |
139 | 86 | (void)result; |
140 | 86 | } |
141 | | |
142 | | // Test _ppdCacheGetType |
143 | 13.6k | if (num_segments > 2 && seg_sizes[2] > 0) |
144 | 102 | { |
145 | 102 | char media_type[256]; |
146 | 102 | size_t copy_len = seg_sizes[2] < sizeof(media_type) - 1 ? seg_sizes[2] : sizeof(media_type) - 1; |
147 | 102 | memcpy(media_type, segments[2], copy_len); |
148 | 102 | media_type[copy_len] = '\0'; |
149 | | |
150 | 102 | const char *result = _ppdCacheGetType(pc, media_type); |
151 | 102 | (void)result; |
152 | 102 | } |
153 | | |
154 | | // Test _ppdCacheGetPageSize with keyword |
155 | 13.6k | if (num_segments > 1 && seg_sizes[1] > 0) |
156 | 1.21k | { |
157 | 1.21k | char page_size[256]; |
158 | 1.21k | size_t copy_len = seg_sizes[1] < sizeof(page_size) - 1 ? seg_sizes[1] : sizeof(page_size) - 1; |
159 | 1.21k | memcpy(page_size, segments[1], copy_len); |
160 | 1.21k | page_size[copy_len] = '\0'; |
161 | | |
162 | 1.21k | int exact = 0; |
163 | 1.21k | const char *result = _ppdCacheGetPageSize(pc, NULL, page_size, &exact); |
164 | 1.21k | (void)result; |
165 | 1.21k | } |
166 | | |
167 | | // Test _ppdCacheGetPageSize with IPP job |
168 | 13.6k | if (num_segments > 5 && seg_sizes[5] > 0) |
169 | 189 | { |
170 | 189 | ipp_t *job = create_test_job(segments[5], seg_sizes[5]); |
171 | 189 | if (job) |
172 | 189 | { |
173 | 189 | int exact = 0; |
174 | 189 | const char *result = _ppdCacheGetPageSize(pc, job, NULL, &exact); |
175 | 189 | (void)result; |
176 | 189 | ippDelete(job); |
177 | 189 | } |
178 | 189 | } |
179 | | |
180 | | // Test _ppdCacheGetInputSlot |
181 | 13.6k | if (num_segments > 5 && seg_sizes[5] > 0) |
182 | 189 | { |
183 | 189 | ipp_t *job = create_test_job(segments[5], seg_sizes[5]); |
184 | 189 | if (job) |
185 | 189 | { |
186 | 189 | const char *result = _ppdCacheGetInputSlot(pc, job, NULL); |
187 | 189 | (void)result; |
188 | 189 | ippDelete(job); |
189 | 189 | } |
190 | 189 | } |
191 | | |
192 | | // Test _ppdCacheGetMediaType |
193 | 13.6k | if (num_segments > 5 && seg_sizes[5] > 0) |
194 | 189 | { |
195 | 189 | ipp_t *job = create_test_job(segments[5], seg_sizes[5]); |
196 | 189 | if (job) |
197 | 189 | { |
198 | 189 | const char *result = _ppdCacheGetMediaType(pc, job, NULL); |
199 | 189 | (void)result; |
200 | 189 | ippDelete(job); |
201 | 189 | } |
202 | 189 | } |
203 | | |
204 | | // Test _ppdCacheGetSize |
205 | 13.6k | if (num_segments > 1 && seg_sizes[1] > 0) |
206 | 1.21k | { |
207 | 1.21k | char page_size[256]; |
208 | 1.21k | size_t copy_len = seg_sizes[1] < sizeof(page_size) - 1 ? seg_sizes[1] : sizeof(page_size) - 1; |
209 | 1.21k | memcpy(page_size, segments[1], copy_len); |
210 | 1.21k | page_size[copy_len] = '\0'; |
211 | | |
212 | 1.21k | pwg_size_t *result = _ppdCacheGetSize(pc, page_size, NULL); |
213 | 1.21k | (void)result; |
214 | 1.21k | } |
215 | | |
216 | | // Test _ppdCacheGetFinishingValues |
217 | 13.6k | if (ppd) |
218 | 13.6k | { |
219 | 13.6k | int finishings[20]; |
220 | 13.6k | int num_finishings = _ppdCacheGetFinishingValues(ppd, pc, 20, finishings); |
221 | 13.6k | (void)num_finishings; |
222 | 13.6k | } |
223 | | |
224 | | // Test _ppdCacheGetFinishingOptions |
225 | 13.6k | if (num_segments > 5 && seg_sizes[5] > 0) |
226 | 189 | { |
227 | 189 | ipp_t *job = create_test_job(segments[5], seg_sizes[5]); |
228 | 189 | if (job) |
229 | 189 | { |
230 | 189 | cups_option_t *options = NULL; |
231 | 189 | int num_options = 0; |
232 | 189 | num_options = _ppdCacheGetFinishingOptions(pc, job, IPP_FINISHINGS_NONE, num_options, &options); |
233 | | |
234 | 189 | if (options) |
235 | 0 | { |
236 | 0 | cupsFreeOptions(num_options, options); |
237 | 0 | } |
238 | 189 | ippDelete(job); |
239 | 189 | } |
240 | 189 | } |
241 | 13.6k | } |
242 | | |
243 | | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
244 | 9.77k | { |
245 | | // Minimum size check |
246 | 9.77k | if (size < 100) |
247 | 13 | { |
248 | 13 | return 0; |
249 | 13 | } |
250 | | |
251 | | // Setup cleanup |
252 | 9.76k | atexit(cleanup_files); |
253 | | |
254 | | // Create filenames with cursor_test_ prefix |
255 | 9.76k | g_ppd_file = malloc(256); |
256 | 9.76k | g_cache_file = malloc(256); |
257 | 9.76k | if (!g_ppd_file || !g_cache_file) |
258 | 0 | { |
259 | 0 | cleanup_files(); |
260 | 0 | return 0; |
261 | 0 | } |
262 | | |
263 | 9.76k | snprintf(g_ppd_file, 256, "/tmp/cursor_test_ppd_%d.ppd", getpid()); |
264 | 9.76k | snprintf(g_cache_file, 256, "/tmp/cursor_test_cache_%d.cache", getpid()); |
265 | | |
266 | | // Parse input segments |
267 | 9.76k | const uint8_t *segments[10]; |
268 | 9.76k | size_t seg_sizes[10]; |
269 | 9.76k | int num_segments = parse_input_segments(data, size, segments, seg_sizes, 10); |
270 | | |
271 | 9.76k | if (num_segments < 1) |
272 | 49 | { |
273 | 49 | cleanup_files(); |
274 | 49 | return 0; |
275 | 49 | } |
276 | | |
277 | | // Write PPD file data |
278 | 9.71k | FILE *file = fopen(g_ppd_file, "wb"); |
279 | 9.71k | if (!file) |
280 | 0 | { |
281 | 0 | cleanup_files(); |
282 | 0 | return 0; |
283 | 0 | } |
284 | | |
285 | 9.71k | fwrite(segments[0], 1, seg_sizes[0], file); |
286 | 9.71k | fclose(file); |
287 | | |
288 | | // Open PPD file |
289 | 9.71k | ppd_file_t *ppd = ppdOpenFile(g_ppd_file); |
290 | 9.71k | if (!ppd) |
291 | 2.33k | { |
292 | 2.33k | cleanup_files(); |
293 | 2.33k | return 0; |
294 | 2.33k | } |
295 | | |
296 | | // Create cache from PPD |
297 | 7.37k | _ppd_cache_t *cache = _ppdCacheCreateWithPPD(NULL, ppd); |
298 | 7.37k | if (!cache) |
299 | 0 | { |
300 | 0 | ppdClose(ppd); |
301 | 0 | cleanup_files(); |
302 | 0 | return 0; |
303 | 0 | } |
304 | | |
305 | | // Test all cache functions |
306 | 7.37k | test_cache_functions(cache, ppd, segments, seg_sizes, num_segments); |
307 | | |
308 | | // Test cache file write/read cycle |
309 | 7.37k | if (_ppdCacheWriteFile(cache, g_cache_file, NULL)) |
310 | 7.37k | { |
311 | 7.37k | ipp_t *attrs = NULL; |
312 | 7.37k | _ppd_cache_t *cache2 = _ppdCacheCreateWithFile(g_cache_file, &attrs); |
313 | 7.37k | if (cache2) |
314 | 6.28k | { |
315 | | // Test functions on loaded cache |
316 | 6.28k | test_cache_functions(cache2, ppd, segments, seg_sizes, num_segments); |
317 | 6.28k | _ppdCacheDestroy(cache2); |
318 | 6.28k | } |
319 | 7.37k | if (attrs) |
320 | 1 | { |
321 | 1 | ippDelete(attrs); |
322 | 1 | } |
323 | 7.37k | } |
324 | | |
325 | | // Test _cupsConvertOptions if we have enough segments |
326 | 7.37k | if (num_segments > 6 && seg_sizes[6] > 0) |
327 | 597 | { |
328 | 597 | ipp_t *request = ippNewRequest(IPP_OP_PRINT_JOB); |
329 | 597 | if (request) |
330 | 597 | { |
331 | 597 | cups_option_t *options = NULL; |
332 | 597 | int num_options = 0; |
333 | | |
334 | | // Parse options from segment data |
335 | 597 | char options_str[1024]; |
336 | 597 | size_t copy_len = seg_sizes[6] < sizeof(options_str) - 1 ? seg_sizes[6] : sizeof(options_str) - 1; |
337 | 597 | memcpy(options_str, segments[6], copy_len); |
338 | 597 | options_str[copy_len] = '\0'; |
339 | | |
340 | 597 | num_options = cupsParseOptions(options_str, num_options, &options); |
341 | | |
342 | 597 | if (num_options > 0) |
343 | 579 | { |
344 | 579 | _cupsConvertOptions(request, ppd, cache, NULL, NULL, NULL, |
345 | 579 | "testuser", "application/pdf", 1, num_options, options); |
346 | 579 | cupsFreeOptions(num_options, options); |
347 | 579 | } |
348 | | |
349 | 597 | ippDelete(request); |
350 | 597 | } |
351 | 597 | } |
352 | | |
353 | | // Cleanup resources |
354 | 7.37k | _ppdCacheDestroy(cache); |
355 | 7.37k | ppdClose(ppd); |
356 | 7.37k | cleanup_files(); |
357 | | |
358 | 7.37k | return 0; |
359 | 7.37k | } |