Writing Secure C and Secure C Idioms

Ethan Heilman picture Ethan Heilman · Jan 5, 2010 · Viewed 7.1k times · Source

"The average man does not want to be free. He simply wants to be safe." - H. L. Menken

I am attempting to write very secure C. Below I list some of the techniques I use and ask are they as secure as I think they are. Please don't not hesitate to tear my code/preconceptions to shreds. Any answer that finds even the most trivial vulnerability or teaches me a new idea will be highly valued.

Reading from a stream:

According to the GNU C Programming Tutorial getline:

The getline function will automatically enlarge the block of memory as needed, via the realloc function, so there is never a shortage of space -- one reason why getline is so safe. [..] Notice that getline can safely handle your line of input, no matter how long it is.

I assume that getline should, under all inputs, prevent a buffer overflow from occurring when reading from a stream.

  • Is my assumption correct? Are there inputs and/or allocation schemes under which this could lead to an exploit? For instance what if the first character from the stream is some bizarre control character, maybe 0x08 BACKSPACE (ctl-H).
  • Has any work been done to mathematically prove getline as secure?

Malloc Returns Null on Failure:

If malloc encounters an error malloc returns a NULL pointer. This presents a security risk since one can still apply pointer arithmetic to a NULL (0x0) pointer, thus wikipedia recommends

/* Allocate space for an array with ten elements of type int. */
int *ptr = (int*)malloc(10 * sizeof (int));
if (ptr == NULL) {
    /* Memory could not be allocated, the program should handle 
       the error here as appropriate. */
} 

Secure sscanf:

When using sscanf I've gotten in the habit of allocating the size to-be-extracted strings to the size of the input string hopefully avoiding the possibility of an overrun. For example:

const char *inputStr = "a01234b4567c";
const char *formatStr = "a%[0-9]b%[0-9]c":
char *str1[strlen(inputStr)];
char *str2[strlen(inputStr)];

sscanf(inputStr, formatStr, str1, str2);

Because str1 and str2 are the size of the inputStr and no more characters than strlen(inputStr) can be read from inputStr, it seems impossible, given all possible values for the inputStr to cause a buffer overflow?

  • Am I correct? Are there strange corner cases I haven't thought of?
  • Are there better ways to write this? Libraries that have already solved it?

General Questions:

While I've posted a large number of questions I don't expect anyone to answer all of them. The questions are more of guideline to the sorts of answers I am looking for. I really want to learn the secure C mindset.

  • What other secure C idioms are out there?
  • What corner cases do I need to always check?
  • How can I write unit tests to enforce these rules?
  • How can I enforce constraints in a testability or provably correct way?
  • Any recommended static/dynamic analysis technics or tools for C?
  • What secure C practices do you follow and how do you justify them to yourself and others?

Resources:

Many of the resources were borrowed from the answers.

Answer

nont picture nont · Jan 5, 2010

I think your sscanf example is wrong. It can still overflow when used that way.

Try this, which specifies the maximum number of bytes to read:

void main(int argc, char **argv)
{
  char buf[256];
  sscanf(argv[0], "%255s", &buf);
}

Take a look at this IBM dev article about protecting against buffer overflows.

In terms of testing, I would write a program that generates random strings of random length and feed them to your program, and make sure they are handled appropriately.