sammycage / lunasvg

lunasvg is a standalone SVG rendering library in C++
MIT License
818 stars 115 forks source link

Fix for UB caused by null pointer arithmetic #126

Closed m-carrasco closed 1 year ago

m-carrasco commented 1 year ago

Hi :wave:

Issue

According to the C standard, pointer arithmetic on a NULL pointer is undefined behavior. LunaSVG can trigger this issue using valid SVG files. Clang's UB sanitiser confirms this. This could cause portability and security issues while changing compilers or compilation flags.

lunasvg/3rdparty/plutovg/plutovg-ft-stroker.c:656:47: runtime error: applying zero offset to null pointer
    #0 0x788046 in ft_stroke_border_export lunasvg/3rdparty/plutovg/plutovg-ft-stroker.c:656:47
    #1 0x786d57 in PVG_FT_Stroker_ExportBorder lunasvg/3rdparty/plutovg/plutovg-ft-stroker.c:1750:29
    #2 0x788890 in PVG_FT_Stroker_Export lunasvg/3rdparty/plutovg/plutovg-ft-stroker.c:1758:5
    #3 0x720bca in plutovg_rle_rasterize lunasvg/3rdparty/plutovg/plutovg-rle.c:243:9
    #4 0x6d6065 in plutovg_stroke_preserve lunasvg/3rdparty/plutovg/plutovg.c:470:5
    #5 0x6d5c24 in plutovg_stroke lunasvg/3rdparty/plutovg/plutovg.c:429:5
    #6 0x638fa3 in lunasvg::Canvas::stroke(lunasvg::Path const&, lunasvg::Transform const&, double, lunasvg::LineCap, lunasvg::LineJoin, double, lunasvg::DashData const&, lunasvg::BlendMode, double) lunasvg/source/canvas.cpp:116:5
    #7 0x5fa0c4 in lunasvg::StrokeData::stroke(lunasvg::RenderState&, lunasvg::Path const&) const lunasvg/source/layoutcontext.cpp:344:19
    #8 0x5fc73b in lunasvg::LayoutShape::render(lunasvg::RenderState&) const lunasvg/source/layoutcontext.cpp:409:20
    #9 0x5ed612 in lunasvg::LayoutContainer::renderChildren(lunasvg::RenderState&) const lunasvg/source/layoutcontext.cpp:88:16
    #10 0x5f10b6 in lunasvg::LayoutSymbol::render(lunasvg::RenderState&) const lunasvg/source/layoutcontext.cpp:159:5
    #11 0x50232e in lunasvg::Document::render(lunasvg::Bitmap, lunasvg::Matrix const&) const lunasvg/source/lunasvg.cpp:343:11
    #12 0x503c1a in lunasvg::Document::renderToBitmap(unsigned int, unsigned int, unsigned int) const lunasvg/source/lunasvg.cpp:368:5
    #13 0x4f44b3 in main lunasvg/example/svg2png.cpp:54:29
    #14 0x7f3d8c7c4082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
    #15 0x430bbd in _start (lunasvg/build/example/svg2png+0x430bbd)

Test Cases

Steps

  1. Clone: git clone https://github.com/sammycage/lunasvg.git && cd lunasvg
  2. Build with sanitisers: mkdir build && cd build && CXX=clang++ CC=clang cmake -DLUNASVG_BUILD_EXAMPLES=ON -DCMAKE_CXX_FLAGS="-g -O0 -fsanitize=undefined,address -fno-sanitize-recover=all" -DCMAKE_C_FLAGS="-g -O0 -fsanitize=undefined,address -fno-sanitize-recover=all" ../ && make -j4
  3. Download SVGs (this is just for one): wget -O example.svg https://user-images.githubusercontent.com/3461126/225989850-39e47b2f-fb16-4163-a193-ff3ea2801c1b.svg
  4. Run with sanitisers: UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 ASAN_OPTIONS=halt_on_error=1 ./example/svg2png example.svg

Fix

Add checks to prevent pointer arithmetic on NULL pointers.