Slashdot Log In
Are Buffer Overflow Sploits Intel's Fault?
Posted by
CmdrTaco
on Sat Jul 29, 2000 12:22 PM
from the only-if-you're-looking-for-someone-to-blame dept.
from the only-if-you're-looking-for-someone-to-blame dept.
Bruce Perens submitted a story he wrote for his website on overflows and who's fault they are. I'm pretty skeptical of almost every point raised in this story, but it's an interesting read. [Updated 21:13 by t] As Sea Monkey points out, Bruce has now taken down the article, with a brief note: "I've withdrawn this article after enough people convinced me that I didn't know what I was talking about. It happens sometimes. Thanks." What if everyone displayed such grace?
This discussion has been archived.
No new comments can be posted.
The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
Full
Abbreviated
Hidden
Loading... please wait.
Re:Blame the CHIP? Blame the LANGUAGE? Pfah! (Score:3)
I disagree with this, making it the developers responsibility to write bounds checking code every time they deal with input is why we are in this mess today. Not a week goes by without annother buffer overflow sob story on Bugtraq. Asking software developers never to make any mistakes, ever, is not a realistic solution and assigning blame isn't going to make the problem go away.
There are a few possible solutions, none of them really easy.
Buffer overflows and other common security problems have been with us for over thirty years and still aren't in the "solved problems" bin. This is inexcusable. If people are going to rely on computers in their daily lives, the computer have to be reliable and having the possibility of security comprimise using 30 year old techniques does not a reliable computer make.
Re:Blame the Language (Score:2)
At least gcc's features are open --- If people are worried about gcc accepting non-standards-conforming code, why not hack it into -pedantic or -ansi themselves and release a patch?
I'm stupid and careless (Score:3)
And to help half-wits like us still do something useful with software, it might be nice to give us tools we don't hurt ourselves with too much. You know, scissors instead of a Samurai sword. A Toyota Camry instead of a Formula 1 race car. 110V household current instead of 50KV "professional" power.
The fact is, C/C++ is too powerful for me. Oh, I understand it just fine, and with enough time and effort, I can make something work semi-reliably in it. But what's the benefit I get for that self-flagellation? Should I spend all that extra time because finding the bugs "hurts so good"?
The fact is: writing code in C/C++ is a lot of unnecessary work. The only reason why people put up with it is because everybody else does it, so it's the path of least resistance if you want to use the "standard" compiler on your platform, use a language other people are likely to understand, and use other people's C/C++ libraries. But make no mistake about it: C/C++ is successful these days in spite of its cumbersome design, not because of it.
Re:strict code/data sections (Score:2)
The OS'es fault (and language's) (Score:2)
It is also the fault of the language. For its first 10 years (when it did not have C), there was literally never a buffer overflow bug on any program in VMS. For example, the internet worm exploited only Unix hosts, and couldn't do anything to VMS hosts. However, in the last 10 years, VMS has adopted more C programs, and the number of buffer overflow exploits has risen from 0 to a siliar amount on Unix. The string and array methodologies under C are incredibly fragile and primitive (as well as very low performance - you need to access byte at a time, which is VERY SLOW on modern architectures), and more advanced languages have much more high performance and more secure methodologies of dealing with data.
Re:C++ IS NOT TYPE SAFE! (Score:2)
safe assembly language (Score:3)
'' Oh? I'm fairly sure machine code is /also/ "unsafe", and that's what your pretty source code ends up as. How do you prove that your oh-so-wonderful language is still safe when rendered into raw machine code? ''
I'm sure you're thinking that you've got me beat, but in fact this is a great question!
The old, less-satisfying answer is that compilers are less likely to have bugs than the programs they're given. This is probably true (I don't recall any exploits due to compiler bugs, though to be fair I do recall some Java VM exploits).
The new exciting answer is: We use a type-safe subset of the target machine's assembly code.
In our TILT [cornell.edu] compiler for instance, we take ML code and put it through a series of transformations. At each transformation or optimization we also translate the types (a static proof that the program can't crash) until we get to machine language. This catches a lot of compiler bugs, and helps propagate safety properties to the raw code.
The result is that we have machine language which can pretty easily be checked for type-safety. This allows us to do some other cool things, like ship the proof along with the raw machine code, to be executed on someone else's machine. They don't have to trust us (just the proof), and it doesn't suffer sandboxing costs like java. Wow! Read about Proof Carrying Code [cmu.edu] .
The second answer isn't really usable today, except in theory. The first is absolutely practical, though. (even if it fails due to compiler bugs, we'd still cut down on a high percentage of errors -- and we'd only need to fix bugs in one place).
Re:Why do people still program in C? (Score:2)
Re:Blame the programmer (Score:2)
If I read you correctly, the burden to avoid buffer overflows should be put on the programmer, not on the hardware or on the machine. Then you start advocating that the compiler/library should take care of this! Isn't that like just laying the safety net a couple feet higher?
As a general rule, I think dumb tasks should be left for the machine, the noble ones for the programmer. Checking whether a given input validation is a potential door for an exploit is the programmer's responsibility.
Another thing that you seem to suggest is that quick and dirty test code should be the basis for production code, thus holes could migrate to the final product. I think the ideal solution is to discard test code altogether and start from scratch, but who does that, right? One other approach, which I actually use and believe many do, is to check for errors (at least return values) from the very beginning, so as those parts which will inevitably be cut and pasted to the production source are structured in a way that adding extra checks would be much easier (favouring using heap memory, encasing calls in try/catch blocks in C++, for example)
Just my $0,02
Re:Blame the Language (Score:2)
You can write object oriented code in any language you like. You can write procedural code in any language you like. Object oriented langauges simply facilitate the use of object orientation by providing you with tools that take advantage of it. You can write oo basic, and you can write procedural java (just make everything static and put it in your main class). The paradigm is not being forced on you. You simply ignore some of the features. But don't take my word for it, look at the tour if C++ in Starstroup's The C++ Programming Language.
Polymorphism, encapsulation, and inheritance are simply properties that fall out of the OO paradigm and are implemented to take advantage of it of its implications. Ultimately the right tool for the job in any given case may or may not implement these.
--locust
Bull Pucky (Score:4)
Nicholas C Weaver
nweaver@cs.berkeley.edu
Re:Blame the Language (Score:2)
--
-jacob
Re:Why do people still program in C? (Score:2)
A lot of (bad?) programmers do a lot of unnecessary work with their strings because they don't know whether they need to be copied or not, so they always do it. C++ offers string classes that make this irrelevant. Reference counting leading to copy-on-write ensures much greater simplicity and often better performance. A decent string class implemented using a bridge pattern will only be 4 bytes (same as a char*) - it will just consist of a pointer to its implementation and so it can passed around on the stack very quickly. They also have the benefit of being guaranteed '\0' termination. Much easier to handle embedded NULs too.
Why MacOS doesn't get 'sploited and why it matters (Score:2)
It's because MacOS uses one big-ass shared memory space to run everything in that it's safe from being taken over by buffer overflows. Well, gee, if it's all unprotected, why is it so safe? Because while you can still crash a program with a buffer overflow, you can't predict the stack address. And the critical part of a stack overflow exploit is to get the program counter pointing to the exploit code on the stack.
And even if you could, what would you do with it? There's no shell (at least not until OS X, but that's a completely different OS) to give commands, and no root privs to exploit (actually you are "root" at all times!)
Intel is relatively low on the fault scale here. A bigger problem is the number of people running Linux distros with the same binaries in them. If you compile your own code, the stack addresses will be less predictable (though not completely unpredicatable), and you'll be in the same boat as MacOS: without a predictable stack address, there's no way to run the 'sploit code!
If we simply had more people compile code their own binaries, the problem would be reduced.
But at heart, the fault is one of languages that let you stick things into memory without any sort of range checking. Get too much data or lose the null terminator from a C string and your stack is toast.
And most of these problems happen inside of a library routine. But you can't blame the library routine when it has no way to know the size of the destination buffer. The best it can do is know where the frame pointer is and to not write past it.
If C strings were more than just bare buffers with only a lone null to save you from oblivion, the library routines could be smart enough to save your ass. So I blame C and its strings as the primary problem causing buffer overflow exploits.
Use a language with internally checked datatypes and no bare pointers like Java or Perl, and this type of exploit will go away.
Re:Why MacOS doesn't get 'sploited and why it matt (Score:2)
Use a language with internally checked datatypes and no bare pointers like Java or Perl, and this type of exploit will go away.
Programmers writing SUID programs should also be capable of using pointers without creating buffer overflow exploits.
Or do you think the problems with buffer overflows outweigh the potential gain from using pointers in the first place ??
I strongly prefer the additional power of constructs in C that are provided by pointers. I do not think that a higher level language is likely to be any safer. Sure, the language may conceptually be without overflows, but the increased size of the compilers/interpreters makes those much more difficult to check, and still prone to overflow.
Re:Bull Pucky (Score:2)
Unfortunatly, the semantics of C do not allow easy general bounds checking, since arrays are semantically defined as pointer arithmatic, eg foo[i] is equivelent to *(foo + i). There is no actual array type in C!
A C-compiler can attempt to funge things to try some bounds-checking like operations, or hacks like stackguard which detect a class of misoperations or purify which does the same thing in a different manner, but the language itself semantically doesn't allow bounds-checking in general, due to how arrays and pointers are typed, without going through serious hacks like what Purify does. Of course, Purify ends up costing more then the bounds checking in a proper language would cost.
Nicholas C Weaver
nweaver@cs.berkeley.edu
Your Really Bad Solution (Score:2)
An AC says:
"duh, this one is really easy to solve. wrap delete with an inline function that checks if the pointer is NULL, deletes, then sets it to null.
no more multi delete problems. (of course, you really should fix the bug that causes you to delete the pointer twice, but you can't really blame the language for your own ineptitude...) "
I boggle, and respond:
Wow, now THERE is a severely misinformed post.
#1. I'm contending that we use more advanced languages because they make life easier for both good and bad programmers, not merely compensate for "ineptitude".
#2. Your solution is 100% wrong.
C * a = new C();
C * b = a;
delete a;
delete b;
'b' is a different memory location, which isn't set 0 when 'a' is deleted. Unless you're implicitly suggesting that we move to memory handles (which is going to give you MUCH worse performance than modern languages which just don't let you write this kind of program), your solution doesn't solve anything at all.
And here's the real beauty... (Score:2)
But the cool thing is -- you can just make the page tables regarding the code address spaces point at the same pages as the data (and vice versa), and do this at page granularity. So you can make an 8k buffer that is read/write/execute (but accessed with different linear addresses when used as code or data) for your genetic programming, but keep the rest of your program safe.
VM tricks are so much fun. ^_^
What a great great man -thanks Timothy (Score:4)
Or what if everyone bothered to do some research before writing and self-promoting some inane rant.
Re:Its not intel's fault(history) (Score:5)
If you used the segment registers, the result was basically a highly non-linear address space. In a lot of ways, it was an 8 bit processor with 16 bit registers and hardware bank switching (for those of you that remember bank switching).
as a result, there were a few 'standard' memory models that programmers used:
- Small address space: All segment registers the same. don't touch them. This gave you a flat 16bit (64k)address space, turning the machine into a glorified 8085/Z80 -- almost completely source code (assembler!) compatible. It also gave a slight speed advantage, since all pointers and integers were 16 bits wide.
- Intermediate address space: segment registers point to disjoint spaces. not too much difference but you get some breathing space since the code and data don't share the same (tiny!) 64K address space.. pointers are still 16 bits, but you now have to remember which segment you're talking to.
- 'large' address space: all pointers are 32 bits wide. (include both segment registers and then pointers within the segments). This gives you access to the full 1M address space. (the 640K limit was because 380K was reserved for I/O space).
The 80286 allowed people to break the 1M barrier without doing bank switching (EMS?), but it turned the segment register/pointer problem into a serious horror story. Unless you were seriously masochistic (or just plain desperate) you just made it look like an 8086 that ran a bit faster.SERIOUS performance hit. If you allow arrays >64K then just about every array access requires you to calculate and load the segment register. address math sucks because if you have two 32 bit addresses A and B, A != B does not necessarily mean that they don't point to the same memory, and *X++ can require some serious work to do the exepected thing.
When they came out with the '386 you now had segments of 4GB each. This was at a time when a 2GB ram module could have been camouflaged as a desk and would have required a 15KW watt power supply.
Most programmers and OS designers just set all the segment registers the same (the '386 equivalent of the 'small memory model', and forget about them (I called this traumatic amnesia).
So, yes: Intel has a Segment model that could be used to provide security, but few people are brave/stupid enough to risk the horror stories/ flashbacks that enabling it might entail.
Intel: Just short of intelligent.
Re:Bull Pucky (Score:2)
From the view-point of dealing with stack smashes specifically, this can be helpful. Arrays, like any other statically or automatically allocated objects, are declared on the stack, whereas dynamically allocated "arrays" (the target of pointers usually) are declared on the heap. Of course getting rid of stack smashes isn't quite as interesting as getting rid of buffer overruns altogether (both stack smashes and "heap" smashes), but the difference can be useful.
As I mentioned in another post, though, you can interpret C as much as you want. There's no reason for a C implementation to have a compiler, and even a human being can (in silly situations) be considered a compliant implementation. If you interpret the hell out of it, so that for everreference to an object, you trace its history throughout the program, you can be fairly safe. It might take an hour just to go through a single instruction; "hello world" might take six years to run on the fastest Cray, but it will give you everything you ever wanted to know. Of course these are silly examples: usually C interpreters only slow things down by a magnitude of a few hundred times (or less) when compared to compiled code. But you only have to interpret once and get an "everything is OK" before you can take that same code, turn around, and compile it.
This is, of course, possible with other languages. There are political and legal obstacles with Java, I think. But for all complex languages (of which I'm saying C is not), making your own interpreter is too much trouble for such little reward.
Re:It's the industry as a whole. (Score:2)
Yes, C++ is somewhat better than C because it does allow you to build abstractions that perform more checking and automatic resource management. But even if you do that C++ is fundamentally unsafe. Why?
C++ still uses the C pointer model and adds a similar reference model. And C++ still uses manual memory management for dynamic allocation. You cannot, in general, address those problems by creating safe abstractions. If you try, you end up severely limiting language semantics, and as soon as you face any outside library, you have to convert to raw pointers anyway.
And C++ still does not guarantee fault isolation among modules or any way of determining from the source code of a module whether that module is safe or not. That is, any piece of code you link with can cause arbitrary problems in any other piece of code, and you have no way of telling. Perhaps you think that's inevitable, but it is not. None of the other languages that I mentioned have that misfeature.
Arguing that one should not bother fixing those problems because there are lots of other ways in which people can make mistakes is wrong. The problems C/C++ creates for programmers are easily avoided, without performance penalty or other drawbacks. A day lost trying to chase some avoidable pointer bug in a C/C++ program is a day that could have been spent on testing and fixing some conceptual security bug.
I have been using C for 20 years and C++ since before its first public release (nearly 15 years?). I still use them a lot because that's what interfaces best with the software that's out there. At the time, they were reasonably good tradeoffs. But this is the year 2000, and tradeoffs that were good then are not good anymore.
Buffer Overflows (Score:2)
Re:C++ IS NOT TYPE SAFE! (Score:2)
So, if you don't use pointers, address-of, array subscripting, call-by-reference, or any library functions that do, yes, then you can write type-safe C++ programs. Too bad that you also can't do much in that subset of C++.
There is no problem with providing those unsafe constructs in a systems programming language. In fact, lots of languages do, just like C/C++. The problem with C/C++ is that the safe constructs and the unsafe constructs are indistinguishable, and that means that even the 99.9% of a program that can be written nicely with the safe constructs use the unsafe ones, and as a result are much more likely to crash.
It's the industry as a whole. (Score:4)
The underlying problem is that C/C++/Objective-C do not have mechanisms to protect against these kinds of problems. In fact, it's impossible to write substantial programs in those languages that use only "safe" constructs. This is a peculiar and fundamental bug in the C-family language design.
There are excellent alternatives around. Modula-3, Oberon, Ada, Sather, and Eiffel all have efficient, free, open source implementations around, they all provide access to unsafe features when needed, and one of them should satisfy anybody's programming needs. Java is an excellent applications and server programming language, although it has a bit more overhead and no access to low-level features.
So, folks, get with the program and stop writing servers and other applications in C/C++.
This is a very old debate.... (Score:3)
This is a very old debate, and it's been raised on the kernel list several times. The problem is that it seems pretty clear that given a buffer overrun attack which can be exploitable without the stack-exec patch, it's possible to transform that attack into an exploit which will work with the stack-exec patch present.
It may require more work to create the exploit, but it's the sort of thing which only one person needs to do and then share with 100,000 of his best friends on some cracker web site. Hence, such a patch only provides the illusion of security, and it adds crap to the kernel. (There's all sorts of kludges you have to put in there to make sure that trampoline code doesn't break, etc., etc.)
Its not intel's fault (Score:5)
Of course since most of the OS's don't properly use the protection mechanisms Intel has provided, I guess it becomes Intels fault if they don't extend the arch to support a feature and potentially break downward compatibility with other OS's using the current paging system.
Re:C++ IS NOT TYPE SAFE! (Score:2)
In C++, this might look like:
char *p = unsafe::allocate(char,100);
char c = unsafe::ref(p,10);
float f = unsafe::castref(float,p,0);
Of course, C++ would also need to eliminate the unsafe constructs it has outside namespace "unsafe", and in some cases add safe constructs to replace them. Then, you could limit the use of unsafe constructs to only the few places where you actually need them. That greatly reduces the probability of making errors. Languages that do this exist: Modula-3, Oberon, and others. There are no such languages in widespread use yet that look like C or C++, unfortunately.
Blame the Language (Score:5)
Aside from speed-critical stuff like kernels and Quake 3, I don't see the need to write programs in C and C++ any more.
Let's start using modern languages with type safety. They're easier to write programs in (because debugging is easier) and not that slow.
I know that I'd gladly take the 2x speed hit on my security-critical apps (mail daemon, web server, ssh, etc.) to know that they cannot have this kind of bug in them, because they were written in a language like ML, Eiffel, Haskell, or even Java.
Re:It's the industry as a whole. (Score:2)
For Modula-3, go to www.m3.org and follow the links (a whole operating system with various network services has been written at it and is still in use at U. Washington). For Ada, you'll have to talk to your local defense contractor; lots of real-time military systems are written in it, so it definitely gets the performance (Ada is a bit too pedestrian for my taste, so I don't follow it much). For Oberon, the entire Oberon operating system, drivers, compiler, web browser, and other things are written in it, and they are open source.
If you haven't noticed, relational database performance on UNIX sucks. It takes milliseconds to get any data out of the damned thing, which is why everybody is using stored procedures, which means they put code back into a single process. I have not seen any TCP/IP stack under UNIX systems that is "split up along process lines"; if the Linux or SystemV TCP/IP stack crashes, so does the whole kernel. Both of these examples make my point.
But it's the kind of wrapping I'm talking about, and it's the kind of wrapping that is necessary to make C++ a safe language.
The problem with C/C++ pointers is not that they model the hardware very closely. The problem is that they aren't typed sufficiently finely: heap and stack allocated arrays, displaced arrays, references to stack variables, references to locations in data structures, heap allocated data structures, etc. are all represented by a single type, a "pointer". Other languages use different static types to represent those different constructs. And those constructs are different because they are associated with different object lifetimes and different opportunities for (optional) runtime error checking.
Adding those extra static types to distinguish the different meanings of "pointers" has no runtime overhead at all. And if you (for some reason) need to convert among the different static types, a call to "unsafe::convert_..." would do the trick, again, with no overhead, and would indicate that something funny was going on.
The way it is in C/C++ right now, the compiler just doesn't have the information to give meaningful compile time warnings or errors. It also doesn't have enough information to insert efficient runtime error checks if the programmer wants that for debugging. Ultimately, the lack of static type information is even counterproductive for generating efficient code on upcoming architectures.
Re:C++ IS NOT TYPE SAFE! (Score:2)
struct Cast { int x[1]; float y; };
int float_bits_as_int(float f) {
Cast c;
c.y = f;
return x[1];
}
Here is another example:
int float_bits_as_int(float f) {
float *p = new float;
*p = f;
delete p;
int *ip = new int;
int v = *ip;
delete ip;
return v;
}
These "logic errors" are related to type errors: they allow the bits of an object of one type to be interpreted as the bits of an object of another type. A system that's type safe guarantees that that doesn't happen.
In any case "type safety" doesn't just mean compile time type safety. Java has a lot of runtime type safety, where type errors are caught at runtime, not by the compiler. That's still fine for many purposes. C++ has neither.
strict code/data sections (Score:2)
There are architectures (Gould/SEL-32/xx is one) that allow for and, in some cases, insist on strict divisions of code and data pages. The code sections are read only, and will generate a fault if an attempt to write to it occurs from a non-system level.
The data sections are read/write, but you cannot branch there.
It makes it a bit difficult to write self-modifying code, but not impossible if you really need to.
---
Interested in the Colorado Lottery?
Intel says use the SEGMENTS (Score:2)
So what is an Intel-baesd, flat-mode program to do? It sets up two segments - one data, one code - pointing to the same memory. Goodbye hardware security.
Of course the VM doesn't protect against execution - that is the segmentation system's job. Linux (and anything else that assumes a 68k or VAX flat address space) just blows it off.
Simple solution - bring back seperate code and data. Excuse me, I and D. Just like the PDP-11 UNIX grew up on.
Re:Bull Pucky (Score:2)
I don't think this is "no matter the architecture". The need for trampolines is chip-architecture dependent, and any compiler writer who uses trampolines where they're not absolutely forced to should be shot.
Re:Blame the Language (Score:2)
Instead, they have their very own set of blind spots and biases and bad habits. Non-viable mutants are a "new breed" too, but that doesn't mean they're an improvement.
Ah-hah... (Score:2)
Thanks for that.
Re:Its not intel's fault (Score:3)
Re:It's the industry as a whole. (Score:2)
The underlying problem is that C/C++/Objective-C do not have mechanisms to protect against these kinds of problems. In fact, it's impossible to write substantial programs in those languages that use only "safe" constructs.
I should note that the above use of the word "impossible" is misinform{ed,ing}, and bias{ed,ing}.
Management of buffers is a low-level detail that only needs to be taken care of once. Hiding details such as this is something that a good C++ programmer can do with elegance.
If you write a C++ application that uses intelligent string classes such as the STL's std::string, then it becomes very possible to write buffer-safe programs. In fact, it's kind of hard to use std::string in such a way that it does break. (Of course, you have to deal with the fact that all the syscalls use char[]'s rather than string objects, but most of those syscalls should also probably be wrapped in classes -- See the ACE lib).
As mentioned in other posts, it's often just as easy to create security problems (and other data-integrity-destroying bugs) in other languages.
If there is a "fundamental bug" that causes thesee problems, it's the low standard that we currently hold software to. Not even bringing in certain high-profile/buggy pieces of software into the picture, I can speak from personal experience on this one. Quality is a distant second to rapid deployment in many domains. Well-written and bug-free code is a subtle thing to enjoy, but one that I think will eventually come into greater popularity.
So if we could all, as engineers, begin to refuse to produce sloppy code in the face of deadlines and such, I think this type of situation will eventually fix itself.
Just my thirty pieces of silver's worth.
The unsafe C library (Score:4)
They need to be deprecated more forcefully. All the unsafe functions should be pulled from the standard C library and moved to something like "deprecated_unsafe_library.h". All set-UID programs need to be purged of those functions. Now. Any manufacturer shipping a system with those functions in a security-critical program should be sued for gross negligence.
Re:Blame the Language (Score:5)
Educate the programmer on *why* things like sprintf, strcpy, etc. are Bad Things, don't force them to use a Bondage and Discipline-style language like RPG or Java that forces the programmer to do what the *language designer* thought to be The Right Thing.
Instead of using a new language that probably wouldn't be suited to the task, why not write something like lint, but for security holes?
Also...
*PEOPLE SHOULD ENABLE ALL WARNINGS ON THEIR COMPILERS. WARNING CATCH MANY BUGS AND OTHER NASTY THINGS THAT WOULD OTHERWISE BE IGNORED.*
Re:Blame the Language (Score:4)
- gets()
- scanf()
- poor use of *scanf() or str*()
are programs that have (a) been written 10 years ago; or (b) written by programmers who learned how to code in C 10 years ago. Yes, there are stupid technical school and high school teachers too, but normally, before anyone gets to a level where they can do something useful, they will have found a clueful reference to get rid of all that nonsense.
There is a new breed of C programmers, though. They don't assume Unicisms, PDPisms or TheirPlatformisms, and their eyes actually burn a whole through their skull upon the mere sight of gets(), scanf(), or any of the other death traps.
C is a good language. C++, of course, is not, though (hey, if you can get modded up for ignorant flamebait, why can't I?)
Dissecting the Buffer Overflow Problem (Score:3)
Crispin
-----
Immunix: [immunix.org] Free Hardened Linux
Chief Scientist, WireX [wirex.com]
Bounds checking is too Slow? (Score:4)
Ick. That's just the sort of mundane task I want a compiler for. As a programmer, I already have too much to worry about -- bounds checking is one simple task that I'd just as soon have the compiler do.
In most cases, the bounds check can be hoisted out of loops, so there's almost no overhead. In a perfect world, I'd like to see a compiler that, when given a high enough warning level, warns that it can't hoist bounds checks.
Blame the CHIP? Blame the LANGUAGE? Pfah! (Score:3)
Blame the developer!
Sure, some operating systems or languages or chips hold the coder's hand and make some dangerous things impossible or difficult to do.
It's still the programmer's fault for not knowing what the (void*) they're doing.
This is the same argument as "C++ is slow!" It's only slow if you don't bother to learn what code a C++ compiler generates, using lots of mechanisms without realizing it. C++ implements its mechanisms as tightly as it can, but every mechanism you use takes some time to operate.
Back to buffer overrun security: If you are gonna accept data from an untrusted source, why are you (1) putting it on the must-be-kept-inviolate stack, (2) not doing everything in your power to accept no more than n bytes that have been allocated?
If the compiler docs specifically say "data in auto variables will never be put into an executable address space," and it does, then it's time to fix the compiler or docs. Likewise if the docs belie the behavior of a chip, time to fix the chip or docs.
Don't blame a microprocessor for your mess. Don't blame a language for your mess.
You have only yourself to blame.
Praising Bruce's "grace" was not my first thought. (Score:3)
Try this hypothetical: what if, instead of doing public speeches, polticians took to publishing their opinions in articles on the web? That way, if anything they say produces a bad reaction, they can just edit it away, and no one will be able to figure out what the complaints were about. Very convienient, eh?
My take: If you publish an article, and then later recant, the thing to do is to add a link at the top pointing to your later thoughts on the subject.
Re:Its not intel's fault (Score:3)
Almost every 386+ OS has not used segments the way Intel intended. So yes, they've had quite a few years (more than a decade) to add an execute bit, if they actually cared.
Re:Its not intel's fault (Score:3)
There are 4 privilege levels. Does anything other than Multics use more than 2?
Code, Stack, and Data exist in completely seperable address spaces.
A running process has access to some 8000+ local 32-bit address spaces and some 8000+ global 32-bit address spaces.
A selector can specify a buffer to byte granularity.
Basically, the problem is that in current systems, CS, SS, and DS all point to the same nice linear 32-bit address space. Away with segmentation. It's a bit more complicated than that, but in general, most code can be read and written, most data can be executable.
The problem has been solved many times. I think some of the old Burroughs computers did some neat things. Unfortunately the good ones die because of a 5 or 10% performance lag, or they refuse to run certain bugs without complaint.
Executable code on the stack??? Seems like a very bad idea.
Null terminated strings. Nice trick, but miss a \0 or try to handle raw binary, and you have severe problems.
Will anything get solved? Probably not. Any solution will break existing code, or more realistically, discover that the existing code was already broken, only nothin knew or cared about the consequences.
PS, Not a Joke (+ more info) (Score:4)
Lest you be confused by the +1 funny on my post, let me say that I am not joking.
2x slower is the most conservative estimate for the speed of modern safe languages against C code. (In practice I've seen much better. Does anyone trust benchmarks?) My point is, even if it is 2X slower, I'll gladly take it and sleep a little more soundly at night knowing that my linux box isn't being hacked due to 20 year-old issues. 99% of my box's CPU time is spent at Nice -19 trying to find big primes for the GIMPS project.
Modern languages (take java if OO is your thing, but there are more intersting languages around) have SOLVED this problem with buffer checking (or static proofs that checking isn't needed). Without having to worry about this type of common security hole, programmers can spend more time on things we REALLY need: documentation, maintainable code, asymptotic speed increases, and the other possible security holes (ie, not escaping shell metacharacters in user input).
See my thread on Functional Languages for what I think is a convincing argument about modern typed languages in general. I know my position is extreme, but that doesn't make it a joke.
http://slashdot.org/comments.pl?sid=00/07/01/23
Re:Buffer Overflows (Score:4)
No, I think that's more akin to what a packet sniffer does. But close!
Blame the Programmer (Score:5)
This statement troubles me. C/C++ addict who have little exposure to other languages have little knowledge of what they're missing.
_Many_ (if not most?) security attacks involve buffer overflows. You have to _work_ and _think_ to free yourself of buffer overflows in C/C++. In other languages, this protection comes for free.
Yes, it's possible to make a secure program in C/C++. But it's just a hell of a lot easier in bounds-checking languages.
So there.