sammycage / plutosvg

Tiny SVG rendering library in C
MIT License
247 stars 17 forks source link

Program Hangs After Multiple SIGWINCH Signals or maybe Infinite loop #13

Closed kittener closed 1 month ago

kittener commented 2 months ago

Hello, My fuzzer found a strange file that seemed to keep the program occupying resources and unable to stop.

Description

The program consistently hangs after attempting to map a significant amount of memory (~1.66 GB) and receiving multiple SIGWINCH signals. This behavior suggests a potential issue with signal handling or memory management under specific conditions.

Steps to Reproduce

  1. Compile the application.
  2. Run the application using the following command: example poc.png

poc4.zip

More details

When I use strace to track the program, I find the output is like this:

execve("./example", ["./example", "/home/kittener/Documents/crash/p"...], 0x7ffedac63d28 /* 60 vars */) = 0
brk(NULL)                               = 0x5579fde3b000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff9e1618a0) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=81183, ...}) = 0
mmap(NULL, 81183, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9d95246000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\323\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=1369384, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9d95244000
mmap(NULL, 1368336, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f9d950f5000
mmap(0x7f9d95102000, 684032, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd000) = 0x7f9d95102000
mmap(0x7f9d951a9000, 626688, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xb4000) = 0x7f9d951a9000
mmap(0x7f9d95242000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14c000) = 0x7f9d95242000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300A\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\7\2C\n\357_\243\335\2449\206V>\237\374\304"..., 68, 880) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2029592, ...}) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\7\2C\n\357_\243\335\2449\206V>\237\374\304"..., 68, 880) = 68
mmap(NULL, 2037344, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f9d94f03000
mmap(0x7f9d94f25000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f9d94f25000
mmap(0x7f9d9509d000, 319488, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19a000) = 0x7f9d9509d000
mmap(0x7f9d950eb000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f9d950eb000
mmap(0x7f9d950f1000, 13920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f9d950f1000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9d94f00000
arch_prctl(ARCH_SET_FS, 0x7f9d94f00740) = 0
mprotect(0x7f9d950eb000, 16384, PROT_READ) = 0
mprotect(0x7f9d95242000, 4096, PROT_READ) = 0
mprotect(0x5579fdc83000, 8192, PROT_READ) = 0
mprotect(0x7f9d95287000, 4096, PROT_READ) = 0
munmap(0x7f9d95246000, 81183)           = 0
brk(NULL)                               = 0x5579fde3b000
brk(0x5579fde5c000)                     = 0x5579fde5c000
openat(AT_FDCWD, "/home/kittener/Documents/crash/crash/poc", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0666, st_size=1380, ...}) = 0
fstat(3, {st_mode=S_IFREG|0666, st_size=1380, ...}) = 0
lseek(3, 0, SEEK_SET)                   = 0
read(3, "<?xml ven=\"1.0\" ding=\"utf-8\"one="..., 1380) = 1380
lseek(3, 1380, SEEK_SET)                = 1380
close(3)                                = 0
mmap(NULL, 1786175488, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9d2a792000
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---

Then I used the debugger to check and found that it seemed to be accessing the child nodes in render_element

by, kaiyu Xie

sammycage commented 1 month ago

@kittener Resolved in the latest commit. Thank you for bringing this issue to our attention.