It doesn't look like bc uses fuzzing? It'd be interesting to see the outcome there since even in mature projects it consistently leads to novel memory safety bugs every few days [1]. Fuzzing find a lot of really weird and unintuitive bugs in my experience, especially as it relates to use-after-frees and races.
You will get 148 as of 53832b884b5c. Not all of those are bugs found by AFL(++) because some are tending to my fuzzing infrastructure, but at least 2/3 probably are.
Those links say 70% of all security bugs, but since my bc/dc does not have the ! command (to spawn processes) and only reads files, not writes them (except stdout), it’s hard to actually turn a memory safety issue into a security bug, even if it’s possible.
Is this quote assuming ASLR, non-executable stack, stack canaries?
I don't really understand what writing files and forking have to do with the security of system? Unless you mean it limits the attack surface from a ROP gadget?
It means that you have to find input that triggers a memory bug to do something malicious.
If my dc had the `!` command, then you, as an attacker with low privileges, might be able to modify a dc script to spawn another command that you know can be exploited to get root. Without it, you have to exploit my dc for ROP or some other attack.
Of course, then you would just target a shell, right? And that's the point: I've put in enough work, and my bc/dc are locked down enough, that attackers would probably find other ways in.
I was part of a team at a job about 20 years ago that ported an existing C codebase over to (then new) Java. Once we got everything working, a co-worker who was very familiar with the old C codebase remarked that with C it took a lot longer to get things working the first time, but once they were working, they stayed working whereas with Java you could get things working pretty quick, but you'd start to see problems when you actually put load on it.
How do you feel about Go if you've ever worked with it? It seems like it was intended to solve exactly those types of pain points associated with maintaining Java programs
I'm not the person you responded to, but my biggest complaint with Go is binary size. It makes it rather unusable for low level programs on resource constrained systems.
a plumbers livelihood depends on his tools but no one in their right mind would compare a hammer to a seatbelt like this.
The reason people like you are not listened to is that you're so unreasonable.
It's not an accident that ada was designed years ago for software that IS critical in this manner, because different decisions get made. But the vast majority of software is not going to end up with people dead, hence why arguments comparing life-or-death situations with your run-of-the-mill C code is assinine.
Yes, it's true that GCC code will never live under the same level of scrutiny as NASA code, nor should it.
Moreover, it is untenable to maintain a small island of "secure software" for "important things" in a vast ocean of careless and vulnerable code. Inevitably, the island gets infected, and not even air-gaps can save it, as stuxnet showed.
> Moreover, it is untenable to maintain a small island of "secure software" for "important things" in a vast ocean of careless and vulnerable code. Inevitably, the island gets infected, and not even air-gaps can save it, as stuxnet showed.
Why is it inevitable? As long as it doesn't connect to other software (via internet or other means), isn't it possible to formally verify one critical software component, e.g. in pacemakers?
I'm not saying that C would necessarily be the best choice for formally verifying it, though.
more than that, you only have so much time and money, concentrating on more important pieces allows you to be more thorough where the highest impacts are.
perfect is the enemy of good, "security" people act as if all breaches are equally relevant.
When your surface area is everything you're more likely to have holes, that's just a law of nature. Limit your surface area and suddenly you can be more thorough.
Formally verifying does no good if the compiler is infected. In the stuxnet example, formal verification wouldn't even help - how do you formally verify centrifuge timings?
Unlike what your sibling comment claims, I'm not saying all software is equally important, or must have equal effort invested in securing it. But insecurity absolutely is infectious, and the more insecure the general environment is, the harder it is to secure a small part of it.
For example, you'll want a compiler. How secure is the web stack of the page that delivers your gcc/clang? How secure is its host's infrastructure, and of the DNS provider? The browser you're downloading it with? Did you ever visit any other page that might have compromised it? What about your text editor, your OS, the SDK you're using to flash code onto the pacemaker.. And all of them have vast supply-chain networks.
Hopefully, for the pacemaker, the authors of the code would be using a verified compiler like CompCert (although it's only verified for the compilation, not the parsing or the preprocessor), but you don't have control at every level, like for the hardware. You can't verify centrifuge timings, but you can specify software and verify that it fits the specification to the point that it won't be the point of failure (assuming you have everything under control, like the pacemaker SDK, everything). I do see what you're saying about it being infectious, though.
I think you need to read to the end of the post. And then read the one it links to because that one says that I will rewrite all of my new project in a memory-safe language. (bc, unfortunately, needs to stay in C because it needs to have zero dependencies.)
I'm not making the argument that C is good, or that I am good at C. I'm comparing myself against the average.
> (bc, unfortunately, needs to stay in C because it needs to have zero dependencies.)
Couldn't you write it in Golang? That's also popular for creating standalone executables (ignoring the dynamically linked libc when necessary).
I'm not saying you're obligated to switch. I just assume you wrote bc in C because you find it fun, based on your "Why I write C when I care about memory safety" post.
That is true that there is still a dependency on a C compiler, but the Linux kernel has that dependency too, so that dependency is "free."
Edit: In fact, there's really a dependency on POSIX sh and various standard POSIX utilities, but Linux also requires those to build, so those are also "free."
Come on, are you really comparing a calculator to any web API server that is exposed 24/7/365 to malicious people trying to exploit it using various ways, which has many network endpoints with various HTTP methods, authentication, authorization, RBAC, using databases, connection encryption, randomness, hashing, maybe compression, graphics/video/audio conversion, caching and so on?
I'm in love with "bc", I don't know if I use your version or not, but well... it's a calculator... It's well written, it does the job, but come on...
I'm currently making a build system and a VCS with a server that will be exposed 24/7/365 with HTTP, authentication, authorization RBAC, a database, connection encryption, randomness, hashing, compression, caching, and streaming of large files.
bc is my only current data point since this project is not finished, but once it is, we'll start to get real data about what I can do.
This is an interesting article! I think more of this kind of bug-type/origin-breakdown is a good thing to have.
This and the Curl article make me wonder what factors impact the proportion of security bugs which are memory safety bugs. The most obvious variable is codebase size - Microsoft/Chromium both are huge codebases, with multiple millions (billions?) of lines of code each. Curl appears to clock in closer to 100k, and Daniel states "51% (22 of 43) of the issues rated high or critical was due to C mistakes." bc appears to have ~20k lines of code, and this article gives C bug rate closer to 10%. Feature set/attack surface area feels like another important variable, though I'm sure there are arguments for others as well.
I'd be nice if we had more directly comparable numbers as well. The denominator for Microsoft's 70% number is "number of CVEs". The denominator for Chromium's number is "high severity security bugs". Curl's 51% number uses a similar metric, and I think the denominator for bc's ~10% number is just "bugs" (though to be fair, OP does discuss this in the post).
All that being said, I still think the data point introduced by this article is better to have than not.
Do you have an interface in mind to reduce friction for building the catalog on a daily basis? GitHub and Gitea don't really seem to provide clean ways to do this out of the box.
I used C for a many years and generally liked it. I then spent the following 10 years using C++ and had mixed feelings about it. I now use Rust and I'm not sure I could ever in good faith write a new project in C or C++ again. Anyway, we're both members of the same church! :)
38 comments
[ 0.27 ms ] story [ 79.3 ms ] thread[1] Linux syzkaller bug tracker https://groups.google.com/g/syzkaller-bugs
My bc does use fuzzing. [1]
I love fuzzing. In my new project, fuzzing generates my test suite that I then go through by hand and verify.
In bc, if I change the source code before a release, I run a fuzzer for two weeks on both bc and dc.
[2] and [3] are directories of error tests, almost all of which were found by AFL(++).
If you run the following on my bc repo:
You will get 148 as of 53832b884b5c. Not all of those are bugs found by AFL(++) because some are tending to my fuzzing infrastructure, but at least 2/3 probably are.[1]: https://git.gavinhoward.com/gavin/bc/src/branch/master/tests...
[2]: https://git.gavinhoward.com/gavin/bc/src/branch/master/tests...
[3]: https://git.gavinhoward.com/gavin/bc/src/branch/master/tests...
I don't really understand what writing files and forking have to do with the security of system? Unless you mean it limits the attack surface from a ROP gadget?
It means that you have to find input that triggers a memory bug to do something malicious.
If my dc had the `!` command, then you, as an attacker with low privileges, might be able to modify a dc script to spawn another command that you know can be exploited to get root. Without it, you have to exploit my dc for ROP or some other attack.
Of course, then you would just target a shell, right? And that's the point: I've put in enough work, and my bc/dc are locked down enough, that attackers would probably find other ways in.
This is my experience, though I started in Java and transitioned to C.
My C code also does not need to be updated for language changes and such.
Additionally people have died due to software bugs, Therac-25 being quite famous, with its Assembly optimization tricks.
The reason people like you are not listened to is that you're so unreasonable.
It's not an accident that ada was designed years ago for software that IS critical in this manner, because different decisions get made. But the vast majority of software is not going to end up with people dead, hence why arguments comparing life-or-death situations with your run-of-the-mill C code is assinine.
Yes, it's true that GCC code will never live under the same level of scrutiny as NASA code, nor should it.
Moreover, it is untenable to maintain a small island of "secure software" for "important things" in a vast ocean of careless and vulnerable code. Inevitably, the island gets infected, and not even air-gaps can save it, as stuxnet showed.
This idea that all code must be treated equally wrt security is why security people are oddly never effective.
Why is it inevitable? As long as it doesn't connect to other software (via internet or other means), isn't it possible to formally verify one critical software component, e.g. in pacemakers?
I'm not saying that C would necessarily be the best choice for formally verifying it, though.
perfect is the enemy of good, "security" people act as if all breaches are equally relevant.
When your surface area is everything you're more likely to have holes, that's just a law of nature. Limit your surface area and suddenly you can be more thorough.
Unlike what your sibling comment claims, I'm not saying all software is equally important, or must have equal effort invested in securing it. But insecurity absolutely is infectious, and the more insecure the general environment is, the harder it is to secure a small part of it.
For example, you'll want a compiler. How secure is the web stack of the page that delivers your gcc/clang? How secure is its host's infrastructure, and of the DNS provider? The browser you're downloading it with? Did you ever visit any other page that might have compromised it? What about your text editor, your OS, the SDK you're using to flash code onto the pacemaker.. And all of them have vast supply-chain networks.
I think you need to read to the end of the post. And then read the one it links to because that one says that I will rewrite all of my new project in a memory-safe language. (bc, unfortunately, needs to stay in C because it needs to have zero dependencies.)
I'm not making the argument that C is good, or that I am good at C. I'm comparing myself against the average.
Couldn't you write it in Golang? That's also popular for creating standalone executables (ignoring the dynamically linked libc when necessary).
I'm not saying you're obligated to switch. I just assume you wrote bc in C because you find it fun, based on your "Why I write C when I care about memory safety" post.
And that was part of my original requirements because I knew that fact at the time I started.
Edit: In fact, there's really a dependency on POSIX sh and various standard POSIX utilities, but Linux also requires those to build, so those are also "free."
I'm in love with "bc", I don't know if I use your version or not, but well... it's a calculator... It's well written, it does the job, but come on...
I'm currently making a build system and a VCS with a server that will be exposed 24/7/365 with HTTP, authentication, authorization RBAC, a database, connection encryption, randomness, hashing, compression, caching, and streaming of large files.
bc is my only current data point since this project is not finished, but once it is, we'll start to get real data about what I can do.
This and the Curl article make me wonder what factors impact the proportion of security bugs which are memory safety bugs. The most obvious variable is codebase size - Microsoft/Chromium both are huge codebases, with multiple millions (billions?) of lines of code each. Curl appears to clock in closer to 100k, and Daniel states "51% (22 of 43) of the issues rated high or critical was due to C mistakes." bc appears to have ~20k lines of code, and this article gives C bug rate closer to 10%. Feature set/attack surface area feels like another important variable, though I'm sure there are arguments for others as well.
I'd be nice if we had more directly comparable numbers as well. The denominator for Microsoft's 70% number is "number of CVEs". The denominator for Chromium's number is "high severity security bugs". Curl's 51% number uses a similar metric, and I think the denominator for bc's ~10% number is just "bugs" (though to be fair, OP does discuss this in the post).
All that being said, I still think the data point introduced by this article is better to have than not.
Thank you. :)
One thing I am going to do in my new project is catalog all bugs fixed after first release with the following data points:
* Is it a C bug?
* Is it in a stable module of the monorepo? (I will mark things stable after they have been tested.)
* Is the bug in a release, even if it's in an unstable module?
* Is it a build bug?
* Is it a test bug?
* Etc.
I'll keep the catalog in a human- and machine-readable format. This should provide a good set of data.
I would be thrilled if people downloaded my code for human study, analysis, and code archeology.
Until I build my VCS, which will be like Fossil and have an integrated issue tracker that gets cloned with the repo.
Then I'll put the catalog into my VCS by hand and track issues normally; the catalog will build itself as people report bugs.
I'm currently inclined to think that:
1. Yes, it should
2. The OP of the linked issue may be mistaking a tools / social conventions issue for an error by the author
Just pathetically good at seeking out some ego stroking
I hate posts like this one.
They always start off with a banal post heading
Then becomes a way of arguing the posters hiden agenda