I’ve done a lot of dynamic program analysis on hardware wallet software in the last years. In June, I decided to spend some time on analyzing a few popular open source C parser projects to have a change of scenery and see if I could find interesting security issues there. One goal of this research was to get more experience with a variety of different codebases for fuzzing and develop a better understanding of related challenges.

This article describes some results of this research.

Analyzed Projects

Methodology: to select interesting, unexplored and somewhat “relevant” open source software to fuzz, I picked

  • half a dozen parser projects
  • written in pure C
  • with a high number of Github stars
  • no visible fuzzer usage

Summary

Project Description Maintenance status Security issues Non-security issues
gpmf-parser Metadata parsing for GoPro cameras active see separate article GH101, GH102, GH103, GH104
iniparser Configuration file parser library active - last commit 2019 GH125 - full disclosure on maintainer request -
libconfuse Configuration file parser library active #1 - fix released with v3.3 -
libinjection SQL and JS injection detection library maintainer change - GH150 - out of bounds read based on a documentation problem, undefined behavior
minmea Simple GPS parser library active - last commit 2019 - GH56 - undefined behavior
nanosvg Simple SVG parser “not actively maintained” GH178 - no maintainer feedback, public after 90 days, fixed -
tinyexpr Evaluation engine for math expressions active - last commit 2018 GH62 - full disclosure on maintainer request undefined behavior, see GH62

Selection of Discovered Issues

Here are two exemplary bugs that I found:

iniparser Library DOS

When attempting to fetch a boolean configuration flag from a specially prepared .ini file, the library will crash due to incorrect error handling.

Relevant code:

    c = iniparser_getstring(d, key, INI_INVALID_KEY);
    if (c==INI_INVALID_KEY) return notfound ;
    if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {

iniparser.c

If the key entry is not found then c == NULL, leading to a segfault on the c[0] read access.

libconfuse Library DOS

When attempting to parse a specially prepared .conf file, the library will loop forever in cfg_getopt_secidx() due to incorrect program logic.

Here is the shortened program section (GBD view) that the program is stuck on:

265		while (name && *name) {
267			size_t len = strcspn(name, "|=");
[...]
269			if (!index && name[len] == 0 /*len == strlen(name) */ )
[...]
273			if (len) {
[...]
327			name += len;
328			name += strspn(name, "|");
329		}

confuse.c

Relevant state:

(gdb) print name
$2 = 0x604000000090 "="
(gdb) print len
$3 = 0
(gdb) print index
$4 = (long *) 0x0

The string processing never advances since len == 0. An example input file which causes this is "=" (three characters).

Recommendation for Developers

Similar to the recommendations section in base64 C parser issues, here are some words of advice to developers:

  • Writing parsers in C without introducing security issues is hard. If possible, pick a safer language to do this.
  • For hardening, you should really consider fuzzing as an extension to unit tests.
  • Unless your parser was extensively fuzzed or audited, it will likely have at least some denial of service issue when parsing arbitrary input data.
  • Fuzzing will also help you to spot and remove undefined behavior problems from your code. It is better to do this before the compiler introduces weird bugs into your binaries.

Recommendation for Maintainers

General advice for popular open source projects:

  • Clearly document the current project maintenance status. This simplifies the life of everyone involved.
  • List a dedicated security contact email address or contact method, for example in your README.md or SECURITY.md .
  • If you have a PGP key for confidential reports, please list it together with the security contact.
  • If you want to restrict security reports (and CVEs) to some parts of your project then clearly describe the intended scope in a public place.
  • Acknowledge the receipt of disclosure emails within a few work days, even if you don’t have time to read their contents. Among other things, this rules out unfortunate “outdated email address” / “aggressive spam filter” situations, which is helpful.

In short: make proper reporting of a confidential issue as straightforward and unambiguous as possible. This will increase the chances that people will actually take the time and effort to report issues confidentially - or at all.

Disclosure Timelines

gpmf-parser

See the separate GPMF-parser article.

iniparser

Date information
2020-06-18 Private disclosure to the maintainers maintainers with PGP
2020-06-18 Retransmission of the private report without PGP
2020-06-18 Maintainer replies and requests full disclosure
2020-06-19 Full disclosure via public Github issue
2020-06-22 Additional communication about security considerations

libconfuse

Date information
2020-06-18 Private disclosure to the maintainers with PGP
2020-06-20 Discussion of the issue
2020-06-21 Public patch on Github
2020-06-25 Release v3.3 includes the patch, changelog describes the underlying issue

libinjection

Date information
2020-06-18 Private disclosure to the maintainer
2020-06-25 Followup request to the maintainer for a reply
2020-08-01 Public Github issue with high-level issue description and request for feedback
2020-08-03 Public feedback and indications for maintainer switch
2020-08-04 Private disclosure to new maintainer
2020-08-07 Internal discussion of proposed patches
2020-08-17 Documentation issue is detected, security assessment changes
2020-08-27 Public Github notice about documentation issue

nanosvg

Date information
2020-06-17 Private disclosure to the maintainer
2020-08-01 Public Github issue with high-level issue description and request for feedback
2020-08-17 Developer from the Tk project requests more information
2020-08-23 Private email to two Tk developers
2020-08-25 Tk developer relays private email contents to public mailing list
2020-08-25 Termination of private disclosure to the Tk developers
2020-09-16 Public disclosure of POC input on Github after 90 days
2020-09-16 Public patch proposal by Tk developers
2020-09-21 Fix adopted upstream

tinyexpr

Date information
2020-06-17 Private disclosure to the maintainer
2020-06-25 Followup request to the maintainer for a reply
2020-06-25 Maintainer replies and requests full disclosure
2020-06-25 Full disclosure via public Github issue