OpenPrinting / cups

OpenPrinting CUPS Sources
https://openprinting.github.io/cups
Apache License 2.0
967 stars 177 forks source link

Segmentation fault with raster-interpret.c:1055 #831

Closed schsiung closed 7 months ago

schsiung commented 7 months ago

Describe the bug I have found SIGSEGV crashes with cups of version #v2.4.7 when running some fuzzing tests. here is the fuzzing code I use: fuzzer.tar.gz

FuzzCUPS.c

/* Copyright 2022 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
      http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#undef _CUPS_NO_DEPRECATED
#include "cups-private.h"
#include "ppd-private.h"
#include "raster-private.h"
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>

#define kMinInputLength 10
#define kMaxInputLength 10240

extern int
LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{/*cups/cups/testppd.c*/

    if (Size < kMinInputLength || Size > kMaxInputLength){
        return 1;
    }

/*Add Null byte*/
    char *DataFx;
    size_t SizeFx = Size+1;
    DataFx = (char *)calloc(SizeFx,sizeof(char));
    memcpy((void *)DataFx,(void *)Data,Size);

    int preferred_bits;
    cups_page_header2_t header;

    memset(&header, 0, sizeof(header));
    header.Collate = CUPS_TRUE;
    preferred_bits = 0;

    _cupsRasterExecPS(&header, &preferred_bits,(char*)DataFx);

    free(DataFx);
    return 0;
}

__AFL_FUZZ_INIT();

int main(int argc,char **argv) {

  // anything else here, e.g. command line arguments, initialization, etc.

#ifdef __AFL_HAVE_MANUAL_CONTROL
  __AFL_INIT();
#endif

  unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;  // must be after __AFL_INIT
                                                 // and before __AFL_LOOP!

  while (__AFL_LOOP(10000)) {

    int len = __AFL_FUZZ_TESTCASE_LEN;  // don't use the macro directly in a
    //                                     // call!

    // if (len < 8) continue;  // check for a required/useful minimum input length

    LLVMFuzzerTestOneInput(buf,len);
    /* Reset state. e.g. libtarget_free(tmp) */

  }

  return 0;

}

To Reproduce Steps to reproduce the behavior:

  1. add the fuzzer tarball under cups and run make
    ❯ ls
    core  FuzzCUPS  FuzzCUPS.c  FuzzCUPS.o  FuzzIPP  FuzzIPP.c  FuzzIPP.o  FuzzRaster  FuzzRaster.c  FuzzRaster.o  in1  in2  in3  Makefile  out1  out2  out3  out_analysis  seeds
    ❯ pwd
    /mnt/workspace/src-openeuler/cups/fuzzer
  2. run ./FuzzCUPS < out1/default/crashes/id:000051,sig:11,src:000906,time:819791,execs:36265773,op:havoc,rep:3
    
    ❯ ./FuzzCUPS < out1/default/crashes/id:000051,sig:11,src:000906,time:819791,execs:36265773,op:havoc,rep:3
    AddressSanitizer:DEADLYSIGNAL
    =================================================================
    ==427681==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x56396534cc08 bp 0x7ffd07488610 sp 0x7ffd074883c0 T0)
    ==427681==The signal is caused by a READ memory access.
    ==427681==Hint: address points to the zero page.
    #0 0x56396534cc08 in scan_ps /mnt/workspace/src-openeuler/cups/cups/raster-interpret.c:1055:20
    #1 0x56396534cc08 in _cupsRasterExecPS /mnt/workspace/src-openeuler/cups/cups/raster-interpret.c:542:17
    #2 0x56396534a340 in LLVMFuzzerTestOneInput /mnt/workspace/src-openeuler/cups/fuzzer/FuzzCUPS.c:45:5
    #3 0x56396534a829 in main /mnt/workspace/src-openeuler/cups/fuzzer/FuzzCUPS.c:71:5
    #4 0x7f5a3b6461c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #5 0x7f5a3b646284 in __libc_start_main csu/../csu/libc-start.c:360:3
    #6 0x563965216750 in _start (/mnt/workspace/src-openeuler/cups/fuzzer/FuzzCUPS+0x7d750)

AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV /mnt/workspace/src-openeuler/cups/cups/raster-interpret.c:1055:20 in scan_ps ==427681==ABORTING


3. See error with gdb debug info:

$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification] $cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ──── 0x00007fffffffd2a0│+0x0000: 0x00000a0400000002 → 0x0000000000000000 ← $rbx, $rsp 0x00007fffffffd2a8│+0x0008: 0x00007ffff5700170 → 0x0000000000000000 0x00007fffffffd2b0│+0x0010: 0x00007ffff5700100 → 0x0000000000000001 0x00007fffffffd2b8│+0x0018: 0x0000000000000000 0x00007fffffffd2c0│+0x0020: 0x00000ffffeae0020 → 0x0000000000000000 0x00007fffffffd2c8│+0x0028: 0x000051e0000010b9 → " 6666666666666666666666666666666666666666666666666[...]" 0x00007fffffffd2d0│+0x0030: 0x00007ffff570010e → 0x0000000000000000 0x00007fffffffd2d8│+0x0038: 0x0000502000000010 → 0x000000400000000b → 0x0000000000000000 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ──── 0x555555707bf8 <_cupsRasterExecPS+1224> movzx eax, BYTE PTR [r13+0x7fff8000] 0x555555707c00 <_cupsRasterExecPS+1232> test al, al 0x555555707c02 <_cupsRasterExecPS+1234> jne 0x555555707d77 <_cupsRasterExecPS+1607> → 0x555555707c08 <_cupsRasterExecPS+1240> movzx r12d, BYTE PTR [r15] 0x555555707c0c <_cupsRasterExecPS+1244> cmp r12d, 0x25 0x555555707c10 <_cupsRasterExecPS+1248> je 0x555555707cb0 <_cupsRasterExecPS+1408> 0x555555707c16 <_cupsRasterExecPS+1254> test r12d, r12d 0x555555707c19 <_cupsRasterExecPS+1257> je 0x55555570dd1e <_cupsRasterExecPS+26094> 0x555555707c1f <_cupsRasterExecPS+1263> mov QWORD PTR [rbx+0x18], r15 ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:raster-interpret.c+1055 ──── 1050
1051 / 1052 Skip leading whitespace... 1053 / 1054
→ 1055 for (cur =
ptr; cur; cur ++) 1056 { 1057 if (cur == '%') 1058 { 1059 / 1060 Comment, skip to end of line... ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ──── [#0] Id 1, Name: "FuzzCUPS", stopped 0x555555707c08 in scan_ps (), reason: SIGSEGV ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ──── [#0] 0x555555707c08 → scan_ps(st=0x502000000010, ptr=) [#1] 0x555555707c08 → _cupsRasterExecPS(h=, preferred_bits=, code=) [#2] 0x555555705341 → LLVMFuzzerTestOneInput(Data=0x555556277240 <__afl_fuzz_alt> "<</MediaClass(Mes)/MediaColor(M\\TypeCollate \202alse/CutM\350\003ia 2/Duplex ance 1000/AdvanceMedia 1/)/utTyp[5 -2 roll]/e/[100 200]/InsertSheet true/Jog 3/LeadingEdge 1/ManudlFeed true/MediaPosition 8#777/MediaupsInt 16#fe01/MirrorPrint true/NegativePrint true/NumCopies //Orientation 1/OutputFaceUp true/PageSize[612 7]/Separations true/TraySwitch true/Tumble true/a 2/cupsColorOrder 1/cupsColorSpace 1/cupsCompression 1/cupsRowCount 1/cupsRs true/Trayindex>>setpagedevice\npop true false dup\n<</Cex true/HWResolution[10 index/Tumble 6 index>>setpagedevice\npop pop true false dup\n<</Cex true/HWResolution[10 index/Tumble 6 index>>setpagedevice\npop pop [{<</aCylassCex true/HWResolution[10 index/Tumble 6 index>>setpagedevice\npop pop true false dup\n<</Cex true/HWResolution[10 index/Tindex>>setpagedevice\npop pop [{<</aCylass(Mes)/Mon[10 index/Tumble 6 index>>setpagedevice\npop pop true false dup\n<</Cex true/HWResolution[10 index/Tumblx>>setpagedevice\npop pop [{<</aC true/HWResolution[10 index/Tumble 6 index>>setpagedevice\npop pop true false dup\n<</Cex true/HWResolution[10 index/Tumble ", '6' <repeats 1348 times>, " index>>setpagedevice\npop pop [{<</aCylass(Mes)/MediaColor((Mor))/MediaType(M\\Tyllate faedia 1/)/OutputType<41>/rue/[100]/InsertSheet\npop pop true false dup\n<</Lex true/HWResolution[10 index/Tumble 6 index>>setpagedevice\npop pop [{<</aCylasr('Cor))/MediaType(M\\TypeCollatCutMQdianceMedia 1/)/OutputType<41>/rue/[100]/Int true/Jog 3/LeadingEdge 1/ManualFeed true/MediaPosition 8#777/Med (Lr)/cu true/NegativePrint true/NumCopies 1/Oon true/MediaPosition 8 1/OutputFaze[612 792.1utputFaze[792.orde777/", Size=0xb73) [#3] 0x55555570582a → main(argc=0x1, argv=0x7fffffffd788) ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── gef➤



**Expected behavior**
add proper validations for the misused inputs and display the right error message

**System Information:**
 - OS and its version: debian, 12
 - Application [e.g. chrome, safari, evince...]
 - CUPS version [e.g. 2.4.7]

**From**
From: [xiongshengchao@jyhlab.org.cn](mailto:xiongshengchao@jyhlab.org.cn)
zdohnal commented 7 months ago

Hi @schsiung ,

thank you for the report! I'm not able to compile your fuzzer due missing deps on Fedora and precompiled version does not work for me, but from the place and function where it crashed I suppose *ptr is NULL (ptr is optimized out and I don't understand assembler well here) and the binary crashes when it tries to dereference it.

Then the fix would be:

 /*
  * Skip leading whitespace...
  */

+ if (!*ptr)
+   return (NULL);

  for (cur = *ptr; *cur; cur ++)
  {
     if (*cur == '%')

Can you apply it and tell if it helps?

schsiung commented 7 months ago

@zdohnal I have merged your fix code locally and It looks to be a valid fix for the aforementioned crashes.

zdohnal commented 7 months ago

@schsiung Thanks! I'll file PR.