memononen / nanosvg

Simple stupid SVG parser
zlib License
1.71k stars 363 forks source link

endless loop (DOS) when parsing crafted input via nsvgParseFromFile() #178

Closed invd closed 3 years ago

invd commented 4 years ago

Mid-June, I discovered and privately reported an endless loop issue that happens in the following usage scenario with a small crafted input file:

#include <stdint.h>
#include <stdio.h>

#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"

int main(int argc, char *argv[]) {
  // this will loop for some inputs
  NSVGimage* g_image = nsvgParseFromFile("nanosvg_loop_examplefile1.svg", "px", 96);
  return 0;
}

The expected security impact is a denial of service.

So far, I have not received a reply from @memononen. Given that nanosvg is not actively maintained (see README.md), this is somewhat expected, but I want to report the issue anyway because there might still be active users of this library that are affected by this.

@memononen : can you give some quick feedback on whether you want the details to be disclosed publicly here in the bugtracker or prefer them to stay nonpublic until the 15.9.2020 (90 days after initial disclosure)?

tesch1 commented 4 years ago

If you want to find some more to not disclose there's a fuzzer in one of the many branches. Should be totally obvious, but I'll point out that nobody security conscious should be using this library to load svgs from unknown sources.

invd commented 4 years ago

Hello @tesch1, I'm not sure that I fully understood what you were trying to say.

As far as I can see, memononen/nanosvg has no other branches, active or otherwise. Looking deeper into the topic of actual nanosvg forks, I can find your comment at https://github.com/memononen/nanosvg/commit/25241c5a8f8451d41ab1b02ab2d865b01600d949#commitcomment-35986042 and your nanosvg fork, which does have fuzzing-related changes.

Could you please clarify what you're suggesting for the disclosure of the DOS mentioned above? In particular, do you think that you've already found and publicly fixed the relevant issue in your fork, which would resolve this topic?

Correctly disclosing issues in unmaintained projects with unreachable developers is difficult, and it doesn't help that there is no visible followup project with either the blessing of the previous maintainer or many visible users (measured by Github stars, for example). Given the number of stars and forks for this original version, it is not unreasonable to assume that this code is still used somewhere to parse untrusted input. Through this Github issue, I was trying to balance the relevant pros and cons of this situation.

oehhar commented 4 years ago

The Tk project (Tcl/Tk (https://core.tcl-lang.org/tk), TkInter, TkRuby, TkPerl) are happily using svgnano and it is very helpful and very quick. We also have a maintainer issue.

Some bugs are only fixed in Tk and not necessarily reported back to the main project.

We would be glad to get more information on what is actually triggering the issue.

Thank you, Harald

invd commented 4 years ago

Interesting, so the tksvg extension and the main tcl code also carry a copy of nanosvg.h after TIP #507 in 2018, or at least some branches do. @oehhar Can you point me to a specific security contact of the Tcl/Tk project or member of the Tcl core team that is responsible for security matters so that we can discuss this privately?

invd commented 4 years ago

@oehhar, @auriocus : I'm able to reproduce the issue with the nanosvg.h variant that is shipped in the latest version of auriocus/tksvg . I will contact you via email for further discussion.

invd commented 4 years ago

Here is the nanosvg_loop_examplefile1.svg file that can be used to verify the issue: nanosvg_loop_examplefile1.svg.zip

21 bytes are sufficient to trigger the problem:

00000000  3c 67 20 74 72 61 6e 73  66 6f 72 6d 3d 22 73 6b  |<g transform="sk|
00000010  65 77 58 28 31 20 31 29  3e                       |ewX(1 1)>|
fvogelnew1 commented 4 years ago

Quick fix proposal in Tk here

oehhar commented 4 years ago

Here is the patch authored by fvogel:

--- generic/nanosvg.h
+++ generic/nanosvg.h
@@ -1668,29 +1668,36 @@
 }

 static void nsvg__parseTransform(float* xform, const char* str)
 {
    float t[6];
+        int len;
    nsvg__xformIdentity(xform);
    while (*str)
    {
        if (strncmp(str, "matrix", 6) == 0)
-           str += nsvg__parseMatrix(t, str);
+           len = nsvg__parseMatrix(t, str);
        else if (strncmp(str, "translate", 9) == 0)
-           str += nsvg__parseTranslate(t, str);
+           len = nsvg__parseTranslate(t, str);
        else if (strncmp(str, "scale", 5) == 0)
-           str += nsvg__parseScale(t, str);
+           len = nsvg__parseScale(t, str);
        else if (strncmp(str, "rotate", 6) == 0)
-           str += nsvg__parseRotate(t, str);
+           len = nsvg__parseRotate(t, str);
        else if (strncmp(str, "skewX", 5) == 0)
-           str += nsvg__parseSkewX(t, str);
+           len = nsvg__parseSkewX(t, str);
        else if (strncmp(str, "skewY", 5) == 0)
-           str += nsvg__parseSkewY(t, str);
+           len = nsvg__parseSkewY(t, str);
        else{
            ++str;
            continue;
        }
+                if (len != 0) {
+           str += len;
+                } else {
+           ++str;
+           continue;
+                }

        nsvg__xformPremultiply(xform, t);
    }
 }
invd commented 4 years ago

The merged patch appears to resolve the loop issue :+1:

@memononen: additional fuzzing brings up more issues. Please indicate how you want those to be reported. If I don't receive any feedback from you then I will report them in 2 weeks via public Github issue tickets in this repository.

memononen commented 4 years ago

@invd please report them as you find them, I'll try to find time to merge PRs if they surface. @oehhar Do you have time/resources/motivation to look into invd's findings?

oehhar commented 4 years ago

Tierve Mikko, thank you for the great project. It serves each day and makes applications and live beautiful. Thanks, invd. I appreciate to take care about security. I am more the messanger. The tk community (core.tcl.tk/tk) member fvogel had solved the first ticket. I will try again to support the process and bring issues and solutions from one world to the other.

Thank you, Harald

memononen commented 4 years ago

Thanks Harald. I happened to have few hours to spare, so I fixed the to latest findings from @invd

invd commented 3 years ago

I think this issue can be closed.