X
Business

.Net code unsafe? .Not exactly

Heard about buffer overflow problems in Visual Studio .Net applications? Larry Seltzer separates fact from fiction.
Written by Larry Seltzer, Contributor

With the exception of this column, of course, you really shouldn't believe everything you read. Or at least, you should read every statement of alleged fact with some level of skepticism. Believe it or not, sometimes people exaggerate or even misstate facts.

Such was the case with the recent stories of buffer overflows in .Net. The headlines were especially bad, implying that there were security problems in .Net, or maybe in .Net applications, or maybe even in Visual Studio .Net itself. The truth of the actual news was much more narrow and makes for much less interesting headlines: Some programs created by the new version of Visual C++ .Net in the newly released Visual Studio .Net are vulnerable to the same advanced buffer overflow attacks as applications built with other compilers. Many, perhaps most, .Net programs will not be at all subject to this problem. Furthermore, nobody (Microsoft included) ever claimed any different.

The stories all fed off a release from Cigital, a security consulting firm. Cigital's press release doesn't go into details, but implies that Microsoft sold the buffer protection features of Visual C++ .Net as an absolute defense against buffer overruns, and they just plain didn't. In fact, Cigital's more detailed explanation references an article written by a Microsoft Program Manager that concludes by saying: "There is no substitute for good programming skills and peer code review for discovering and fixing vulnerable code. That said, the new /GS option in the new Microsoft Visual C++.Net compiler will help reduce the instances of exploitable buffer overruns in your Windows application code."

The documentation for the infamous feature of the compiler, specifically the /GS switch, is "new">available online for you to read for yourselves. The new VC++ has other stack protection mechanisms, such as the /RTSsu switch that detects several classes of run-time stack errors, such as accessing uninitialized variables.

Nowhere in the documentation will you find a claim that /GS eliminates buffer overflows. I'm not aware of any claim to that effect by Microsoft anywhere. What's actually in the documentation for /GS is pretty interesting. The way it works is that it puts its own computed security cookie on the stack before the return address. At the time the function exits, security check code recomputes the cookie and checks to see that it has not been overwritten, as it would have been in a simple buffer overrun. If the cookie has changed, the program exits with an error rather than risk running the attack code (that's the default behavior; programmers can write their own handler to do something else in event of a smashed cookie).

Other, more advanced types of attacks (see this PowerPoint file for examples), ironically, are much more mature on UNIX than on Windows, but they are being ported as we speak. They tend to take advantage of vulnerabilities in operating system structures and compiler runtime libraries.

Microsoft's first public response to the Cigital claims can be found on the BugTraq mailing list, and a more formal, official response is on the MSDN site. (Anyone interested in this issue really should read these responses.) On BugTraq, Brandon Bray of the Visual C++ Compiler Team goes into more detail about why Microsoft implemented /GS the way they did. A major theme in the response is that adding automatic protection against other than "first generation" attacks would add complexity and performance degradation that developers would not accept. There's no doubt in my mind that the same people whining over the lack of absolute protection against buffer overflows would be whining about the performance hit if the protection were up to their own standards. In both responses, Microsoft denies Cigital's assertion that /GS is a port of StackGuard, a product of Immunix, and states that Microsoft developed their approach independently.

Too bad that software engineering is always a matter of trade-offs between competing interests, and performance is usually one of them. If protecting against buffer overflows were a straightforward matter then someone would have done it by now. There are other systems out there for protecting against buffer overflows, but they all have to make the same decisions. The only ways to prevent these attacks completely are to:

  1. analyze your code, detecting unprotected buffers
  2. stress test your application heavily to detect errors, and
  3. use tools, such as /GS.
None of these methods is perfect, largely because software is too complex for them to be comprehensive.

You don't have to read very far into Cigital's detailed abstract to discover that this problem relates only to native code and not "managed code." In .Net, most programming--ideally as much as you can get away with--should be compiled not to native code but to an intermediate language called MSIL, in which problems like buffer overruns are not an issue (at least they're not supposed to be). The ability to write native code is in there because some developers need to go beyond what MSIL and the .Net framework allow, but one would expect native code to be comparatively uncommon in a .Net world. The fact that there is less of it means that there is less to audit for security problems. Of course, this has been Sun's approach with Java for years: to run all programs within a virtual machine, one function of which is to prevent illegal operations by miscreant code. Eventually it will make sense, but the trade-offs are so stark that I'll believe users will accept this when I see it. We're a long way from a real solution to these problems.

What's your experience with Visual Studio .Net? Problems? Praise? E-mail Larry or post your thoughts in our Talkback forum below.

Editorial standards