Code Security and Robustness
C++ has made the evening news several times in the past several years. And not because it is rescuing kittens from trees, keeping children from villains, or for somehow being instrumental in the quest for world peace. Because a majority of real-world code is written in C++, that code is often the target of malicious attacks. That's right; software viruses often attack programs written in C++.
One of the key reasons attacks are possible is the all too ubiquitous buffer overrun. C++ largely places the onus of ensuring program correctness on the programmer, and a common error is writing code that miscalculates the amount of data being copied into a buffer. Managed runtimes generally prevent this type of behavior at the expense of maximum speed (these environments must validate at runtime the length of the data and the size of its destination).
A lot of C++ developers are unaware as to why buffer overruns offer marauders such an attractive means of attack. I know I didn't until I read Writing Secure Code by Michael Howard and David Leblanc (Microsoft Press, ISBN: 0735615888). What an eye opener! I highly recommend reading this book. To be honest it made me shiver when I considered all of the dramatically non-secure code I've written in the last 10 years.
In its simplest form, a buffer-overrun attack works like this: the attacker sends a malicious data packet to the program in the guise of normally expected data input (perhaps the program processes incoming e-mail headers, so the data is a 'bad' e-mail header). Because the program doesn't properly bounds-check the incoming data (a bug), when it performs an unchecked copy of the input string into a stack-allocated buffer, it corrupts the values of variables allocated on the stack around the buffer. But the corruption is far from randomattackers carefully analyze the target program (victim) and craft input to overwrite the program's data with known values. For example, viruses may attempt to overwrite a value on the stack defining where the program should jump should an exception occur, with the address of the attack code (also delivered in the malicious input). Causing the program to trigger an exception is often trivial (more decisively placed bad data), and once that occurs the malicious code executes and takes over.
So, why am I digressing into this explanation? Well, to scare you. Be afraidbe very afraid.
|Fortunately, protecting your code isn't an impossible prospect.|
Fortunately, protecting your code isn't an impossible prospect. It does require work on your part, and perhaps an adjustment to your coding style. Visual C++ can help too, with a set of features introduced in Visual C++ .NET and improved upon in Everett.
Runtime Error Checks (/RTCn) and Compiler Buffer Security Checks (/GS) are features in the compiler that help improve the robustness of your code. Runtime Checks are intended to aide during the debug/test process in identifying common programming errors, including buffer overruns and stack corruption. Buffer Security Checks are intended for you to use in release builds, and offer a level of protection against attacks like the one I described above. But take note: this technology is intended only to make a severe situation less severe. /GS doesn't prevent attacks, nor does it detect all types of attacks. What it will do is shut down a program when it detects a known type of attack. That is to say, /GS won't detect or protect against all possible attacks.
Microsoft introduced /GS in Visual C++ .NET, and Microsoft improved /GS in Everett with an expanded knowledge of attack types. When you specify /GS, the compiler injects code into functions it decides are at risk. This code checks the value of a random 'cookie' to see if it has been subverted. Developers should always use /GSthe overhead produced when this technology is used is slightroughly 9 instructions per function (and not all functions require this instrumentation). Programs compiled with Everett, (whether they specify /GS or not, actually) also cooperate with the underlying operating system (Windows .NET Server and better) to further protect against certain types of attacks. (See Sidebar: Enhanced Debugging)