CSEC3616Cybersecurity Engineering

    Null termination, integer overflow, format strings, use after free

    Four programming errors beyond the basic stack overflow: missing null terminators, integer overflow, format string errors with printf, and use after free or double free.

    • Explain how a null termination error leads to an overflow or a leak.
    • Describe integer overflow, including the signed and unsigned comparison case, and name two real incidents.
    • Say what %n, %x, %u and %s do in a format string, and give the three consequences of passing user input as the format.
    • Distinguish use after free, a dangling pointer, and a double free.

    15 min readJump to the quiz ↓

    C leaves lengths, ranges and lifetimes to the programmer

    C leaves lengths, types and memory lifetimes to the programmer. Errors in each can compromise a program, even without the stack overflow covered earlier.

    Null termination. C does not store a string’s length. A function such as strcpy, strlen or printf("%s") finds the end by scanning memory until it meets 0x00. A null termination error is a program that either leaves out the terminator, or misjudges where it is. The functions then keep reading or writing past the buffer, which causes buffer overflows or information leaks.

    The n versions of the string functions do not remove this. If the n given is smaller than the real input, the string in the buffer is no longer null terminated.

    Integer overflow silently truncates values

    Integer overflow. It can happen when a value being stored or calculated is too big for its variable. It can also happen when signed and unsigned integers are compared. The result is truncated to fit the variable’s maximum size.

    The notes’ example, with 32-bit values: a = 0xffffffff, b = 0x1, r = a + b. The true sum is 0x100000000, but the stored result wraps back to 0, because 0x100000000 % 0x100000000 = 0.

    It is dangerous for the same reason as a buffer overflow: compilers silently ignore it, and it is hard to detect even after it has happened, until a fatal crash. The lecture cites it as the root cause of the Ariane 5 rocket crash in 1996, and as found in the software of the Boeing 787.

    User-controlled format strings can crash, read or write memory

    Format string errors. A format string controls what a print function outputs. In printf("Number one = %d\n", 1) the format parameter %d takes a decimal value, here 1. Other parameters on the slide:

    • %n stores the number of bytes written, through a reference.
    • %x prints the hexadecimal of a value.
    • %u prints an unsigned int passed as a value.
    • %s prints a string passed by reference.

    The error appears when user input is fed into the function as the format. The format parameters and the values given no longer match, and the lecture lists three consequences.

    • Crash the program. printf("%s%s%s%s", user_input) fetches string references from memory whether they are there or not, and crashes at runtime if they are not.
    • Arbitrary read from memory. printf("%08x %08x %08x") reads hex values off the stack, whatever the current function’s scope.
    • Arbitrary write to memory. printf("12345%n", &val) stores the number of bytes written in val.

    The notes add that the values for the format parameters are read from the stack while the function runs, which is why a mismatch reads whatever happens to be there.

    Freed memory can leave dangling pointers and undefined behaviour

    Use after free and double free. C and C++ let the programmer return memory for reuse: free() in C, delete in C++. That raises a question the language does not answer: which part of the program is responsible for doing it, especially with threads? And what happens if the same location is still referenced through another pointer?

    • Use after free. Accessing memory after it has been deallocated.
    • Dangling pointer. A pointer that still references a memory location that has been freed or is invalid.
    • Double free. Freeing the same address twice, which corrupts the memory allocator.

    All of these give undefined behaviour.

    A format string flaw gives an attacker three things in order of severity: a crash, a read of stack contents, and a write to memory. The read and the write are what turn a bug into an exploit, since the attacker never needs to overflow a buffer.

    For memory lifetime and string errors, the earlier defences apply: length-aware APIs (with the n and l caveats), static analysis and memory-safe languages. Memory-safe languages exclude use after free and double free.

    Pitfall

    The n in strncpy and the %n format specifier are unrelated. One is a length limit on a copy, the other writes a byte count into memory. A question that mentions %n is about format strings.

    Exam detail

    Learn the four format specifiers with their meaning, and the three consequences with an example call for each. For integer overflow, state both triggers (too big a value, and signed against unsigned comparison), the truncation, and the two incidents. For memory lifetime errors, give each term its own one-line definition and say the result is undefined behaviour.

    Optional aside

    The slides do not give a format-string fix. As supplementary guidance, use a fixed format and pass user input as a value.

    The notes’ integer overflow example prints the true sum as 429496729, which is a typo: 0x100000000 is 4294967296 in decimal. The wrap-around result of 0 is what the example is about.

    Recall

    How do null termination, integer overflow, format strings and memory lifetime errors differ?
    • Null termination errors make string functions run past the buffer, since C stores no length.
    • Integer overflow truncates silently. Ariane 5 (1996) and the Boeing 787 are the named cases.
    • User input as a printf format can crash the program, read memory, or write memory with %n.
    • Use after free, dangling pointer and double free are three different things and all give undefined behaviour.

    Check yourself