NVIDIA Security Team: 'What if We Just Stopped Using C?' (adacore.com) 239
This week the Adacore blog shared a story about the NVIDIA Security Team:
Like many other security-oriented teams in our industry today, they were looking for a measurable answer to the increasingly hostile cybersecurity environment and started questioning their software development and verification strategies. "Testing security is pretty much impossible. It's hard to know if you're ever done," said Daniel Rohrer, VP of Software Security at NVIDIA.
In my opinion, this is the most important point of the case study — that test-oriented software verification simply doesn't work for security. Once you come out of the costly process of thoroughly testing your software, you can have a metric on the quality of the features that you provide to the users, but there's not much you can say about security.
Rohrer continues, "We wanted to emphasize provability over testing as a preferred verification method." Fortunately, it is possible to prove mathematically that your code behaves in precise accordance with its specification. This process is known as formal verification, and it is the fundamental paradigm shift that made NVIDIA investigate SPARK, the industry-ready solution for software formal verification.
Back in 2018, a Proof-of-Concept (POC) exercise was conducted. Two low-level security-sensitive applications were converted from C to SPARK in only three months. After an evaluation of the return on investment, the team concluded that even with the new technology ramp-up (training, experimentation, discovery of new tools, etc.), gains in application security and verification efficiency offered an attractive trade-off. They realized major improvements in the security robustness of both applications (See NVIDIA's Offensive Security Research D3FC0N talk for more information on the results of the evaluation).
As the results of the POC validated the initial strategy, the use of SPARK spread rapidly within NVIDIA. There are now over fifty developers trained and numerous components implemented in SPARK, and many NVIDIA products are now shipping with SPARK components.
In my opinion, this is the most important point of the case study — that test-oriented software verification simply doesn't work for security. Once you come out of the costly process of thoroughly testing your software, you can have a metric on the quality of the features that you provide to the users, but there's not much you can say about security.
Rohrer continues, "We wanted to emphasize provability over testing as a preferred verification method." Fortunately, it is possible to prove mathematically that your code behaves in precise accordance with its specification. This process is known as formal verification, and it is the fundamental paradigm shift that made NVIDIA investigate SPARK, the industry-ready solution for software formal verification.
Back in 2018, a Proof-of-Concept (POC) exercise was conducted. Two low-level security-sensitive applications were converted from C to SPARK in only three months. After an evaluation of the return on investment, the team concluded that even with the new technology ramp-up (training, experimentation, discovery of new tools, etc.), gains in application security and verification efficiency offered an attractive trade-off. They realized major improvements in the security robustness of both applications (See NVIDIA's Offensive Security Research D3FC0N talk for more information on the results of the evaluation).
As the results of the POC validated the initial strategy, the use of SPARK spread rapidly within NVIDIA. There are now over fifty developers trained and numerous components implemented in SPARK, and many NVIDIA products are now shipping with SPARK components.
What if, indeed. (Score:3, Insightful)
Where expertise is devalued, doom follows. Mark my words.
Re: (Score:2)
"The determined programmer can write buggy code in any language".
They should just switch to Haskell. Someone, and that somone would be an academic, once tried to tell me that it's impossible to write incorrect code in Haskell.
Re:What if, indeed. (Score:4, Funny)
It is also impossible to write useful code in Haskell ;)
well, practically impossible.
Re: What if, indeed. (Score:2)
Re: (Score:3, Insightful)
Re: What if, indeed. (Score:2)
Re: What if, indeed. (Score:2)
Re: (Score:3)
We have better alternatives, and we're not trying to write applications for computers with 128k of RAM any more.
Perhaps most developers aren't, but even now it's not particularly rare for a lot of us to write for embedded platforms that may only have 128 *bytes* of RAM available.
Re: What if, indeed. (Score:4, Interesting)
As someone who programmed a lot of C++ and Haskell, the languages are similar in a strange way. The only difference is in what's easy and what's hard. In Haskell, all the standard library is full with super safe and friendly containers. In C++, it is full with pointers and APIs with bound checking.
Now comes the interesting part. Theoretically, C++ allows you to write completely safe containers if you always bounds checking apis and rely on ugly templates. Haskell also allows you to directly access memory, do mallocs, and violate access.
The only difference is in the defaults of both languages and what functionality they choose to hide behind complicated APIs.
I think both languages have their places. In industry projects I'm maintaining now, some would better remain in C++ while others should have been rewritten in Haskell.
Re: (Score:2)
Expertise is not being devalued.
And no, you are not smart enough to write secure code in C.
Re: What if, indeed. (Score:2)
And you cannot solve racism with more and different racism. You solve it by letting humans make free will choices and discovering that equality is far and away the optimal solution.
Re: What if, indeed. (Score:2)
Re: measuring stick (Score:2)
Go read Harrison Bergeron.
The possibility thatball races are precisely the same on average as other races is just one of thousands. A quick look at competitive sports teams doesn't support it. Sure there will be many overlapping individuals, but racial equity is at odds with equality. 'Equity' is just codified plundering of others based on race. 'Our team/race' has got to get it's slice as a group even if then individuals don't merit it.
There is nothing wrong with that point of view, but faced with a te
proof (Score:3, Interesting)
Fortunately, it is possible to prove mathematically that your code behaves in precise accordance with its specification.
I'll give you a program, and a specification that says "this program halts"
Re:proof (Score:5, Informative)
I'll give you a program, and a specification that says "this program halts"
The halting problem [wikipedia.org] says that you can't prove that any program halts or not.
But you can prove the behavior of programs that are specifically written to be proven, including whether or not they halt.
In practice, those programs tend to be trivial, and proofs of correctness are not very useful.
Re: (Score:3)
Re: (Score:2)
about 30 years ago ... there were already ... at least one formally verified operating system.
So in 1992, there was a proven correct OS with zero bugs that never ever crashed? Citation needed.
Re: proof (Score:3)
My random guess is they're thinking of QNX which was famous at the time for running nuclear plants and other high reliability situations for years without reboots and being able to upgrade modules in place. The kernel had very few calls which would make it easier to vet.
Re: proof (Score:4, Informative)
My random guess is they're thinking of QNX
QNX is a microkernel, so most functionality is implemented outside the kernel. It is easy to do things reliably when you don't do much of anything. But the QNX Wikipedia page [wikipedia.org] says nothing about formal verification, and a Google search brings up nothing.
The L4 microkernel [wikipedia.org], written in Haskell, was supposedly formally verified in the late 1990s.
Re: (Score:2)
Re: proof (Score:4, Interesting)
Re: proof (Score:2)
Re: (Score:2)
Re: (Score:2)
"The halting problem [wikipedia.org] says that you can't prove that any program halts or not."
No. The program "HALT" provably halts. The program "while (true) {}" does not. What you cannot prove is that an arbitrary one "halts or not". "Any" particular program may be provable or may not me.
"But you can prove the behavior of programs that are specifically written to be proven, including whether or not they halt."
This is in open contradiction to your previous claim. "Any" program includes programs "speci
Re: (Score:2)
In practice, those programs tend to be trivial, and proofs of correctness are not very useful.
For the vast majority of programs, it's obvious whether they halt or not. Generally programs are set up in a giant loop of some sort, and when you encounter that, you can show that it doesn't halt (or in which cases it halts). This is useful, because in practice you want to know in which cases your program halts.
Most practical code is not self-referential, it's not even recursive. So the approach is to look for any strange for loops that might be infinite loops. Once you've analyzed them all, you can tell w
Re: (Score:2)
you can prove the behavior of programs that are specifically written to be proven, including whether or not they halt. In practice, those programs tend to be trivial, and proofs of correctness are not very useful.
In practice, I disagree. Whenever I'm writing recursion or a while loop, I always aim for a single-line comment explaining why it terminates, and I ask for similar comments when I'm reviewing code (unless it's trivial, e.g. an integer increment with clear upper bound). I've found quite a few bugs this way in practical systems. And if there's no recursion or while loop, well, it halts!
Whenever there are two pieces of storage storing related information, I ask for comments explaining the invariants that relat
Re: (Score:2)
This is a misunderstanding of the halting problem. It doesn't say that you can never determine if a program will halt or not, only that you can't determine of all programs halt or not.
Just because we can't solve the problem all of the time, doesn't mean that we can't solve a problem some of the time, or even most of the time.
You should be able to easily write a program that you can prove will halt. You can even write programs that will examine other programs and determine if they will halt or not. What
Re: (Score:2)
only that you can't determine of all programs halt or not.
Nope: only that you can't write an algorithm that proves for every program if it halts or not.
Re: (Score:2)
In your hypothetical, if there is a system that can determine if your specific program will halt or not, it will
Re: (Score:2)
You should be able to easily write a program that halts but you cannot have turing-complete language that will allow you to write programs that always halt. Hence, bugs and security problems will still possible in programs written in either C or SPARK or whatever system NVIDIA security team decided to use.
That is not necessarilly true.
I have never used SPARK in particular. But when using code provers, you never just throw you whole code and ask the prover to show it has a property. The properties are expressed from the ground up through the simpler functions to the more complex functions.
When you realize the prover can't write the proof, you introduce intermediate properties on smaller parts of the code to help it do what you need.
Re: (Score:2)
It was sloppy and incorrect paraphrasing of the halting problem, most certainly leading to confusion for those that it intended to inform, assuming that was the intention. It wasn't the only slop in the post either.
Re: (Score:3)
Please, stop treating us as ignorants... (Score:3)
They *RECODED* (and that's the key) a C program into SPARK and they want us to believe that the "improvements in the security" (whatever that means because there are no code to check nor testsuites nor nothing) was not because of "recoding" but because of "the language"...
Re: (Score:3)
It is difficult to prove the correctness of C programs because of pointer aliasing [wikipedia.org], out of bounds array accesses, and stack munging [wikipedia.org]. Many other languages don't allow these operations.
Re: (Score:3)
out of bounds array accesses.
That why all the smart C programmers moved to std::vector and std::string - they can check that for you.
Re: (Score:2)
The problem here is the can. It should be must.
Re: (Score:2)
The problem here is the can. It should be must.
I believe all the major C++ compilers enable STL range-checking by default these days.
You can use command line switches to turn it on/off as needed.
The real problem is convincing C programmers to educate themselves.
Re: (Score:2)
I believe all the major C++ compilers enable STL range-checking by default these days.
They don't. :(
Re:Please, stop treating us as ignorants... (Score:5, Funny)
Smart C programmers moved to libraries of another language?
Re: (Score:3)
you should be equally worried about accessing the wrong array index that just happens to be within bounds.
Let's say you have a million lines of code and one function of 20 lines that modifies and accesses a local array.
If it is a Rust program, you need to look at 20 lines of code to "prove" the array is consistent (what you write is what you read back).
In a C program, you need to look at a million lines. Any code can modify any memory location.
Re: (Score:3)
If it is a Rust program, you need to look at 20 lines of code to "prove" the array is consistent (what you write is what you read back).
In a C program, you need to look at a million lines. Any code can modify any memory location.
What about a C++ program?
Anybody trying to write large, "secure" code in C is probably doing it wrong.
Re: (Score:3)
What about a C++ program?
C++ has the same problems as C.
You can use objects to encapsulate information, but you can also violate that encapsulation by pointing any pointer to any location in memory. So formal verification is difficult.
Re: (Score:2)
C++ will drastically reduce the number of raw pointers in a program (all the way to zero if that's your goal...)
It also allows iterators, you don't have to constantly pass around the size of things, you also won't be rewriting linked list for the nth time just because you added a new struct.
It's hard to overstate the gains in safety that are possible in C++ compared to C.
Re:Please, stop treating us as ignorants... (Score:5, Insightful)
This is a religious argument, not an objective one.
At any time, a C++ programmer can use straight C so your "gains in safety" assume discipline. That discipline can be applied to the C programmer without using C++ at all. It may be more tedious, but you are claiming "possible/not possible". No.
C programmers are not compelled to use unsafe features just because other languages protect against them.
I can't remember the last time I introduced a memory leak in a program. Decades. Mostly that's because of the nature of the software I develop, but I NEVER use runtime malloc. I've fixed plenty in other people's code though. While C allows the possibility of memory leaks, it does not compel their existence and it is EASY to "overstate the gains" in this area as it applies to my particular coding style.
Furthermore, your argument boils down to code hiding. Various unsafe techniques might still be there, but your language supports constructs that destroy visibility into them. This is ultimately the core problem with modern software quality, it's a mile high stack of shit. Right at the center of it, C++.
As an aside, a long time ago, I worked on a project where performance was paramount. The vendor for our processors sold the company on a promise of 40% performance gains using special software and tools. We denied that it was possible, but I was assigned to pursue the tools with the vendor. After a thorough implementation with the vendor, the speedup was exactly 0%. Why, because the vendor assumed we were incompetent; it turns out everything they were optimizing we had already optimized. Your entire argument assumes the same.
Re: (Score:2)
C++'s safety would be vastly improved if it wasn't saddled with C and older C++ compatibility, but of course, that's also one of it's biggest strengths as a language. The language is largely unsafe by default, with safety features opt-in, and there's no way outside of external tool use (and barely even then), to ensure you're not straying outside the lines. It mostly comes down to sticking to safe conventions and more modern code practices. Yes, you can achieve something fairly close to memory safety the
Re: (Score:2)
If you cannot modify raw memory with Rust, it would mean there are plenty of things you cannot program with that language then.
Re: (Score:2)
Nope.
The typical C program passes pointers around everywhere. If it didn't, then everything would have to be passed by value on the stack and new copies of all data made at every function call.
If you have a function with a dereference of a pointer that has been passed to it, you have to analyze the complete program to find every source of that pointer, and make sure that in each and every case it can never refer to invalid memory at any point during the pointer's lifetime. You don't get to just look at the
Re: (Score:2)
Re: (Score:2)
It doesn't mean the existing code was safe, or that it would stay safe after being modified. Nor does it even mean you could apply what you learned from the
Re: (Score:3)
Yep. Sound to me like they just invented a complex way to find bugs in C programs.
Re: (Score:2)
Or... instead of writing in C then fucking around forever playing whac-a-mole on security holes, you could write in a language which is designed to not have a bunch of those problems and gives you a lot of tools for proving correctness relative to a spec.
Like, gee, imagine if we could use those magical blinkenlight boxes to automate away tedious tasks like auditing the most error prone sections of code for well known bugs.
Re: Please, stop treating us as ignorants... (Score:2)
Re: (Score:2)
That's crazy talk.
How else am I supposed to prove my awesomeness if I can't claim on the internet to write bug free C code? Really half of the posts on this story read like incredibly dull and exceptionally nerdy letters to penthouse.
Re: (Score:3)
Re: (Score:3)
SPARK is based subset [adacore.com] on Ada.
Considering this comes from NVIDIA (Score:5, Interesting)
A company that managed to include a node.js web service with their drivers that exposes privileged system calls to the network, I doubt they would be able to actually use languages with automated proofs.
Re: (Score:2)
Re:Considering this comes from NVIDIA (Score:4, Interesting)
I just had a job interview and I made the coding challenge go sideways - by simply doing a bog-simple check I always do.
I was giving a C string function to write. So the very first thing I write is to check of NULL pointers. I've gotten so used to coding over the years that bad arguments are to be expected, and if you're passed a pointer, you can expect it to be NULL at some point.
Of course, the specification said nothing about getting NULL as input and it threw my interviewers for a loop - I looked at the written specification they gave me, it said nothing, and I looked at the interviewers because I apparently wandered into an edge case no one considered.
The proper way is to handle it somehow - if you can, trigger the debugger. If not, trigger an assertion that halts the program or throw a fatal exception, because it's something that should never happen in normal operation and if you get it, you must assume the system is in an abnormal state. At the very least, return an error.
Of course, triggering a forced breakpoint is probably a nice way to do it - if you're running with a debugger it will trigger the debugger, if you're not, you'll typically get an illegal instruction error (breakpoints are typically handled by a breakpoint instruction, which is generally an illegal instruction with a specific pattern so a debugger can tell it's a breakpoint and not something else when it handles the illegal instruction error. Illegal instruction errors are also precise errors that always point to the faulting instruction so you know exactly where it faults).
Trust me, the look on the interviewer's faces when I presented them with "what is the proper way to handle this error" was priceless. I guess I sort of pre-empted their questions on "well, what happens if we give you NULL?"
LOL! ... Really? (Score:2)
They did that? ... I believe you, it's totally thinkable because of the l00ny Node craze and the epic prevalence of dimwitt deciders, but this is a new level of Monty Python in software projects. Pretty hilarious if you ask me. ROTFL!
Oh lawd, not the formal methods bullshit again (Score:5, Interesting)
Why? Because at that point the spec is code, and code can be bugged. Also it tells you nothing about implementation - it would tell your your outputs were perfect for all your inputs according to what the specification asked for, but wouldn't tell you you'd forgotten to free a pointer.
My lecturer (we're talking early 90s) was adamant that it wasn't just yet another computer language and was different in concept. It was Z I was taught...and lo and behold, a few years after university, a compiler for it appeared...
Re: (Score:2)
Re: (Score:2)
Back then basically all coding assignments where answered on paper with pencil.
Re: (Score:3)
Indeed. Back then, the CS prof teaching us formal verification said he just saw it as a form of an alternate implementation that gets compared to the code. It is not nearly as absolute as most people think and does absolutely nothing (except giving a false sense of security) when the ones writing the spec just make the same mistakes. That is quite common, because a lot of problems result from people missing more complex cases or unexpected behaviors and often they miss them in the code and the spec both, ev
Re: (Score:2)
Indeed. And you probably are not even talking about a formal spec (which is a lot more precise and a lot harder to do), but a regular spec which is unsuitable for formal verification anyways.
Re: (Score:2)
...and the "specs" I get from customers are typically garbage.
I usually get specs like, "We need you to add a report to the program that shows various summaries of certain transaction types. Here's the total we got for yesterday. You'll have to figure out what the transaction types are that end up with that number. We'll need to start using it tomorrow morning."
If I'm really lucky, I'll get a couple weeks notice to fit that in with the twenty five high priority, poorly (if at all) defined issues that needed to be done yesterday.
Go ahead, SPARK, formally verify that.
Re: Oh lawd, not the formal methods bullshit again (Score:2)
It becomes quite a lot harder to prove the drawing the route part when its done using nvidia drivers with abritrary performance hacks of the week to win the fps battle for the latest aaa benchmark title...
Still, you'd think that by now libpng and such that nobody rewrites in latest fashion magic bullet language were proven but apparently not.
bullshit. (Score:2)
Re: (Score:2)
Yeah. The limits of that approach are well known.
Re: (Score:2)
This is your failure in reasoning, not theirs.
They are not claiming that using a language that eliminates many classes of bugs solves all problems. It's only you and your fellow C supremacists who arebasically claiming that the only real alternative to C is complete perfection, so therefore it doesn't exist.
Eliminating certain very common bug classes means you no longer need to spend time auditing for them and fixing them.
You can write secure machine code given enough time and resources. But it's, frankly,
Re: (Score:2)
I recommend reading "Michael Abrash's Black Book of Graphics Programming". My perspective is that the hardware will do whatever it damn well pleases, regardless of your software. Abstracting away software problems doesn't make the problems go away, it merely hides the problems. Thus C, aka portable assembly, which makes it easier to figure out the difference between what you wrote and what the hardware actually did. Yes, it would be nice to use fancier languages, if only the hardware would play along.
Perfect specification (Score:2)
How is it different CodeSonar static code analysis tool?
from https://en.wikipedia.org/wiki/... [wikipedia.org]
SPARK is a formally defined computer programming language based on the Ada programming language,
https://en.wikipedia.org/wiki/... [wikipedia.org]
Verification conditions
- array index out of range
- type range violation
- division by zero
- numerical overflow
https://en.wikipedia.org/wiki/... [wikipedia.org]
This seems to be new, but then the specification needs to be correct:
Static Verification ...proving that the software implementation meets a formal specification of the program's required behaviour
https://www.adacore.com/about-... [adacore.com]
DEF CON 30 video links:
https://blog.adacore.com/when-... [adacore.com]
Re: (Score:2)
Re: (Score:2)
That's kind of ironic because Ada is famous for a certain disaster [bugsnag.com] due to a numerical overflow resulting from a type range violation. `
Re: (Score:2)
Your link has been slashdotted, so here is another https://itsfoss.com/a-floating... [itsfoss.com]
Re: (Score:2)
The best you can do is annotate C(++) and then iteratively modify portions which can not be automatically proven to the point it has Spark level (or higher) correctness guarantees, like the L4 verified project did.
Ignoring that mountainous level of work, Spark has stronger guarantees than Misra C(++) which has stronger guarantees than free form C(++) with analysis tools.
Re:Perfect specification (Score:4, Insightful)
The best you can do is annotate C(++) and then iteratively modify portions which can not be automatically proven to the point it has Spark level (or higher) correctness guarantees, like the L4 verified project did.
Ignoring that mountainous level of work,
Exactly. The ClEvEr PrOgRaMmErS wRiTe BuG fReE C crowd are ignoring that while you can, it usually involves external tools and standards and ton of work. I can never get the reason why they think it's so terrible to have those integrated into the language itself, to reduce the workload.
So this is really Ada? (Score:2)
Had not heard much about that language in years
There's an easy way to guarantee security (Score:2)
It's fun to program a coder (Score:2)
It's fun to order a programmer
To program everything in C
To patch, install, bug fix and more
And run at the first sign of bankruptcy!
It can be manly in programming
They'll cut your salary semi-annually
It's not tax deductible
Our binaries are corruptible
We're programming in the language known as C
Great, more nonsense (Score:2)
Yes, testing is limited in what it can do for security. But that primarily applies to logical errors and does apply not or only in a very limited sense to the specific vulnerabilities caused by the absence of memory safety. Hence this is _not_ a reason to give up C and this person has no clue what they are talking about.
Re: (Score:2)
Spark exists and Misra C and its competitors can not provide tool chains able to give equivalent guarantees even if it is theoretically possible. Spark is cheap too.
By the time you are following Misra type coding guidelines and add range annotation it might as well be a different language any way, that ain't C to me.
Haven't we been here before? (Score:2)
C is not the problem (Score:5, Insightful)
Re: (Score:2)
I had a fierce discussion about this with one of the programmers. He argued that we had to do everything in C++, because that is the only "real" programming language. It was also going to be a lot faster.
Re: (Score:2)
Re: (Score:2)
Of course, Python never has any security problems. Neither does Javascript.
Re: (Score:2)
Running on interpreters written in ... (Score:2)
... oh, what was it called again..
oh yeah,
C
Re: (Score:2)
1) Functionality (does the software do what it is supposed to, more or less)
2) Interoperability (using and offering APIs) 3) Maintainability (readable code, documentation, solid yet flexible design and object models, good data models, etc)
4) Testing (allowing for automatic testing)
5) Security.
I found that many software developers stop after point 2 or 3. They'll pay lip service to testing ans security, instead trusting that the testing
Re: (Score:3)
have little-to-no training
Oooof. That's not a good sales pitch for you book, trying to solve human problems with training doesn't work well. The safety industry got away from that mindset in the 80s, programmers should too.
The core problem is humans be humans, and we should do our best to mitigate that problem *without* relying on attempting to change the human.
Ha! (Score:2)
'What if We Just Stopped Using C?'
What if you just shut the hell up, hmm?
Pretty spot on definition of an Upgrade (Score:2)
A/B Testing (Score:2)
Look, this has become a religious war for many.
The C camp will continue doing C.
Their competition will use Rust and similar tools.
We'll see in a few years who's come out on top.
I would put my money in a bank coded in Rust. Place your bets.
Re: (Score:2)
Java evangelists said the same thing in the 90s (Score:2)
Java certainly got traction but nothing like what we were led to believe. Its big in certain sectors for backend dev , eg finance , and for some shitty DB plugins , eg Oracle, but thats about it even thought believe it or not it was originally designed for embedded systems.
Why not Spin? (Score:2)
Why SPARK and not Spin [spinroot.com]?
Spin uses C and not Ada. So it seems like it would be more familiar to NVIDIA's engineering staff. And the step of porting over would be omitted.
Spin can be used in way beyond what SPARK can offer. From the website:
Spin can be used in four main modes:
as a simulator, allowing for rapid prototyping with a random, guided, or interactive simulations
as an exhaustive verifier, capable of rigorously proving the validity of user specified correctness requirements (using partial order reduction theory to optimize the search)
as proof approximation system that can validate even very large system models with maximal coverage of the state space.
as a driver for swarm verification (a new form of swarm computing that can exploit cloud networks of arbitrary size), which can make optimal use of large numbers of available compute cores to leverage parallelism and search diversification techniques, which increases the chance of locating defects in very large verification models.
Of course if you do an exhaustive verification of a complex program it would take more resources to complete than exist. It's not going to solve the halting problem for you. But for narrow cases you can fully verify and there are examples of real-time schedulers and network
Re: (Score:2)
Re: (Score:2)
Re: (Score:2)
But maybe you are Super Programmer, not like those cowboys who work on the Linux kernel and are incapable of
Re: (Score:2)
Read up on the AS/400 architecture, it’s fascinating. Buffer overflows are almost non existent.