Thursday, December 3, 2009

Chapter 5 How does Libsafe work?

5.1 Presentation

Libsafe is a dynamic library that is loaded prior to the other libraries in memory and overrides some of the unsafe functions of the libc. Libsafe intercepts the calls to the unsafe functions of the standard C library and uses instead its own implementation of the function. While keeping the same semantic, it adds detection of bound violations. The unsafe functions overriden are:

• strcpy(char *dest, const char *src)

• strcat(char *dest, const char *src)

• getwd(char *buf)

• gets(char *s)

• scanf(const char *format,... )

• realpath(char *path, char resolved_path[])

• sprintf(char *str, const char *format,... )

5.2   Why are the functions of the libC unsafe ?

Some functions of the standard C library are unsafe because they do not check the bounds of a buffer. For example here is the implementation of strcpy:

char * strcpy(char * dest,const char *src) {

char *tmp = dest;

while ((*dest++ = *src++)   != '\0') /* nothing */; return tmp; }

In this implementation of strcpy the size of the dest buffer is not a factor for deciding if we should copy more characters or not. The only criterium for quitting the loop is the termination character '\0'.

5.3   What does libsafe provide ?

Unlike the standard library, libsafe does bounds checking. Below is the implemantation of strcpy by libsafe:

char *strcpy(char *dest, const char *src) {

1 if ((len = strnlen(src, max_size)) == max_size)

2 _libsafe_die("Overflow caused by strcpy()");

3 real_memcpy(dest, src, len + 1);

4 return dest; }

max_size is obtained with__libsafe_stackVariableP(dest). This function returns the distance (in

fact the number of bytes) between dest and the frame pointer in which dest resides. This value is obviously the maximum size that could be used by dest without compromising the integrity of the return address.

__libsafe_stackVariableP(void *addr) returns 0 if the addr does not reference to a valid address in

stack.

__libsafe_stackVariableP(void *addr) relies on __builtin_frame_address(le) , which gives the address of the frame pointer for the level le. This function is a property of the gcc compiler. At this stage there is something important to notice: if the vulnerable program has been compiled with the option: --fomit-frame-pointer or with optimisation options then libsafe is useless and will not work properly.

strnlen returns the maximum value between the length of the string src and max_size (see explanations above). If there was an attempt to overflow the buffer, then strnlen() would return max_size and the process would be stopped (_libsafe_die).

If this verification is passed then memcpy() is called and will copy the string referenced by src to the address referenced by dest.

No comments:

Post a Comment