Lymphatus / caesium-clt

Caesium Command Line Tools - Lossy/lossless image compression tool
http://saerasoft.com/caesium
Other
354 stars 34 forks source link

a hang bug or a DoS bug #41

Closed buptsseGJ closed 4 years ago

buptsseGJ commented 4 years ago

Hello, I found the hang bug in the master version of caesiumclt binary or its library.

Below are steps followed to reproduce the bug. I used GCC 5.4 and AddressSanitizer (export CFLAGS="-g -fsanitize=address" CXXFLAGS="-g -fsanitize=address" LDFLAGS="-fsanitize=address" before make) to build it, this test file can cause hang bug.

Test case: hang.png

I tried to debug it with gdb using the following command: ./build/src/caesiumclt -q 80 -s 0.5 -o out hang.png After typing r command, it hanged, so I type Ctrl+c to interrupt it. The debug output is listed below:

stbi__zexpand (n=1, zout=0x7fffae5fb800 "", z=0x7fffffff7fa0) at /root/--/libcaesium/caesium/vendor/stb_image.h:3905
3905          limit *= 2;
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
──────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────
 RAX  0x44000001
 RBX  0x1
 RCX  0xfffffffeffa ◂— 0x0
 RDX  0x44000000
 RDI  0x7fff6a5fb800 ◂— 0x2220122222212200
 RSI  0x0
 R8   0x0
 R9   0x0
 R10  0xfffffffeff8 ◂— 0x0
 R11  0x44000000
 R12  0x7fffffff7fa0 —▸ 0x621000019167 ◂— 0xbebebebebebebebe
 R13  0x7fffffff7fc8 —▸ 0x7fffae5fb800 ◂— 0x0
 R14  0x7fffffff7fb4 ◂— 0xae5fb80000000000
 R15  0x7fffffff7fc0 —▸ 0x7fff6a5fb800 ◂— 0x2220122222212200
 RBP  0x22
 RSP  0x7fffffff7d50 —▸ 0x7fffffff7fb0 ◂— 0x1d
 RIP  0x7ffff6b5cba0 (stbi.parse_zlib+1584) ◂— add    esi, esi
────────────────────────────────────────────────────────────────[ DISASM ]────────────────────────────────────────────────────────────────
 ► 0x7ffff6b5cba0 <stbi.parse_zlib+1584>    add    esi, esi
   0x7ffff6b5cba2 <stbi.parse_zlib+1586>    cmp    eax, esi
   0x7ffff6b5cba4 <stbi.parse_zlib+1588>    jg     stbi.parse_zlib+1584 <0x7ffff6b5cba0>
    ↓
 ► 0x7ffff6b5cba0 <stbi.parse_zlib+1584>    add    esi, esi
   0x7ffff6b5cba2 <stbi.parse_zlib+1586>    cmp    eax, esi
   0x7ffff6b5cba4 <stbi.parse_zlib+1588>    jg     stbi.parse_zlib+1584 <0x7ffff6b5cba0>
    ↓
 ► 0x7ffff6b5cba0 <stbi.parse_zlib+1584>    add    esi, esi
   0x7ffff6b5cba2 <stbi.parse_zlib+1586>    cmp    eax, esi
   0x7ffff6b5cba4 <stbi.parse_zlib+1588>    jg     stbi.parse_zlib+1584 <0x7ffff6b5cba0>
    ↓
 ► 0x7ffff6b5cba0 <stbi.parse_zlib+1584>    add    esi, esi
   0x7ffff6b5cba2 <stbi.parse_zlib+1586>    cmp    eax, esi
────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────
In file: /root/--/libcaesium/caesium/vendor/stb_image.h
   3900    z->zout = zout;
   3901    if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
   3902    cur   = (int) (z->zout     - z->zout_start);
   3903    limit = old_limit = (int) (z->zout_end - z->zout_start);
   3904    while (cur + n > limit)
 ► 3905       limit *= 2;
   3906    q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
   3907    STBI_NOTUSED(old_limit);
   3908    if (q == NULL) return stbi__err("outofmem", "Out of memory");
   3909    z->zout_start = q;
   3910    z->zout       = q + cur;
────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffff7d50 —▸ 0x7fffffff7fb0 ◂— 0x1d
01:0008│      0x7fffffff7d58 —▸ 0x7fffffff7fa8 —▸ 0x621000019167 ◂— 0xbebebebebebebebe
02:0010│      0x7fffffff7d60 —▸ 0x7fffffff7fb8 —▸ 0x7fffae5fb800 ◂— 0x0
03:0018│      0x7fffffff7d68 ◂— 0x22000000
04:0020│      0x7fffffff7d70 ◂— 0x212
05:0028│      0x7fffffff7d78 ◂— 0x38 /* '8' */
06:0030│      0x7fffffff7d80 —▸ 0x7fffffff841c ◂— 0x1000000010000
07:0038│      0x7fffffff7d88 —▸ 0x107000000 ◂— 0x0
──────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────
 ► f 0     7ffff6b5cba0 stbi.parse_zlib+1584
   f 1     7ffff6b5cba0 stbi.parse_zlib+1584
   f 2     7ffff6b5cba0 stbi.parse_zlib+1584
   f 3     7ffff6ba2253 stbi_zlib_decode_malloc_guesssize_headerflag+307
   f 4     7ffff6ba2253 stbi_zlib_decode_malloc_guesssize_headerflag+307
   f 5     7ffff6ba43ee stbi.parse_png_file+7966
   f 6     7ffff6bab1dc stbi.load_main+4044
   f 7     7ffff6bab1dc stbi.load_main+4044
   f 8     7ffff6bab1dc stbi.load_main+4044
   f 9     7ffff6bc9f08 stbi.load_and_postprocess_8bit+296
   f 10     7ffff6bcac2a stbi_load_from_file+442
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Program received signal SIGINT

The call stack is shown below:

>bt
#0  stbi__zexpand (n=1, zout=0x7fffae5fb800 "", z=0x7fffffff7fa0) at /root/--/libcaesium/caesium/vendor/stb_image.h:3905
#1  stbi__parse_huffman_block (a=0x7fffffff7fa0) at /root/--/libcaesium/caesium/vendor/stb_image.h:3937
#2  stbi__parse_zlib (a=a@entry=0x7fffffff7fa0, parse_header=parse_header@entry=1) at /root/--/libcaesium/caesium/vendor/stb_image.h:4113
#3  0x00007ffff6ba2253 in stbi__do_zlib (parse_header=1, exp=1, olen=<optimized out>, obuf=<optimized out>, a=0x7fffffff7fa0) at /root/--/libcaesium/caesium/vendor/stb_image.h:4126
#4  stbi_zlib_decode_malloc_guesssize_headerflag (buffer=<optimized out>, len=len@entry=103, initial_size=<optimized out>, outlen=outlen@entry=0x7fffffff9140, parse_header=parse_header@entry=1) at /root/--/libcaesium/caesium/vendor/stb_image.h:4157
#5  0x00007ffff6ba43ee in stbi__parse_png_file (z=z@entry=0x7fffffff98b0, scan=scan@entry=0, req_comp=req_comp@entry=0) at /root/--/libcaesium/caesium/vendor/stb_image.h:4798
#6  0x00007ffff6bab1dc in stbi__do_png (ri=<optimized out>, req_comp=0, n=<optimized out>, y=0x7fffffff9df0, x=0x7fffffff9db0, p=0x7fffffff98b0) at /root/--/libcaesium/caesium/vendor/stb_image.h:4856
#7  stbi__png_load (ri=<optimized out>, req_comp=0, comp=<optimized out>, y=0x7fffffff9df0, x=0x7fffffff9db0, s=0x7fffffff9c00) at /root/--/libcaesium/caesium/vendor/stb_image.h:4886
#8  stbi__load_main (s=0x7fffffff9c00, x=<optimized out>, y=<optimized out>, comp=<optimized out>, req_comp=<optimized out>, ri=<optimized out>, bpc=8) at /root/--/libcaesium/caesium/vendor/stb_image.h:967
#9  0x00007ffff6bc9f08 in stbi__load_and_postprocess_8bit (s=<optimized out>, x=0x7fffffff9db0, y=0x7fffffff9df0, comp=0x7fffffff9e30, req_comp=0) at /root/--/libcaesium/caesium/vendor/stb_image.h:1060
#10 0x00007ffff6bcac2a in stbi_load_from_file (f=f@entry=0x61600000f680, x=x@entry=0x7fffffff9db0, y=y@entry=0x7fffffff9df0, comp=comp@entry=0x7fffffff9e30, req_comp=req_comp@entry=0) at /root/--/libcaesium/caesium/vendor/stb_image.h:1146
#11 0x00007ffff6bcadb4 in stbi_load (filename=filename@entry=0x60200000efd0 "hang", x=x@entry=0x7fffffff9db0, y=y@entry=0x7fffffff9df0, comp=comp@entry=0x7fffffff9e30, req_comp=req_comp@entry=0) at /root/--/libcaesium/caesium/vendor/stb_image.h:1136
#12 0x00007ffff6be6bae in cs_png_resize (input=input@entry=0x60200000efd0 "hang", output=output@entry=0x60400000dfd0 "/root/--/caesium-clt/out/hang", factor=<optimized out>) at /root/--/libcaesium/caesium/png.c:93
#13 0x00007ffff6be7460 in cs_png_optimize (input=input@entry=0x60200000efd0 "hang", output=output@entry=0x60400000dfd0 "/root/--/caesium-clt/out/hang", options=options@entry=0x7fffffffc238) at /root/--/libcaesium/caesium/png.c:24
#14 0x00007ffff6b1957f in cs_compress (input_path=0x60200000efd0 "hang", output_path=output_path@entry=0x60400000dfd0 "/root/--/caesium-clt/out/hang", options=options@entry=0x7fffffffc210, err_n=err_n@entry=0x7fffffffa134) at /root/--/libcaesium/caesium/caesium.c:39
#15 0x0000000000409f57 in start_compression (options=options@entry=0x7fffffffc260, parameters=parameters@entry=0x7fffffffc210) at /root/--/caesium-clt/src/helper.c:310
#16 0x0000000000401de3 in main (argc=argc@entry=8, argv=argv@entry=0x7fffffffe388) at /root/--/caesium-clt/src/main.c:45
#17 0x00007ffff6457830 in __libc_start_main (main=0x401c60 <main>, argc=8, argv=0x7fffffffe388, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe378) at ../csu/libc-start.c:291
#18 0x0000000000402099 in _start ()

I hope this helps you.

Lymphatus commented 4 years ago

Judging by the stack trace, could be a bug with the resize feature. Can you please tun the same command without -s 0.5 and see if it works?

buptsseGJ commented 4 years ago

Following your suggestion, I remove the -s 0.5 option and the output looks like this:

Collecting files...
(1/1) hang.png -> /root/--/caesium-clt/out/hang.png
[ERROR] 301: Unrecognized error.
Lymphatus commented 4 years ago

The problem is not with caesiumclt itself, but with zopflipng, the library used for the compression. To be more specific, the library cannot load the PNG file due to invalid CRC and returns Decoding error 57: invalid CRC encountered (checking CRC can be disabled)

As a test, I just re-saved your image from a photo editing application and all went fine. The only solution would be not to check the CRC, but I think this might not be the best option.