5

everyone!

Image that i have a program(usemalloc) like this:

#include <stdio.h>
#include <stdlib.h>

#define USER_BYTES_SIZE 100

int main(void){
    char* userbytes = (char*)malloc(USER_BYTES_SIZE*sizeof(char));
    if(!userbytes)
        return 1;

    for(int i = 0; i <= USER_BYTES_SIZE; i++){ // "i <= USER_BYTES_SIZE" leads to an off-by-one memory overrun.
        userbytes[i] = 0;
    }
    return 0;
}

As you see that, there is an off-by-one bug which leads to a memory overflow. I want to detect such bugs at runtime. LD_PRELOADed libraries are proper to do my work. I have manufactured a library named libhijack.so to hijack the call to real malloc and replace it with the call to my own customed malloc which call the real malloc and add red zones at ends of the memory strips allocted by the real malloc. The libhijack.so's code like this:

void* (*real_malloc) (size_t size);
void* malloc(size_t size){
    real_malloc = ((void*)(*)(size_t))dlsym(RTLD_NEXT, "malloc");
    void* allocbytes = (void*)real_malloc(size + 4); //put 2 bytes at each end, call them red zones
    return (allocbytes + 2);
}

I run the main program with the library using this command:

LD_PRELOAD=./libhijack.so ./usemalloc

Then if there are access to memory in red zones, I will detect them and deem them as memory overflow bugs.

This LD_PRELOAD solution works well when the main process contains calls to malloc but fails when forked child process does that.

For example, we change the "usemalloc" as follows:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // +

#define USER_BYTES_SIZE 100

int main(void){
    pid_t child = fork();
    if(child < 0)
        exit(1);

    if(child == 0){ //child process
        char* userbytes = (char*)malloc(USER_BYTES_SIZE*sizeof(char));
        if(!userbytes)
            return 1;

        for(int i = 0; i <= USER_BYTES_SIZE; i++){ // "i <= USER_BYTES_SIZE" leads to an off-by-one memory overrun.
            userbytes[i] = 0;
        }
    }
    else { //the current process
        wait(NULL);
    }
    return 0;
}

The overflow bug occured in child process will not be detect by LD_PRELOADed library.

So my questions are: how can I detect the overflow bug in the child process using LD_PRELOADed libraries? Is that(using LD_PRELOADed libraries) possible? If not, any alternatives? Any suggestions ar eappreciated!!!

振 禹
  • 51
  • 3
  • 1
    Did you consider using `valgrind` (& ASAN option in compilers) which probably provides most of what you want already, without any `LD_PRELOAD` trick. – Basile Starynkevitch Jan 01 '13 at 14:12
  • valgrind or pin is too heavy for my instrumentation. I just want a lightweight solution such as LD_PRELOAD to hijack some interesting functions. Anyway, thanks for commenting! – 振 禹 Jan 01 '13 at 14:28
  • You cannot have a reliable lightweight solution: there is no hardware assistance for such buffer overflow bugs, and you'll need to patch the compiler. See ASAN & other recent efforts in GCC (future 4.8) or Clang (3.2) – Basile Starynkevitch Jan 01 '13 at 14:30
  • Well, I don't want to fix the memory overflow bug. I just want to determine at runtime whether there are accesses to memories in red zones. If such accesses exist, I just print the stack trace and terminate the hijacked program. – 振 禹 Jan 01 '13 at 14:38
  • You probably are creating more memory leaks than ever using this method since you will not be freeing the 2 bytes before and after the malloc'ed area. – fpmurphy Jan 01 '13 at 15:23
  • A little nitpick: please use multiples of the word-size for the sizes of both red zones - using just 2 bytes could break programs that (erroneously?) depend on `malloc()` pointers being aligned at a word boundary... – thkala Jan 01 '13 at 17:28
  • 1
    Oh, and I suppose you *have* overridden `free()` along with `malloc()`, right? – thkala Jan 01 '13 at 17:29
  • Of course, I will override free() to free the extra memory, namely red zones. – 振 禹 Jan 02 '13 at 01:52
  • You're trying to rewrote ElectricFence (efence) http://en.wikipedia.org/wiki/Electric_Fence http://directory.fsf.org/wiki/Electric_Fence http://linux.die.net/man/3/efence – Yann Droneaud Jan 02 '13 at 10:14

3 Answers3

0

I hope I'm not being nit-picky by pointing out that the libhijack code doesn't actually allocate any memory? pthread_mutex_lock requires a pthread_mutex_t * argument, and returns an integer communicating success/failure on whether or not the mutex lock was successful?

Also, you are fork()'ing a child process, which is a little bit different to creating a thread and so the pthread functions may not really be what you are after...?

The other trick is that while the code that is causing the problem has been demonstrated, how are you checking your "red zones"? Maybe the detection quirk lies in the detection code?

user1884242
  • 146
  • 1
  • sorry for editing fault. "pthread_mutex_lock" should be replaced with "malloc" in the call to dlsym. I have corrected it. My question is how I can use LD_PRELOADed libraries to detect overflow bugs in child process? Do you know that? – 振 禹 Jan 02 '13 at 01:55
0

Use valgrind to detect memory leaks and other memory problems. it works great and you won't have to implement anything.

LtWorf
  • 7,286
  • 6
  • 31
  • 45
0

I don't think your problem has anything to do with fork() vs. LD_PRELOAD. I think it might be a bug somewhere else in your code. I tried to reproduce your problem using the following test case:

// preloadlib.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <unistd.h>
void* malloc(size_t size)
{
        write(1, "malloc\n", 7);
        void *(*real_malloc)(size_t) = dlsym(RTLD_NEXT, "malloc");
        return real_malloc(size);
}

.

// example.c
#include <unistd.h>
#include <stdlib.h>
int main()
{
        if (fork()) {
                write(1, "A\n", 2);
                malloc(1337);
                write(1, "B\n", 2);
        } else {
                write(1, "C\n", 2);
                malloc(1337);
                write(1, "D\n", 2);
        }
        return 0;
}

.

# run.sh
gcc -Wall -Wextra -o example example.c
gcc -Wall -Wextra -fPIC -o preloadlib.so -shared preloadlib.c -ldl
LD_PRELOAD=$PWD/preloadlib.so ./example

And this is the output I get:

$ bash run.sh 
A
malloc
C
B
malloc
D

This is on 64-bit Kubuntu 12.04 (libc version 2.15-0ubuntu10.4).

CliffordVienna
  • 7,995
  • 1
  • 37
  • 57