Section 7.1. Buggy Code


7.1. Buggy Code

  1: /* broken.c */  2:  3: #include <stdlib.h>  4: #include <stdio.h>  5: #include <string.h>  6:  7: char global[5];  8:  9: int broken(void) { 10:     char * dyn; 11:     char local[5]; 12: 13:     /* First, overwrite a buffer just a little bit */ 14:     dyn = malloc(5); 15:     strcpy(dyn, "12345"); 16:     printf("1: %s\n", dyn); 17:     free(dyn); 18: 19:     /* Now overwrite the buffer a lot */ 20:     dyn = malloc(5); 21:     strcpy(dyn, "12345678"); 22:     printf("2: %s\n", dyn); 23: 24:     /* Walk past the beginning of a malloced local buffer */ 25:     *(dyn - 1) = '\0'; 26:     printf("3: %s\n", dyn); 27:     /* note we didn't free the pointer! */ 28: 29:     /* Now go after a local variable */ 30:     strcpy(local, "12345"); 31:     printf("4: %s\n", local); 32:     local[-1] = '\0'; 33:     printf("5: %s\n", local); 34: 35:     /* Finally, attack global data space */ 36:     strcpy(global, "12345"); 37:     printf("6: %s\n", global); 38: 39:     /* And write over the space before the global buffer */ 40:     global[-1] = '\0'; 41:     printf("7: %s\n", global); 42: 43:     return 0; 44: } 45: 46: int main(void) { 47:     return broken(); 48: } 

Throughout this chapter, we look for the problems in this code segment. This code corrupts three types of memory regions: memory allocated from the dynamic memory pool (the heap) via malloc(); local variables allocated on the program's stack; and global variables, which are stored in a separate area of memory that is statically allocated when the program starts.[1] For each of these memory classes, this test program writes over the end of the reserved area of memory (usually, by a single byte) and stores a byte immediately before the allocated area as well. In addition, the code includes a memory leak to show how various tools can help track down leaks.

[1] Unfortunately, none of the tools discussed in this chapter is capable of tracking memory errors with global variables; this requires help from the compiler. In the first edition of Linux Application Development, we discussed a tool called Checker that was a modified version of the gcc compiler, but it is no longer maintained. A new technology called "mudflap" is in the process of being added to the official gcc compiler, but it is not yet integrated as we write this. If you are looking for errors involving global variables, you may wish to check the current state of mudflap technology in gcc by reading the current gcc manual. However, since overuse of global variables tends to be a sign of bad program design, you might also consider design changes that eliminate or reduce your use of global variables, which might give other benefits as well.

Although this code has many problems, it actually runs just fine. Does that mean these problems are not important? Not by any means. Buffer overflows tend to cause a program to misbehave long after the actual overflow, and memory leaks in programs that run for a length of time waste a computer's resources. Furthermore, buffer overflows are a classic source of security vulnerabilities, as discussed in Chapter 22. For reference, here is what the program looks like when it is executed.

 $ gcc -Wall -o broken broken.c $ ./broken 1: 12345 2: 12345678 3: 12345678 4: 12345 5: 12345 6: 12345 7: 12345 


    Linux Application Development
    Linux Application Development (paperback) (2nd Edition)
    ISBN: 0321563220
    EAN: 2147483647
    Year: 2003
    Pages: 168 © 2008-2017.
    If you may any questions please contact us: