How security flaws work: the buffer overflow
arstechnica.com
arstechnica.com
20 years later and we're still using C++. I hope Rust takes off. The status quo today is terrible.
I suspect we'll have a Rust compiler that compiles fast applications with a very minor performance hit before this happens to aging languages like C/C++.
I'll bet there are lots of legacy codebases that would actively resist using such a compiler technology for C/C++ because of unknown behaviours happening in their codebase (and because there is no test suite, or just poor test coverage).
But even if not, and even if this accounts for 60% of existing C/C++ codebases, improving the remaining 40% is a huge win that would take tremendously more time to reimplement in Rust.
This is not to say that I am not also very excited about Rust.
Not the best data point, but showed pretty quickly who had a self-taught (and usually practical) understanding of security vulnerabilities vs an academic understanding.
Smashing the Stack in 2010 (linux, windows) - http://www.mgraziano.info/docs/stsi2010.pdf
Smashing the Stack in Windows 8 - https://archive.org/details/SmashingW8Stack
And if you have a 'load aligned double word' instruction which load two consecutive word in Rx and Rx+1 (aligned to avoid the thorny issue of page missing in the middle of an instruction), you can reduce the cost of having to manage both the array address and its length.
Sure this isn't free: more registers used, more cache used, still it doesn't look THAT bad from a performance POV no? Or very complex to implement. Is-there something I'm not understanding?
1: and if the checks fails there is TRAP executed, which is compatible with C/C++ semantic.
When I was in school, my professor for CPU Architecture had a good saying: "If you're going down to NAND gates to debug your software you're doing something wrong".
I think another issue is that arrays, trees, and other structures are a complete abstraction. The CPU doesn't need to know a thing about them for them to work, because all it actually sees is addresses and instructions (I get that I'm grossly oversimplifying things), and so introducing that type of "check" at the hardware level is pushing the abstraction down, and I don't think that's a good idea either.
But I do think that's one of the great reasons for using a higher level language, where there are array bounds checks, etc.
To me, C/C++ is like "pretty" assemby language (Now with new features like Undefined Behavior!!!), and I like that about it. But I'm not sure how other people feel.
Anyways, that's just my take on it, take it with a grain of salt.
Array boundary checking is I think desirable but I can understand that for some applications it is an unacceptable performance hit.
Given the severe potential security implications for not using it, enabling bounds checking is a sensible default in my opinion. People always mention the speed of C for example but ignore what is being sacrificed for it.
You also haven't explained how would that size information, which we already have, magically solve the problem.
char buf[512];
where we want to read x number of bytes from a file descriptor starting from a offset other than the first element: read(fd, buf + 256, sizeof(buf)); // Whoops, incorrect sizeof, buffer overflow!
Could the compiler still detect this buffer overflow error without knowing the address of the first element in the array?What about:
char *dst = buf + 256;
...
read(fd, dst, sizeof(buf));
perhaps the compiler could trace back all the calculations performed on the dst pointer to see whether this operation is valid?Many, many, many moons ago, C strings won out over Pascal strings. If the competition was somehow re-run from scratch today, with modern machines, it would be no contest: Pascal strings would win. But there was a time when every byte was precious. And not just "a bit precious", but very precious.
Maybe if we could start CPU architecture from scratch, array with sizes would make more sense? Maybe even we could done it so memory segmentation would no longer be needed: https://en.wikipedia.org/wiki/X86_memory_segmentation
Haven't figured out the details, but maybe we can even gain some performance that way.
Rust is obviously a great example. So is Go. Bounds checked arrays in languages that compile to native is not a new thing.
https://news.ycombinator.com/item?id=10125348
Also see capability-based computer systems by levy. Free book. Pointer protection by itself can give all kinds of benefits. Modern version of that is Cambridge's CHERI processor which is open-source and already runs FreeBSD. :)
I thought the daemon exploited was sendmail? ... quick search later ... so the fingerd was used. Good explanation here: ~ Eugene H. Spafford, "The Internet Worm Program: An Analysis" http://spaf.cerias.purdue.edu/tech-reps/823.pdf
I know how I would answer this question but I am curious how others would answer it.
EDIT: s/possible/known to occur
If you're thinking that memory for the program is less likely to be contiguous, then, yes, that is a way it may end up being less likely. But there are already techniques that do exactly that for systems with virtual memory (see https://plasma.cs.umass.edu/emery/diehard.html). But as long as you have a stack frame contiguous with a previous stack frame, you're susceptible to buffer overflows, and I think that will be likely even without virtual memory. (That is, the stack frames are not that large, and are likely to be well within the contiguous block size for the memory system.)
http://www.smecc.org/The%20Architecture%20%20of%20the%20Burr...
No matter what naysayers claim, the ability to inexpensively immunize a system against buffer and stack attacks has existed for decades while being deployed commercially on 1960's-1980's era hardware. The market went for what was backward compatible with IBM, UNIX, and later DOS software plus highest raw performance at lowest price. Systems designed for excellent security and maintenance (esp written in HLL) had low market share with many getting acquired, disappearing, or having security advantages removed in later releases. It's a market thing, not a technical thing.
Here's a modern example, the SAFE architecture, that's being developed by BAE & academia.
http://www.crash-safe.org/assets/ieee-hst-2013-paper.pdf
It's actually more heavyweight as it tries to fix... computing in general haha. It specifically mentions buffer overflows and stack risks with the ways they try to immunize against them. The atomic groups with associated processing are actually lightweight a la Burrough's model. They alone provide quite the bit of protection seeing how many types of attack leverage pointer, array, or stack flaws. The other tag will cause more of a hit but could do type enforcement of calling functions. Is also very helpful given interface errors underlie most attacks on systems. I've suggested porting Oberon System and compiler to this architecture to get a fully-usable box with automated protection. And see what attacks can still get through.
In any case, buffer overflows have been preventable since before they even had a name past being an example of "insufficient argument validation" (MULTICS security evaluation). They only exist because (a) market wants them to exist via how it votes with its wallet and (b) legacy software refuses to take the hit that automated protections created. The latter situation improved greatly with tools such as Softbound + CETS which enforces full safety on C code with average 50% hit, limited tools such as Control Pointer Integrity that protects pointers with a tiny hit, and tools such as ASTREE/SPARK that prove C/Ada code free of many types of errors that lead to crashes or hacks. Pretty much no uptake.
There are counterexamples though. I've seen a reverse stack on x86, a DNS server (IRONSIDES) written in SPARK, security kernels that extensively used segmenting for OS-level POLA, a web application server reducing risk w/ FSM's + a separation kernel, and recently MirageOS building a whole stack in a language that prevents so many issues at compile-time while designing for isolation in partitions. So, we can do it better, some are doing it better, and I encourage others to do the same. Look for work that knocks out issues, use it, improve it, and get our baseline up to at least OK instead of FUBAR (current status).