Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
schsiung opened this issue Nov 23, 2023 · 3 comments · Fixed by #834
Closed

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

schsiung opened this issue Nov 23, 2023 · 3 comments · Fixed by #834
Labels
bug Something isn't working priority-medium

Comments

@schsiung
Copy link

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
  1. 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
  1. 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=<optimized out>)
[#1] 0x555555707c08 → _cupsRasterExecPS(h=<optimized out>, preferred_bits=<optimized out>, code=<optimized out>)
[#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

@zdohnal
Copy link
Member

zdohnal commented Nov 23, 2023

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?

@zdohnal zdohnal added bug Something isn't working priority-medium waiting for reporter There are data requested from the reporter labels Nov 23, 2023
@schsiung
Copy link
Author

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

@zdohnal zdohnal removed the waiting for reporter There are data requested from the reporter label Nov 24, 2023
@zdohnal
Copy link
Member

zdohnal commented Nov 24, 2023

@schsiung Thanks! I'll file PR.

zdohnal added a commit to zdohnal/cups that referenced this issue Nov 24, 2023
Fuzzer using `_cupsRasterExecPS()` found a way how to pass NULL into
`scan_ps()`, causing crash - we have to sanitize the argument for NULL
to fix it.

Fixes OpenPrinting#831
zdohnal added a commit that referenced this issue Nov 27, 2023
Fuzzer using _cupsRasterExecPS() found a way how to pass NULL into scan_ps(), causing crash - we have to sanitize the argument for NULL to fix it.

Fixes #831
zdohnal added a commit that referenced this issue Nov 27, 2023
Fuzzer using `_cupsRasterExecPS()` found a way how to pass NULL into
`scan_ps()`, causing crash - we have to sanitize the argument for NULL
to fix it.

Fixes #831
tillkamppeter pushed a commit to OpenPrinting/libppd that referenced this issue Dec 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working priority-medium
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants