Segfaults and Twitter monkeys: a tale of pointlessness

For a few years in the 1990s, when PNG was just getting established as a Web image format, I was a developer on the libpng team.

One reason I got involved is that the compression patent on GIFs was a big deal at the time. I had been the maintainer of GIFLIB since 1989; it was on my watch that Marc Andreesen chose that code for use in the first graphics-capable browser in ’94. But I handed that library off to a hacker in Japan who I thought would be less exposed to the vagaries of U.S. IP law. (Years later, after the century had turned and the LZW patents expired, it came back to me.)

Then, sometime within a few years of 1996, I happened to read the PNG standard, and thought the design of the format was very elegant. So I started submitting patches to libpng and ended up writing the support for six of the minor chunk types, as well as implementing the high-level interface to the library that’s now in general use.

As part of my work on PNG, I volunteered to clean up some code that Greg Roelofs had been maintaining and package it for release. This was “gif2png” and it was more or less the project’s official GIF converter.

(Not to be confused, though, with the GIFLIB tools that convert to and from various other graphics formats, which I also maintain. Those had a different origin, and were like libgif itself rather better code.)

gif2pngs’s role then was more important than it later became. ImageMagick already existed, but not in anything like its current form; GIMP had barely launched, and the idea of a universal image converter hadn’t really taken hold yet. The utilities I ship with GIFLIB also had an importance then that they would later lose as ImageMagick’s “convert” became the tool everyone learned to reach for by reflex.

It has to be said that gif2png wasn’t very good code by today’s standards. It had started life in 1995 as a dorm-room project written in journeyman C, with a degree of carelessness about type discipline and bounds checking that was still normal in C code of the time. Neither Greg nor I gave it the thorough rewrite it perhaps should have gotten because, after all, it worked on every well-formed GIF we ever threw at it. And we had larger problems to tackle.

Still, having taken responsibility for it in ’99. I kept it maintained even as it was steadily decreasing in importance. ImageMagick convert(1) had taken over; I got zero bug reports or RFEs for six years between 2003 and 2009.

I did some minor updating in 2010, but more out of completism than anything else; I was convinced that the user constituency for the tool was gone. And that was fine with me – convert(1) had more eyes on it and was almost certainly better code. So gif2png fell to near the bottom of my priority list and stayed there.

A few years after that, fuzzer attacks on programs started to become a serious thing. I got one against GIFLIB, which was issued a CVE and I took very seriously – rogue code execution in a ubiquitous service library is baaaad. A couple of others in GIFLIB’s associated utility programs, which I took much less seriously as I wasn’t convinced anyone still used them at all. You’re going to exploit these…how?

And, recently, two segfaults in gif2png. Which was absolutely at the bottom of my list of security concerns. Standalone program, designed to be used in input files you trust to be reasonably close to well-formed GIFs (there was a ‘recover’ option that could salvage certain malformed ones if you were very lucky). Next to no userbase since around 2003. Again, you’re going to exploit this…how?

Now, I’m no infosec specialist, but there is real-world evidence that I know how to get my priorities right. I’ve led the the NTPsec project for nearly five years now, reworking its code so thoroughly that its size has shrunk by a factor of 4. NTP implementations are a prime attack target because the pre-NTPsec reference version used to be so easy to subvert. And you know what the count of CVEs against our code (as opposed to what we inherited) is?

Zero. Zip. Zilch. Nobody has busted my code or my team’s. Despite half the world’s academics and security auditors running attacks on it. Furthermore, we have a record of generally having plugged about four out of five CVEs in the legacy code by the time they’re issued.

That’s how the security of my code looks when I think it’s worth the effort. For libgif I’ll spend that effort willingly. For the GIFLIB tools around it, less willingly. But for gif2png, that seemed pointless. I was tired of spending effort to deal with the 47,000th CS student thinking “I know! I’ll run a fuzzer on <random -program-x>!” and thinking a crash was a big deal when the program was a superannuated standalone GIF filter that hasn’t seen any serious use since J. Random Student was in diapers.

So two days ago I marked two crashes on malformed input in gif2png won’t-fix, put in in a segfault handler so it would die gracefully no matter what shit you shoved at it, and shipped it…

…only to hear a few ours later, from my friend Perry Metzger, that there was a shitstorm going down on Twitter about how shockingly incompetent this was.

Really? They really thought this program was an attack target, and that you could accomplish anything by running rogue code from inside it?

Narrator voice: No, they didn’t. There are some people for whom any excuse to howl and fling feces will do.

A similar bug in libgif or NTPsec would have been a serious matter. But I’m pretty good at not allowing serious bugs to happen in those. In a quarter century of writing critical service code my CVE count is, I think, two (one long ago in fetchmail) with zero exploits in the wild.

This? This ain’t nothin’. Perry did propose a wildly unlikely scenario in which the gif2png binary somehow got wedged in the middle of somebody’s web framework on a server and allowed to see ill-formed input, allowing a remote exploit, but I don’t believe it.

Alas, if I’ve learned anything about living on the modern Internet it’s that arguing that sort of point with the howler monkeys on Twitter is a waste of time. (Actually, arguing anything with the howler monkeys on Twitter is a waste of time.) Besides, the code may not be an actual security hazard, but it has been kind of embarrassing to drag around ever since I picked it up.

So, rather than patch the C and deal with yet another round of meaningless fuzzer bugs in the future, I’ve rewritten it in Go. Here it is, and now that it’s in a type-safe language with access bounds checking I don’t ever have to worry about that class of problem again.

One good thing may come of this episode (other than lifting code out of C, which is always a plus). I notice that the GIF and PNG libraries in Go are, while serviceable for basic tasks, rather limited. You can convert with them, but you can’t do lossless editing with them. Neither one deserializes the entire ontology of its file format.

As the maintainer of GIFLIB and a past libpng core developer, I don’t know where I’d find a better-qualified person to fix this than me. So now on my to-do list, though not at high priority: push some patches upstream to improve these libraries.

49 comments

  1. So two days ago I marked two crashes on malformed input in gif2png won’t-fix, put in in a segfault handler so it would die gracefully no matter what shit you shoved at it, and shipped it…

    …only to hear a few ours later, from my friend Perry Metzger, that there was a shitstorm going down on Twitter about how shockingly incompetent this was.

    —snip—

    So, rather than patch the C and deal with yet another round of meaningless fuzzer bugs in the future, I’ve rewritten it in Go. Here it is, and now that it’s in a type-safe language with access bounds checking I don’t ever have to worry about that class of problem again.

    Why not just deprecate the project? Say on the project page “Gif2png no longer has a user base and will be minimally, if at all maintained. I do not recommend that it be used where there are not legacy requirements for it. If you have a critical need for it, maybe you’d like to take up maintainership.” If someone files a bug against the gif2png that you don’t think is worth your time, you mark it won’t-fix, with the above comment. Seems easier than rewriting the whole thing.

    1. >Why not just deprecate the project?

      I did not wish to allow the appearance that I had abandoned my responsibility or retreated in confusion. It was worth a day of work to prevent that.

      Believing the userbase to have vanished did relieve my concern about the fact that the Go version loses some capabilities that the C version had, like the progress-meter option and writing interlaced files.

      1. It seems there was a lot of confusion anyway. I’ve had to gently (and not so gently) prevent segfault handlers in code proposed by junior coworkers. It’s a tempting non-solution for potentially extremely serious problems. If I had seen such a patch from you first-hand, my first thought would probably be more like “oh crap, trolls got into esr’s account, people need sweaters in hell today.”

        Your intent would have been clearer if you just deleted the code, and/or replaced it with a program that printed only “this program is too dangerous for use as anything but a museum exhibit. If you disagree, you can crawl the git history to revert the delete commit and/or volunteer to fix it yourself. All available data says this code is not a productive use of anyone’s time in 2019. I’m out, and if you trust my skill and experience as a maintainer, you should be out too.”

        Lots of people deprecate time-sink code they’re rationally unwilling to maintain. More people should get into the habit of doing that proactively, especially on code where there is known dangerously unpredictable behavior (i.e. everything in C by default). Then follow the “but wait I was using that” bug reports to see what humans should be spending their time on (including people who are running fuzzers on all currently active code…).

        Maybe there’s a form-letter version of the above that LBIPs can use?

        1. >this program is too dangerous for use as anything but a museum exhibit.

          Huh? How it that even true? The C version is completely safe in its intended use case – converting a GIF that you know is good because it’s been in production use on your website.

          1. > a GIF that you know is good because it’s been in production use on your website.

            That doesn’t follow. Production website GIFs graphic assets come from lots of different places, and almost nobody audits them for malware, or anything else (except copyright). It could be used in (extremely hypothetical) disgruntled graphic designer attacks.

            1. >It could be used in (extremely hypothetical) disgruntled graphic designer attacks.

              The disgruntled graphic designer attacks!

              It lashes you with its ponytail! You take 3 points of damage.

              Yeah, that’s an extreme hypothetical all right. Disgruntled would have to know at the time he composes the GIF that you plan to convert it to a PNG using gif2png in the future. I think a severe ponytail lashing is more likely.

              1. It could be used in (extremely hypothetical) disgruntled graphic designer attacks.

                As both a graphic designer and a professional software developer, I’m gonna say no. Ain’t worth nobody’s time to even try.

                (And like esr implies … who makes GIFs for websites in 2019? People in the past can’t time-travel this bug and implement [even if it’s theoretically exploitable, which is unclear].

                And people now aren’t making GIFs for clients for their websites. They’re making PNGs natively.)

    2. The alternative that occurred to me was to write a wrapper around convert that exposes an interface identical to the old gif2png. That way, if you are mistaken in your belief that nobody uses the program, the disruption they experience is limited to their package manager fetching ImageMagick when they update and dependency resolution kicks in. If in future somebody files a bug again, you know that the responsible upstream code has a real userbase worth worrying about, regardless of the correctness of your estimate that nobody uses gif2png specifically.

  2. “Alas, if I’ve learned anything about living on the modern Internet it’s that arguing that sort of point with the howler monkeys on Twitter is a waste of time. ”

    I agree, do not argue on social media, just do. It is the “show, don’t tell” of developers.

  3. @esr: “So, rather than patch the C … I’ve rewritten it in Go.”

    Do you think this will become any kind of trend in your work? C-to-Go conversion is obviously an area where you have considerable expertise now.

    1. >Do you think this will become any kind of trend in your work?

      Yes, I do. I’m a little surprised it took me this long to hit a case where moving one of my C projects to Go was was the thing to be done immediately.

      1. Glad to hear that answer. I might dare hope it would become a sort of industry-wide trend.

        1. Most of the industry has agreed upon Rust as a C replacement. Google and Microsoft are reaching for Rust when there’s new system-level work to be done, and there are great Rust replacements for find and grep being used in the wild.

          Go is much more a Python replacement — different niche.

          1. >Most of the industry has agreed upon Rust as a C replacement.

            If that’s so, It’s not showing in web-search-based usage estimates. TIOBE has Go at 14 and rising, Rust is at 38 = below GOBOL. Since I last checked, Go has jumped 5 places up and Rust dropped two places down.

                1. Sounds like a term for the needlessly verbose code that results when you attempt to use Go, a language with a 1970s type system lacking both generics and operator overloading, to write business apps.

                  1. Instead of one of your favored bondage-and-discipline languages? Surely you’re not advocating Rust for business application development…

                  2. I love me some generics, but I hear “operator overloading” and my immediate response is oh, HELL no.

                    Bugpump gonna pump bugs, and I don’t want to even THINK about the “business apps” that “need” overloaded operators.

                  1. >Actually, it turns out to be a language oriented to manipulating data with COBOL-style syntax that transpiles to Go.

                    This is not a parody. This is apparently a real thing. I assure you it was unknown to me when I committed my typo.

                    O tempora. O mores!

                    1. Which reminds me of the shocking fact that deep fried eel is the latest craze in fast food.

                      O tempura! O morays!

                    2. Could be worse. He could have committed the COBOL shell.

                      And yes, I am fully aware of the JCL shell.

          2. I will note that none of the job openings I’ve looked at have called for Rust, while Go is very much there, though not as popular as Python, C++, or Ruby.

            I picked up enough Go to be productive in a few hours. Can you say the same for Rust?

            1. Onomastics is real. Who wants to use a language named after a process of degradation?

              Similarly, I’m glad Nim changed away from Nimrod.

              1. Hey, the original connotation of “Nimrod” was “a mighty hunter before the Lord”. Then a certain wabbit that was unimpressed with Elmer Fudd’s wabbit hunting skills called him “Nimrod” in sarcasm, and it was all over.

  4. At a glance, my sympathies lie mostly with the Twitter mob. This comment from Reddit (with gratuitous insults against you from the end omitted) nails it, I think:

    You’ll note that the readme at the time and still, doesn’t say anywhere that the library is “designed to be used in input files you trust to be reasonably close to well-formed GIFs” on pain of arbitrary code execution. It even claims that it’s “very mature and well-tested”.

    You’re arguing that there’s no need to fix this because it works fine for its “intended use case” of converting already-trusted files, but it’s not obvious to me that the docs ever indicated that it was specifically for that use case or that it was dangerous to use it on untrusted input, nor is it obvious to me that nobody in the wild was using it on untrusted user input on a webserver somewhere.

    Good job rewriting in Go, though.

    1. >but it’s not obvious to me that the docs ever indicated that it was specifically for that use case

      Gee, you think that might have something to do with the fact that it predates mass adoption of the Web and the modern security panic? Naaah, couldn’t be.

      1. Gee, you think that the first thing people do when they want to convert a gif to a png is to check whether the project they’re using predates mass adoption of the Web and the modern security panic?

        1. >Gee, you think that the first thing people do when they want to convert a gif to a png is to check whether the project they’re using predates mass adoption of the Web and the modern security panic?

          No, the first thing they do is run convert(1). Also the last thing.

          1. I used to use convert weekly to submit my timesheet. The…um…people I sent it to didn’t like PNG, then wanted PDF.

          2. *slow clap*

            Ain’t nobody running giflib for anything, let alone automating it to take rando attack-gifs that might … cause it to segv and handwave-handwave … sorry, I can’t even take this hypothetical seriously.

            (I mean, for context, I write software that, among other things, handles credit card payments; I’ve run though a PCI-DSS audit.

            This is the sort of attack surface that I’m not sure even PCI would take seriously, and they have no sense of humor.)

            1. >Ain’t nobody running giflib for anything

              Don’t confuse gif2png with libgif. The names are similar but the security exposure is night-and-day different. Where Gif2png is a superannuated conversion tool, libgif is a service library linked into basically everything written in C that lights up a pixel-addressible display. Breaches in it get CVEs because they’re serious shit (there’s been only one so far, because I write good code).

        2. Oi! I am the Cabbage who posted the first comment in this thread (beginning with “At a glance”), and, for the record, I am not the author of this comment (beginning “Gee”). Please don’t adopt other users’ names in a comment thread; it’s needlessly confusing.

          1. >Please don’t adopt other users’ names in a comment thread; it’s needlessly confusing.

            Warning to the pseudo-Cabbage: masquerading is a banning offense here. You will receive no second warning.

  5. ESR,

    If this was one workday, you are either 1) extremely productive 2) having a workday longer than 8 hours 3) relying partially on automatic conversion 4) my guess: all three.

    .

    1. >If this was one workday, you are either 1) extremely productive 2) having a workday longer than 8 hours 3) relying partially on automatic conversion 4) my guess: all three.

      I didn’t use automatic conversion in this case, so 1 and 2.

      If you think this was impressive, try to track my output sometime when I’m out of surgical recovery and no longer constantly hungry, tired, and in intermittent pain.

      1. I wrote:

        >I didn’t use automatic conversion in this case, so 1 and 2.

        Also, Go is a very supportive language if you need to code fast. Not quite as good as Python that way but light-years better than C.

      2. > constantly hungry, tired, and in intermittent pain.

        I think there were like three days back in the early 80s when I wasn’t hungry, tired and in mild pain.

    2. It’s amazing how much work you can get done when you don’t have Scrum ceremonies, interrupting bosses/coworkers, noisy offices, etc. to distract you from the task at hand.

  6. ESR: Thoughts on this?:
    Opensource ChaosEsque Anthology project ends due to interference from FortNight developer.
    (Chad Wagie FortNite Developer causes NEET Opensource “Shitpile” to Shutdown)

    ChaosEsque Anthology, an opensource QuakeC project, has ended development after over seven years of continuous development. The project boasted hundreds of weapons, a spell system, and many maps, amongst other features.

    The culprit is FooFlinger: a self-proclaimed successful FortNight developer who indicated that he felt the opensource project was a “pile of shit”, “a collection of assets” created by a “NEET pedophile” who likes girls. FooFlinger noted in his 1 star review that:
    >Author is a pedophile and takes pride in it. Also advertises this clump of assets on every anonymous imageboard multiple times a week.

    Another reviewer from the same time period noted:
    >The graphics are terrible and author is a sack of ****.

    The developers will no longer be contributing to opensource and have ended the game.

    http://www.indiedb.com/games/chaosesqueanthology

    >ChaosEsqueTeam 21hours ago
    >
    >FooFlinger: we have ended the project due to
    >your criticisms. We will no longer contribute
    >to opensource what-so-ever.

    The opensource NEET developer also reportedly supported Joe Biden for president in 2020 because “he likes girls too, unlike heretic white men who are ruled over, mind and soul, by ‘Muh White Wuman'”

    1. a) I suspect the claim that they have ended the project may be sarcasm. They’re dealing with an irritating troll (fooflinger)…why would they rage quit over a jackass like that?
      b) The game really is a pile of shit. Look at it. In this day of super-realistic 1st person shooters, it’s embarrassingly bad.
      c) The whole situation is a grade A shitshow and ESR is totally right to steer clear. I only took a peek out of morbid curiosity ;)

  7. I think fixing that segfault properly would have taken less time than writing all this post, and for sure less than rewriting it in Go

Leave a Reply to esr Cancel reply

Your email address will not be published. Required fields are marked *